https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a55bab8d1d13eab9afe30e29203164e50cf653cd

commit a55bab8d1d13eab9afe30e29203164e50cf653cd
Author:     Dmitry Borisov <di.s...@protonmail.com>
AuthorDate: Fri Jan 17 19:39:28 2020 +0600
Commit:     Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org>
CommitDate: Thu Feb 13 18:10:02 2020 +0100

    [FREELDR] Fix IDE driver failures on real hardware. (#2255)
    
    - Changes in device detection code:
        * Properly check device signature.
        * Сorrectly reset the IDE controller.
        * Remove check for device type code.
    - Fix CD-ROM sector read issue:
        * Changed ATAPI packet opcode to be more universal (Some devices may 
not have READ12 support).
        * Always use 2048 bytes as sector size when reading the data from a 
disc.
        * Modify WaitForFlags() to stop polling if the error bit was set.
        * Changed timeout to 31 seconds (ATA default value).
    - Add more informational messages in DEBUG mode.
    - Fix invalid IDE register value.
    - Fix registers names.
    
    Tested by Stanislav Motylkov and Daniel Reimer on XQEMU and on real
    hardware MS Xbox revision 1.3 with Philips DVD drive.
    It has also been tested manually on PC with a SONY DVD drive.
    
    CORE-16628 CORE-16216
---
 boot/freeldr/freeldr/arch/drivers/hwide.c | 335 ++++++++++++++++++++----------
 boot/freeldr/freeldr/include/hwide.h      |  10 +-
 2 files changed, 231 insertions(+), 114 deletions(-)

diff --git a/boot/freeldr/freeldr/arch/drivers/hwide.c 
b/boot/freeldr/freeldr/arch/drivers/hwide.c
index c1f8f666769..9eb92ada048 100644
--- a/boot/freeldr/freeldr/arch/drivers/hwide.c
+++ b/boot/freeldr/freeldr/arch/drivers/hwide.c
@@ -1,8 +1,8 @@
 /*
  * PROJECT:     FreeLoader
  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE:     ATA/ATAPI polled I/O driver.
- * COPYRIGHT:   Copyright 2019 Dmitry Borisov (di.s...@protonmail.com)
+ * PURPOSE:     ATA/ATAPI programmed I/O driver.
+ * COPYRIGHT:   Copyright 2019-2020 Dmitry Borisov (di.s...@protonmail.com)
  */
 
 /* INCLUDES 
*******************************************************************/
@@ -21,10 +21,7 @@ DBG_DEFAULT_CHANNEL(DISK);
 
 #define TAG_ATA_DEVICE 'DatA'
 #define ATAPI_PACKET_SIZE(IdentifyData) (IdentifyData.AtapiCmdSize ? 16 : 12)
-
-/* Used in WaitForFlags() and should be 31 seconds (31e5), but it's too much 
for polled I/O */
-#define ATA_STATUS_TIMEOUT 36000
-#define ATA_READ_TIMEOUT   4e5
+#define ATA_STATUS_TIMEOUT 31e5
 
 #define AtaWritePort(Channel, Port, Data) \
     WRITE_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)), (Data))
@@ -70,6 +67,22 @@ WaitForFlags(
 
 static
 BOOLEAN
+WaitForFlagsOr(
+    IN UCHAR Channel,
+    IN UCHAR FirstValue,
+    IN UCHAR SecondValue,
+    IN ULONG Timeout
+);
+
+static
+BOOLEAN
+WaitForBusy(
+    IN UCHAR Channel,
+    IN ULONG Timeout
+);
+
+static
+VOID
 SelectDevice(
     IN UCHAR Channel,
     IN UCHAR DeviceNumber
@@ -83,6 +96,19 @@ IdentifyDevice(
     OUT PDEVICE_UNIT *DeviceUnit
 );
 
+static
+BOOLEAN
+AtapiRequestSense(
+    IN PDEVICE_UNIT DeviceUnit,
+    OUT PSENSE_DATA SenseData
+);
+
+static
+VOID
+AtapiPrintSenseData(
+    IN PDEVICE_UNIT DeviceUnit
+);
+
 static
 BOOLEAN
 AtapiReadyCheck(
@@ -274,21 +300,23 @@ AtaReadLogicalSectorsLBA(
         }
 
         /* Select the drive */
-        if (!SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber))
+        SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
+        if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
+        {
+            ERR("AtaReadLogicalSectorsLBA() failed. Device is busy.\n");
             return FALSE;
+        }
 
         /* Disable interrupts */
-#ifndef SARCH_PC98
-        AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_AltStatus, 
IDE_DC_DISABLE_INTERRUPTS);
+        AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_Control, 
IDE_DC_DISABLE_INTERRUPTS);
         StallExecutionProcessor(1);
-#endif
 
         if (UseLBA48)
         {
             /* FIFO */
             AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, 0);
             AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, ATA_PIO);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, 
(BlockCount & 0xFF) >> 8);
+            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, 
(BlockCount >> 8) & 0xFF);
             AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, BlockCount 
& 0xFF);
             AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, (Lba >> 
24) & 0xFF);
             AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, Lba & 
0xFF);
@@ -321,8 +349,8 @@ AtaReadLogicalSectorsLBA(
         for (RemainingBlockCount = BlockCount; RemainingBlockCount > 0; 
--RemainingBlockCount)
         {
             /* Wait for ready to transfer data block */
-            if (!WaitForFlags(DeviceUnit->Channel, (IDE_STATUS_BUSY | 
IDE_STATUS_DRQ | IDE_STATUS_ERROR),
-                              IDE_STATUS_DRQ, ATA_READ_TIMEOUT))
+            if (!WaitForFlags(DeviceUnit->Channel, IDE_STATUS_DRQ,
+                              IDE_STATUS_DRQ, ATA_STATUS_TIMEOUT))
             {
                 ERR("AtaReadLogicalSectorsLBA() failed. Status: 0x%02x, Error: 
0x%02x\n",
                     AtaReadPort(DeviceUnit->Channel, IDX_IO1_i_Status),
@@ -351,9 +379,15 @@ AtaSendAtapiPacket(
     IN UCHAR PacketSize,
     IN USHORT ByteCount)
 {
-    /* No DRQ for TEST UNIT READY */
-    BOOLEAN NoData = (AtapiPacket[0] == SCSIOP_TEST_UNIT_READY);
-    UCHAR ExpectedFlags = NoData ? IDE_STATUS_DRDY : (IDE_STATUS_DRQ | 
IDE_STATUS_DRDY);
+    /*
+     * REQUEST SENSE is used by driver to clear the ATAPI 'Bus reset' 
indication.
+     * TEST UNIT READY doesn't require space for returned data.
+     */
+    UCHAR ExpectedFlagsMask = (AtapiPacket[0] == SCSIOP_REQUEST_SENSE) ?
+                               IDE_STATUS_DRDY : (IDE_STATUS_DRQ | 
IDE_STATUS_DRDY);
+    UCHAR ExpectedFlags = ((AtapiPacket[0] == SCSIOP_TEST_UNIT_READY) ||
+                           (AtapiPacket[0] == SCSIOP_REQUEST_SENSE)) ?
+                           IDE_STATUS_DRDY : (IDE_STATUS_DRQ | 
IDE_STATUS_DRDY);
 
     /* PIO mode */
     AtaWritePort(Channel, IDX_ATAPI_IO1_o_Feature, ATA_PIO);
@@ -365,8 +399,7 @@ AtaSendAtapiPacket(
     /* Prepare to transfer a device command via a command packet */
     AtaWritePort(Channel, IDX_ATAPI_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
     StallExecutionProcessor(50);
-    if (!WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | 
IDE_STATUS_ERROR),
-                      IDE_STATUS_DRQ, NoData ? ATA_STATUS_TIMEOUT : 
ATA_READ_TIMEOUT))
+    if (!WaitForFlagsOr(Channel, IDE_STATUS_DRQ, IDE_STATUS_DRDY, 
ATA_STATUS_TIMEOUT))
     {
         ERR("AtaSendAtapiPacket(0x%x) failed. A device error occurred Status: 
0x%02x, Error: 0x%02x\n",
             AtapiPacket[0], AtaReadPort(Channel, IDX_ATAPI_IO1_i_Status), 
AtaReadPort(Channel, IDX_ATAPI_IO1_i_Error));
@@ -375,8 +408,7 @@ AtaSendAtapiPacket(
 
     /* Command packet transfer */
     AtaWriteBuffer(Channel, AtapiPacket, PacketSize);
-    if (!WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | 
IDE_STATUS_DRDY | IDE_STATUS_ERROR),
-                      ExpectedFlags, NoData ? ATA_STATUS_TIMEOUT : 
ATA_READ_TIMEOUT))
+    if (!WaitForFlags(Channel, ExpectedFlagsMask, ExpectedFlags, 
ATA_STATUS_TIMEOUT))
     {
         TRACE("AtaSendAtapiPacket(0x%x) failed. An execution error occurred 
Status: 0x%02x, Error: 0x%02x\n",
               AtapiPacket[0], AtaReadPort(Channel, IDX_ATAPI_IO1_i_Status), 
AtaReadPort(Channel, IDX_ATAPI_IO1_i_Error));
@@ -398,28 +430,25 @@ AtapiReadLogicalSectorLBA(
     BOOLEAN Success;
 
     /* Select the drive */
-    if (!SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber))
+    SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
+    if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
+    {
+        ERR("AtapiReadLogicalSectorLBA() failed. Device is busy!\n");
         return FALSE;
+    }
 
     /* Disable interrupts */
-    AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_AltStatus, 
IDE_DC_DISABLE_INTERRUPTS);
+    AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_Control, 
IDE_DC_DISABLE_INTERRUPTS);
     StallExecutionProcessor(1);
 
     /* Send the SCSI READ command */
     RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-#if defined(SARCH_PC98)
     AtapiPacket[0] = SCSIOP_READ;
-    AtapiPacket[8] = 1;
-    AtapiPacket[9] = 0;
-#else
-    AtapiPacket[0] = SCSIOP_READ12;
-    AtapiPacket[8] = 0;
-    AtapiPacket[9] = 1;
-#endif
     AtapiPacket[2] = (SectorNumber >> 24) & 0xFF;
     AtapiPacket[3] = (SectorNumber >> 16) & 0xFF;
     AtapiPacket[4] = (SectorNumber >> 8) & 0xFF;
     AtapiPacket[5] = SectorNumber & 0xFF;
+    AtapiPacket[8] = 1;
     Success = AtaSendAtapiPacket(DeviceUnit->Channel,
                                  AtapiPacket,
                                  ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
@@ -427,6 +456,7 @@ AtapiReadLogicalSectorLBA(
     if (!Success)
     {
         ERR("AtapiReadLogicalSectorLBA() failed. A read error occurred.\n");
+        AtapiPrintSenseData(DeviceUnit);
         return FALSE;
     }
 
@@ -461,11 +491,61 @@ AtapiCapacityDetect(
 
         *SectorSize = (AtapiCapacity[4] << 24) | (AtapiCapacity[5] << 16) |
                       (AtapiCapacity[6] << 8) | AtapiCapacity[7];
+
+        /* If device reports a non-zero block length, reset to defaults (we 
use READ command instead of READ CD) */
+        if (*SectorSize != 0)
+            *SectorSize = 2048;
     }
     else
     {
         *TotalSectors = 0;
         *SectorSize = 0;
+
+        AtapiPrintSenseData(DeviceUnit);
+    }
+}
+
+static
+BOOLEAN
+AtapiRequestSense(
+    IN PDEVICE_UNIT DeviceUnit,
+    OUT PSENSE_DATA SenseData)
+{
+    UCHAR AtapiPacket[16];
+    BOOLEAN Success;
+
+    RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
+    RtlZeroMemory(SenseData, sizeof(SENSE_DATA));
+    AtapiPacket[0] = SCSIOP_REQUEST_SENSE;
+    AtapiPacket[4] = SENSE_BUFFER_SIZE;
+    Success = AtaSendAtapiPacket(DeviceUnit->Channel,
+                                 AtapiPacket,
+                                 ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
+                                 SENSE_BUFFER_SIZE);
+    if (Success)
+    {
+        AtaReadBuffer(DeviceUnit->Channel, SenseData, SENSE_BUFFER_SIZE);
+        return TRUE;
+    }
+    else
+    {
+        ERR("Cannot read the sense data.\n");
+        return FALSE;
+    }
+}
+
+static
+VOID
+AtapiPrintSenseData(IN PDEVICE_UNIT DeviceUnit)
+{
+    SENSE_DATA SenseData;
+
+    if (AtapiRequestSense(DeviceUnit, &SenseData))
+    {
+        ERR("SK 0x%x, ASC 0x%x, ASCQ 0x%x\n",
+            SenseData.SenseKey,
+            SenseData.AdditionalSenseCode,
+            SenseData.AdditionalSenseCodeQualifier);
     }
 }
 
@@ -479,7 +559,8 @@ AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
     BOOLEAN Success;
 
     /* Select the drive */
-    if (!SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber))
+    SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
+    if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
         return FALSE;
 
     /* Send the SCSI TEST UNIT READY command */
@@ -490,16 +571,7 @@ AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
                        ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
                        0);
 
-    /* Send the SCSI REQUEST SENSE command */
-    RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-    RtlZeroMemory(&SenseData, SENSE_BUFFER_SIZE);
-    AtapiPacket[0] = SCSIOP_REQUEST_SENSE;
-    AtapiPacket[4] = SENSE_BUFFER_SIZE;
-    Success = AtaSendAtapiPacket(DeviceUnit->Channel,
-                                 AtapiPacket,
-                                 ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
-                                 SENSE_BUFFER_SIZE);
-    if (!Success)
+    if (!AtapiRequestSense(DeviceUnit, &SenseData))
         return FALSE;
 
     AtaReadBuffer(DeviceUnit->Channel, &SenseData, SENSE_BUFFER_SIZE);
@@ -531,7 +603,10 @@ AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
                                                  
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
                                                  MAXIMUM_CDROM_SIZE);
                     if (!Success)
+                    {
+                        AtapiPrintSenseData(DeviceUnit);
                         return FALSE;
+                    }
 
                     AtaReadBuffer(DeviceUnit->Channel, &DummyData, 
MAXIMUM_CDROM_SIZE);
                     /* fall through */
@@ -578,14 +653,66 @@ WaitForFlags(
     IN UCHAR ExpectedValue,
     IN ULONG Timeout)
 {
+    UCHAR Status;
+
     ASSERT(Timeout != 0);
 
+    WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
+
     while (Timeout--)
     {
-        if ((AtaReadPort(Channel, IDX_IO1_i_Status) & Flags) == ExpectedValue)
+        StallExecutionProcessor(10);
+
+        Status = AtaReadPort(Channel, IDX_IO1_i_Status);
+        if (Status & IDE_STATUS_ERROR)
+            return FALSE;
+        else if ((Status & Flags) == ExpectedValue)
+            return TRUE;
+    }
+    return FALSE;
+}
+
+static
+BOOLEAN
+WaitForFlagsOr(
+    IN UCHAR Channel,
+    IN UCHAR FirstValue,
+    IN UCHAR SecondValue,
+    IN ULONG Timeout)
+{
+    UCHAR Status;
+
+    ASSERT(Timeout != 0);
+
+    WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
+
+    while (Timeout--)
+    {
+        StallExecutionProcessor(10);
+
+        Status = AtaReadPort(Channel, IDX_IO1_i_Status);
+        if (Status & IDE_STATUS_ERROR)
+            return FALSE;
+        else if ((Status & FirstValue) || (Status & SecondValue))
+            return TRUE;
+    }
+    return FALSE;
+}
+
+static
+BOOLEAN
+WaitForBusy(
+    IN UCHAR Channel,
+    IN ULONG Timeout)
+{
+    ASSERT(Timeout != 0);
+
+    while (Timeout--)
+    {
+        StallExecutionProcessor(10);
+
+        if ((AtaReadPort(Channel, IDX_IO1_i_Status) & IDE_STATUS_BUSY) == 0)
             return TRUE;
-        else
-            StallExecutionProcessor(10);
     }
     return FALSE;
 }
@@ -597,31 +724,25 @@ AtaHardReset(IN UCHAR Channel)
     TRACE("AtaHardReset(Controller %d)\n", Channel);
 
     AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER);
-    StallExecutionProcessor(200000);
+    StallExecutionProcessor(100000);
     AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
-    StallExecutionProcessor(1);
+    StallExecutionProcessor(5);
+    WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
 }
 
 static
-BOOLEAN
+VOID
 SelectDevice(IN UCHAR Channel, IN UCHAR DeviceNumber)
 {
 #if defined(SARCH_PC98)
     /* Select IDE Channel */
     WRITE_PORT_UCHAR((PUCHAR)IDE_IO_o_BankSelect, Channel);
-    StallExecutionProcessor(1);
+    StallExecutionProcessor(5);
 #endif
 
     AtaWritePort(Channel, IDX_IO1_o_DriveSelect,
                  DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1);
-    StallExecutionProcessor(500);
-    if (!WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ), 0, 
ATA_STATUS_TIMEOUT))
-    {
-        TRACE("SelectDevice() failed. Device(%d:%d) is busy.\n", Channel, 
DeviceNumber);
-        return FALSE;
-    }
-
-    return TRUE;
+    StallExecutionProcessor(5);
 }
 
 static
@@ -631,11 +752,10 @@ IdentifyDevice(
     IN UCHAR DeviceNumber,
     OUT PDEVICE_UNIT *DeviceUnit)
 {
-    UCHAR SignatureLow, SignatureHigh;
+    UCHAR SignatureLow, SignatureHigh, SignatureCount, SignatureNumber;
+    UCHAR Command;
     IDENTIFY_DATA Id;
-    INQUIRYDATA AtapiInquiry;
-    BOOLEAN Success;
-    UCHAR AtapiPacket[16];
+    SENSE_DATA SenseData;
     ULONG i;
     ULONG SectorSize;
     ULONGLONG TotalSectors;
@@ -644,50 +764,61 @@ IdentifyDevice(
     TRACE("IdentifyDevice() Channel = %x, Device = %x, BaseIoAddress = 0x%x\n",
           Channel, DeviceNumber, BaseArray[Channel]);
 
+    /* Look at controller */
+    SelectDevice(Channel, DeviceNumber);
+    StallExecutionProcessor(5);
+    AtaWritePort(Channel, IDX_IO1_o_BlockNumber, 0x55);
+    AtaWritePort(Channel, IDX_IO1_o_BlockNumber, 0x55);
+    StallExecutionProcessor(5);
+    if (AtaReadPort(Channel, IDX_IO1_i_BlockNumber) != 0x55)
+        goto Failure;
+
     /* Reset the controller */
     AtaHardReset(Channel);
 
     /* Select the drive */
-    if (!SelectDevice(Channel, DeviceNumber))
+    SelectDevice(Channel, DeviceNumber);
+    if (!WaitForBusy(Channel, ATA_STATUS_TIMEOUT))
         goto Failure;
 
-    /* Send the IDENTIFY DEVICE command */
-    AtaWritePort(Channel, IDX_IO1_o_Command, IDE_COMMAND_IDENTIFY);
-    StallExecutionProcessor(50);
-    if (WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | 
IDE_STATUS_ERROR),
-                     IDE_STATUS_DRQ, ATA_STATUS_TIMEOUT))
-    {
-        SignatureLow = AtaReadPort(Channel, IDX_IO1_i_CylinderLow);
-        SignatureHigh = AtaReadPort(Channel, IDX_IO1_i_CylinderHigh);
-        TRACE("IdentifyDevice(): SignatureLow = 0x%x, SignatureHigh = 0x%x\n", 
SignatureLow, SignatureHigh);
-        if (SignatureLow == 0x00 && SignatureHigh == 0x00)
-        {
-            /* This is PATA */
-            TRACE("IdentifyDevice(): Found PATA device at %d:%d\n", Channel, 
DeviceNumber);
-            goto Identify;
-        }
-    }
-
-    /* If not PATA, ATAPI maybe? Send the IDENTIFY PACKET DEVICE command */
-    AtaWritePort(Channel, IDX_ATAPI_IO1_o_Command, IDE_COMMAND_ATAPI_IDENTIFY);
-    StallExecutionProcessor(500);
+    /* Signature check */
     SignatureLow = AtaReadPort(Channel, IDX_IO1_i_CylinderLow);
     SignatureHigh = AtaReadPort(Channel, IDX_IO1_i_CylinderHigh);
-    TRACE("IdentifyDevice(): SignatureLow = 0x%x, SignatureHigh = 0x%x\n", 
SignatureLow, SignatureHigh);
-    /* Check for devices that implements the PACKET Command feature */
-    if (SignatureLow == ATAPI_MAGIC_LSB && SignatureHigh == ATAPI_MAGIC_MSB)
+    SignatureCount = AtaReadPort(Channel, IDX_IO1_i_BlockCount);
+    SignatureNumber = AtaReadPort(Channel, IDX_IO1_i_BlockNumber);
+    TRACE("IdentifyDevice(): SL = 0x%x, SH = 0x%x, SC = 0x%x, SN = 0x%x\n",
+          SignatureLow, SignatureHigh, SignatureCount, SignatureNumber);
+    if (SignatureLow == 0x00 && SignatureHigh == 0x00 &&
+        SignatureCount == 0x01 && SignatureNumber == 0x01)
+    {
+        TRACE("IdentifyDevice(): Found PATA device at %d:%d\n", Channel, 
DeviceNumber);
+        Command = IDE_COMMAND_IDENTIFY;
+    }
+    else if (SignatureLow == ATAPI_MAGIC_LSB &&
+             SignatureHigh == ATAPI_MAGIC_MSB)
     {
-        /* This is ATAPI */
-        Flags |= ATA_DEVICE_ATAPI | ATA_DEVICE_LBA | ATA_DEVICE_NOT_READY;
         TRACE("IdentifyDevice(): Found ATAPI device at %d:%d\n", Channel, 
DeviceNumber);
-        goto Identify;
+        Flags |= ATA_DEVICE_ATAPI | ATA_DEVICE_LBA | ATA_DEVICE_NOT_READY;
+        Command = IDE_COMMAND_ATAPI_IDENTIFY;
     }
     else
     {
         goto Failure;
     }
 
-Identify:
+    /* Disable interrupts */
+    AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS);
+    StallExecutionProcessor(5);
+
+    /* Send the identify command */
+    AtaWritePort(Channel, IDX_IO1_o_Command, Command);
+    StallExecutionProcessor(50);
+    if (!WaitForFlags(Channel, IDE_STATUS_DRQ, IDE_STATUS_DRQ, 
ATA_STATUS_TIMEOUT))
+    {
+        ERR("IdentifyDevice(): Identify command failed.\n");
+        goto Failure;
+    }
+
     /* Receive parameter information from the device */
     AtaReadBuffer(Channel, &Id, IDENTIFY_DATA_SIZE);
 
@@ -705,25 +836,6 @@ Identify:
     TRACE("FR %.*s\n", sizeof(Id.FirmwareRevision), Id.FirmwareRevision);
     TRACE("MN %.*s\n", sizeof(Id.ModelNumber), Id.ModelNumber);
 
-    /* Detect the type of device */
-    if (Flags & ATA_DEVICE_ATAPI)
-    {
-        /* Send the SCSI INQUIRY command */
-        RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-        AtapiPacket[0] = SCSIOP_INQUIRY;
-        AtapiPacket[4] = INQUIRYDATABUFFERSIZE;
-        Success = AtaSendAtapiPacket(Channel, AtapiPacket, 
ATAPI_PACKET_SIZE(Id), INQUIRYDATABUFFERSIZE);
-        if (!Success)
-            goto Failure;
-
-        AtaReadBuffer(Channel, &AtapiInquiry, INQUIRYDATABUFFERSIZE);
-        if (AtapiInquiry.DeviceType != READ_ONLY_DIRECT_ACCESS_DEVICE)
-        {
-            TRACE("IdentifyDevice(): Unsupported device type 0x%x!\n", 
AtapiInquiry.DeviceType);
-            goto Failure;
-        }
-    }
-
     /* Allocate a new device unit structure */
     *DeviceUnit = FrLdrTempAlloc(sizeof(DEVICE_UNIT), TAG_ATA_DEVICE);
     if (*DeviceUnit == NULL)
@@ -737,9 +849,16 @@ Identify:
     (*DeviceUnit)->DeviceNumber = DeviceNumber;
     (*DeviceUnit)->IdentifyData = Id;
 
-    /* Detect a medium's capacity */
     if (Flags & ATA_DEVICE_ATAPI)
     {
+        /* Clear the ATAPI 'Bus reset' indication */
+        for (i = 0; i < 10; ++i)
+        {
+            AtapiRequestSense(*DeviceUnit, &SenseData);
+            StallExecutionProcessor(10);
+        }
+
+        /* Detect a medium's capacity */
         AtapiCapacityDetect(*DeviceUnit, &TotalSectors, &SectorSize);
         if (SectorSize == 0 || TotalSectors == 0)
         {
diff --git a/boot/freeldr/freeldr/include/hwide.h 
b/boot/freeldr/freeldr/include/hwide.h
index 04f9f2d51ae..23f7fd94ad0 100644
--- a/boot/freeldr/freeldr/include/hwide.h
+++ b/boot/freeldr/freeldr/include/hwide.h
@@ -1,8 +1,8 @@
 /*
  * PROJECT:     FreeLoader
  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
- * PURPOSE:     ATA/ATAPI polled I/O driver header file.
- * COPYRIGHT:   Copyright 2019 Dmitry Borisov (di.s...@protonmail.com)
+ * PURPOSE:     ATA/ATAPI programmed I/O driver header file.
+ * COPYRIGHT:   Copyright 2019-2020 Dmitry Borisov (di.s...@protonmail.com)
  */
 
 /* GLOBALS 
********************************************************************/
@@ -35,8 +35,7 @@
 #define IDX_IO1_o_DriveSelect   0x0C
 #define IDX_IO1_o_Command       0x0E
 
-#define IDX_IO2_o_AltStatus     0x10C
-#define IDX_IO2_o_Control       0x10E
+#define IDX_IO2_o_Control       0x10C
 #define IDE_IO_o_BankSelect     0x432
 #else /* SARCH_PC98 */
 #define IDX_IO1_i_Data          0x00
@@ -60,8 +59,7 @@
 #define IDX_IO1_o_DriveSelect   0x06
 #define IDX_IO1_o_Command       0x07
 
-#define IDX_IO2_o_AltStatus     0x206
-#define IDX_IO2_o_Control       0x207
+#define IDX_IO2_o_Control       0x206
 #endif
 
 /*

Reply via email to