https://git.reactos.org/?p=reactos.git;a=commitdiff;h=787f81f3f5552a23890b2…
commit 787f81f3f5552a23890b244b2ab1eb07d80737e4
Author:     Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Wed Mar 19 02:56:25 2025 +0600
Commit:     GitHub <noreply(a)github.com>
CommitDate: Tue Mar 18 21:56:25 2025 +0100
    [FREELDR] Refactor and optimize the IDE driver (#7728)
    [DDK] Update IDENTIFY data and other ATA definitions.
    Based on the MinGW header.
    [FREELDR] Refactor and optimize the IDE driver.
    Fix long-standing bugs, which have a negative impact on the boot stability.
    - Make the driver more ATA specification compliant.
    - Improve the speed of device detection.
    - Remove inconsistent delays.
    - Support modern hard drives with sector size greater than 512 bytes.
    - Add basic error recovery.
    - Move private definitions to a separate private header.
    - Remove the useless AtaFree API method.
---
 boot/freeldr/freeldr/arch/drivers/hwide.c         | 1749 +++++++++++++--------
 boot/freeldr/freeldr/arch/drivers/hwidep.h        |  387 +++++
 boot/freeldr/freeldr/arch/i386/pc98/machpc98.c    |    1 -
 boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c    |    9 +-
 boot/freeldr/freeldr/arch/i386/xbox/machxbox.c    |    1 -
 boot/freeldr/freeldr/arch/i386/xbox/xboxdisk.c    |   51 +-
 boot/freeldr/freeldr/include/arch/i386/machpc98.h |    1 -
 boot/freeldr/freeldr/include/arch/i386/machxbox.h |    1 -
 boot/freeldr/freeldr/include/hwide.h              |  341 +---
 sdk/include/ddk/ata.h                             |  558 ++++++-
 10 files changed, 2002 insertions(+), 1097 deletions(-)
diff --git a/boot/freeldr/freeldr/arch/drivers/hwide.c
b/boot/freeldr/freeldr/arch/drivers/hwide.c
index 9eb92ada048..2baffe48345 100644
--- a/boot/freeldr/freeldr/arch/drivers/hwide.c
+++ b/boot/freeldr/freeldr/arch/drivers/hwide.c
@@ -1,371 +1,750 @@
 /*
  * PROJECT:     FreeLoader
- * LICENSE:     GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * LICENSE:     MIT (
https://spdx.org/licenses/MIT)
  * PURPOSE:     ATA/ATAPI programmed I/O driver.
- * COPYRIGHT:   Copyright 2019-2020 Dmitry Borisov (di.sean(a)protonmail.com)
+ * COPYRIGHT:   Copyright 2019-2025 Dmitry Borisov (di.sean(a)protonmail.com)
  */
 /* INCLUDES *******************************************************************/
 #include <freeldr.h>
-#include <hwide.h>
 /* DDK */
 #include <ata.h>
 #include <scsi.h>
+#include <hwide.h>
+#include "hwidep.h"
+
 #include <debug.h>
 DBG_DEFAULT_CHANNEL(DISK);
 /* GLOBALS ********************************************************************/
-#define TAG_ATA_DEVICE 'DatA'
-#define ATAPI_PACKET_SIZE(IdentifyData) (IdentifyData.AtapiCmdSize ? 16 : 12)
-#define ATA_STATUS_TIMEOUT 31e5
-
-#define AtaWritePort(Channel, Port, Data) \
-    WRITE_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)), (Data))
-
-#define AtaReadPort(Channel, Port) \
-    READ_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)))
-
-#define AtaWriteBuffer(Channel, Buffer, Count) \
-    WRITE_PORT_BUFFER_USHORT(UlongToPtr(BaseArray[(Channel)] + IDX_IO1_o_Data), \
-                             (PUSHORT)(Buffer), (Count)/sizeof(USHORT))
-
-#define AtaReadBuffer(Channel, Buffer, Count) \
-    READ_PORT_BUFFER_USHORT(UlongToPtr(BaseArray[(Channel)] + IDX_IO1_i_Data), \
-                            (PUSHORT)(Buffer), (Count)/sizeof(USHORT))
-
-/* IDE/ATA Channels base - Primary, Secondary, Tertiary, Quaternary */
-static const ULONG BaseArray[] =
+/** IDE Channels base - Primary, Secondary, Tertiary, Quaternary */
+static const IDE_REG AtapChannelBaseArray[] =
 {
-#if defined(SARCH_XBOX)
+#if defined(SARCH_PC98)
+    0x640
+#elif defined(SARCH_XBOX)
     0x1F0
-#elif defined(SARCH_PC98)
-    0x640, 0x640
 #else
     0x1F0, 0x170, 0x1E8, 0x168
 #endif
 };
+#define CHANNEL_MAX_CHANNELS    RTL_NUMBER_OF(AtapChannelBaseArray)
-#define MAX_CHANNELS RTL_NUMBER_OF(BaseArray)
-#define MAX_DEVICES  2 /* Master/Slave */
+static PHW_DEVICE_UNIT AtapUnits[CHANNEL_MAX_CHANNELS * CHANNEL_MAX_DEVICES];
-static PDEVICE_UNIT Units[MAX_CHANNELS * MAX_DEVICES];
-
-/* PRIVATE PROTOTYPES *********************************************************/
+/* PRIVATE FUNCTIONS **********************************************************/
+#if defined(ATA_SUPPORT_32_BIT_IO)
 static
+inline
 BOOLEAN
-WaitForFlags(
-    IN UCHAR Channel,
-    IN UCHAR Flags,
-    IN UCHAR ExpectedValue,
-    IN ULONG Timeout
-);
+AtapIs32BitIoSupported(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+#if defined(ATA_ALWAYS_DO_32_BIT_IO)
+    return TRUE;
+#else
+    return !!(DeviceUnit->P.Flags & ATA_DEVICE_FLAG_IO32);
+#endif
+}
+#endif
 static
-BOOLEAN
-WaitForFlagsOr(
-    IN UCHAR Channel,
-    IN UCHAR FirstValue,
-    IN UCHAR SecondValue,
-    IN ULONG Timeout
-);
+VOID
+AtapSelectDevice(
+    _In_ PIDE_REGISTERS Registers,
+    _In_range_(0, 3) UCHAR DeviceNumber)
+{
+#if defined(SARCH_PC98)
+    /* Select the primary (0) or secondary (1) IDE channel */
+    ATA_WRITE(0x432, DeviceNumber >> 1);
+#endif
+
+    ATA_WRITE(Registers->Device, (DEV_SLAVE(DeviceNumber) << 4) |
IDE_DRIVE_SELECT);
+    ATA_IO_WAIT();
+}
 static
 BOOLEAN
-WaitForBusy(
-    IN UCHAR Channel,
-    IN ULONG Timeout
-);
+AtapWaitForNotBusy(
+    _In_ PIDE_REGISTERS Registers,
+    _In_range_(>, 0) ULONG Timeout,
+    _Out_opt_ PUCHAR Result)
+{
+    UCHAR IdeStatus;
+    ULONG i;
-static
-VOID
-SelectDevice(
-    IN UCHAR Channel,
-    IN UCHAR DeviceNumber
-);
+    ASSERT(Timeout != 0);
+
+    for (i = 0; i < Timeout; ++i)
+    {
+        IdeStatus = ATA_READ(Registers->Status);
+        if (!(IdeStatus & IDE_STATUS_BUSY))
+        {
+            if (Result)
+                *Result = IdeStatus;
+            return TRUE;
+        }
+
+        if (IdeStatus == 0xFF)
+            break;
+
+        StallExecutionProcessor(10);
+    }
+
+    if (Result)
+        *Result = IdeStatus;
+    return FALSE;
+}
 static
 BOOLEAN
-IdentifyDevice(
-    IN UCHAR Channel,
-    IN UCHAR DeviceNumber,
-    OUT PDEVICE_UNIT *DeviceUnit
-);
+AtapWaitForIdle(
+    _In_ PIDE_REGISTERS Registers,
+    _Out_ PUCHAR Result)
+{
+    UCHAR IdeStatus;
+    ULONG i;
+
+    for (i = 0; i < ATA_TIME_DRQ_CLEAR; ++i)
+    {
+        IdeStatus = ATA_READ(Registers->Status);
+        if (!(IdeStatus & (IDE_STATUS_DRQ | IDE_STATUS_BUSY)))
+        {
+            *Result = IdeStatus;
+            return TRUE;
+        }
+
+        StallExecutionProcessor(2);
+    }
+
+    *Result = IdeStatus;
+    return FALSE;
+}
 static
-BOOLEAN
-AtapiRequestSense(
-    IN PDEVICE_UNIT DeviceUnit,
-    OUT PSENSE_DATA SenseData
-);
+VOID
+AtapSendCdb(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request)
+{
+#if defined(ATA_SUPPORT_32_BIT_IO)
+    if (AtapIs32BitIoSupported(DeviceUnit))
+    {
+        ATA_WRITE_BLOCK_32(DeviceUnit->Registers.Data,
+                           Request->Cdb,
+                           DeviceUnit->CdbSize / sizeof(USHORT));
+    }
+    else
+#endif
+    {
+        ATA_WRITE_BLOCK_16(DeviceUnit->Registers.Data,
+                           Request->Cdb,
+                           DeviceUnit->CdbSize);
+    }
+
+    /*
+     * In polled mode (interrupts disabled)
+     * the NEC CDR-260 drive clears BSY before updating the interrupt reason register.
+     * As a workaround, we will wait for the phase change.
+     */
+    if (DeviceUnit->P.Flags & ATA_DEVICE_IS_NEC_CDR260)
+    {
+        ULONG i;
+
+        ATA_IO_WAIT();
+
+        for (i = 0; i < ATA_TIME_PHASE_CHANGE; ++i)
+        {
+            UCHAR InterruptReason = ATA_READ(DeviceUnit->Registers.InterruptReason);
+            if (InterruptReason != ATAPI_INT_REASON_COD)
+                break;
+
+            StallExecutionProcessor(10);
+        }
+    }
+}
 static
 VOID
-AtapiPrintSenseData(
-    IN PDEVICE_UNIT DeviceUnit
-);
+AtapPioDataIn(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ ULONG ByteCount)
+{
+    ByteCount = min(ByteCount, DeviceUnit->BytesToTransfer);
+
+#if defined(ATA_SUPPORT_32_BIT_IO)
+    if (AtapIs32BitIoSupported(DeviceUnit))
+    {
+        ATA_READ_BLOCK_32(DeviceUnit->Registers.Data,
+                          (PULONG)DeviceUnit->DataBuffer,
+                          ByteCount / sizeof(ULONG));
+    }
+    else
+#endif
+    {
+        ATA_READ_BLOCK_16(DeviceUnit->Registers.Data,
+                          (PUSHORT)DeviceUnit->DataBuffer,
+                          ByteCount / sizeof(USHORT));
+    }
+
+    DeviceUnit->DataBuffer += ByteCount;
+    DeviceUnit->BytesToTransfer -= ByteCount;
+}
 static
 BOOLEAN
-AtapiReadyCheck(
-    IN OUT PDEVICE_UNIT DeviceUnit
-);
+AtapWaitForRegisterAccess(
+    _In_ PIDE_REGISTERS Registers,
+    _In_range_(0, 3) UCHAR DeviceNumber)
+{
+    ULONG i;
+
+    for (i = 0; i < ATA_TIME_RESET_SELECT; ++i)
+    {
+        /* Select the device again */
+        AtapSelectDevice(Registers, DeviceNumber);
+
+        /* Check whether the selection was successful */
+        ATA_WRITE(Registers->ByteCountLow, 0xAA);
+        ATA_WRITE(Registers->ByteCountLow, 0x55);
+        ATA_WRITE(Registers->ByteCountLow, 0xAA);
+        if (ATA_READ(Registers->ByteCountLow) == 0xAA)
+            return TRUE;
+
+        StallExecutionProcessor(10);
+    }
+
+    return FALSE;
+}
 static
-BOOLEAN
-AtapiReadLogicalSectorLBA(
-    IN PDEVICE_UNIT DeviceUnit,
-    IN ULONGLONG SectorNumber,
-    OUT PVOID Buffer
-);
+VOID
+AtapSoftwareReset(
+    _In_ PIDE_REGISTERS Registers)
+{
+    ATA_WRITE(Registers->Control, IDE_DC_RESET_CONTROLLER | IDE_DC_ALWAYS);
+    StallExecutionProcessor(20);
+    ATA_WRITE(Registers->Control, IDE_DC_DISABLE_INTERRUPTS | IDE_DC_ALWAYS);
+    StallExecutionProcessor(20);
+}
 static
 BOOLEAN
-AtaReadLogicalSectorsLBA(
-    IN PDEVICE_UNIT DeviceUnit,
-    IN ULONGLONG SectorNumber,
-    IN ULONG SectorCount,
-    OUT PVOID Buffer
-);
+AtapPerformSoftwareReset(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+    PIDE_REGISTERS Registers = &DeviceUnit->Registers;
-/* FUNCTIONS ******************************************************************/
+    ERR("Reset device at %X:%u\n", Registers->Data,
DeviceUnit->DeviceNumber);
-/* Don't call this before running the system timer calibration and MM initialization
*/
-BOOLEAN
-AtaInit(OUT PUCHAR DetectedCount)
-{
-    UCHAR Channel, DeviceNumber;
-    PDEVICE_UNIT DeviceUnit = NULL;
+    /* Perform a software reset */
+    AtapSoftwareReset(Registers);
-    TRACE("AtaInit()\n");
+    /* The reset will cause the master device to be selected */
+    if (DEV_SLAVE(DeviceUnit->DeviceNumber))
+    {
+        if (!AtapWaitForRegisterAccess(Registers, DeviceUnit->DeviceNumber))
+            return FALSE;
+    }
-    *DetectedCount = 0;
+    /* Now wait for busy to clear */
+    if (!AtapWaitForNotBusy(Registers, ATA_TIME_BUSY_RESET, NULL))
+        return FALSE;
-    RtlZeroMemory(&Units, sizeof(Units));
+    return TRUE;
+}
-    /* Detect and enumerate ATA/ATAPI devices */
-    for (Channel = 0; Channel < MAX_CHANNELS; ++Channel)
+static
+UCHAR
+AtapProcessAtapiRequest(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request,
+    _In_ UCHAR IdeStatus)
+{
+    UCHAR InterruptReason;
+
+    InterruptReason = ATA_READ(DeviceUnit->Registers.InterruptReason);
+    InterruptReason &= ATAPI_INT_REASON_MASK;
+    InterruptReason |= IdeStatus & IDE_STATUS_DRQ;
+
+    switch (InterruptReason)
     {
-        for (DeviceNumber = 0; DeviceNumber < MAX_DEVICES; ++DeviceNumber)
+        case ATAPI_INT_REASON_AWAIT_CDB:
         {
-            if (IdentifyDevice(Channel, DeviceNumber, &DeviceUnit))
-            {
-                Units[(*DetectedCount)++] = DeviceUnit;
-            }
+            if (!(Request->Flags & REQUEST_FLAG_AWAIT_CDB))
+                return ATA_STATUS_RESET;
+
+            Request->Flags &= ~REQUEST_FLAG_AWAIT_CDB;
+
+            AtapSendCdb(DeviceUnit, Request);
+            return ATA_STATUS_PENDING;
         }
+
+        case ATAPI_INT_REASON_DATA_IN:
+        {
+            ULONG ByteCount;
+
+            if (!Request->DataBuffer || (Request->Flags &
REQUEST_FLAG_AWAIT_CDB))
+                return ATA_STATUS_RESET;
+
+            ByteCount = ATA_READ(DeviceUnit->Registers.ByteCountLow);
+            ByteCount |= ATA_READ(DeviceUnit->Registers.ByteCountHigh) << 8;
+
+            AtapPioDataIn(DeviceUnit, ByteCount);
+            return ATA_STATUS_PENDING;
+        }
+
+        case ATAPI_INT_REASON_STATUS_NEC:
+        {
+            /* The NEC CDR-260 drive always clears CoD and IO on command completion */
+            if (!(DeviceUnit->P.Flags & ATA_DEVICE_IS_NEC_CDR260))
+                return ATA_STATUS_RESET;
+
+            __fallthrough;
+        }
+        case ATAPI_INT_REASON_STATUS:
+        {
+            if (IdeStatus & (IDE_STATUS_ERROR | IDE_STATUS_DEVICE_FAULT))
+                return ATA_STATUS_ERROR;
+
+            break;
+        }
+
+        default:
+            return ATA_STATUS_RESET;
     }
-    return (*DetectedCount > 0);
+    return ATA_STATUS_SUCCESS;
+}
+
+static
+UCHAR
+AtapProcessAtaRequest(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request,
+    _In_ UCHAR IdeStatus)
+{
+    /* Check for errors */
+    if (IdeStatus & (IDE_STATUS_ERROR | IDE_STATUS_DEVICE_FAULT))
+    {
+        if (IdeStatus & IDE_STATUS_DRQ)
+            return ATA_STATUS_RESET;
+        else
+            return ATA_STATUS_ERROR;
+    }
+
+    /* Read command */
+    if (Request->DataBuffer)
+    {
+        if (!(IdeStatus & IDE_STATUS_DRQ))
+            return ATA_STATUS_RESET;
+
+        /* Read the next data block */
+        AtapPioDataIn(DeviceUnit, DeviceUnit->DrqByteCount);
+
+        if (DeviceUnit->BytesToTransfer != 0)
+            return ATA_STATUS_PENDING;
+
+        /* All data has been transferred, wait for DRQ to clear */
+        if (!AtapWaitForIdle(&DeviceUnit->Registers, &IdeStatus))
+            return ATA_STATUS_RESET;
+
+        if (IdeStatus & (IDE_STATUS_ERROR | IDE_STATUS_DEVICE_FAULT))
+            return ATA_STATUS_ERROR;
+    }
+
+    /* Status phase or non-data ATA command */
+    return ATA_STATUS_SUCCESS;
 }
+static
+BOOLEAN
+AtapProcessRequest(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request,
+    _In_ UCHAR IdeStatus)
+{
+    if (Request->Flags & REQUEST_FLAG_PACKET_COMMAND)
+        return AtapProcessAtapiRequest(DeviceUnit, Request, IdeStatus);
+    else
+        return AtapProcessAtaRequest(DeviceUnit, Request, IdeStatus);
+}
+
+static
+VOID
+AtapIssuePacketCommand(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request)
+{
+    USHORT ByteCount;
+
+    Request->Flags |= REQUEST_FLAG_AWAIT_CDB;
+
+    /*
+     * If a larger transfer is attempted, the 16-bit ByteCount register might overflow.
+     * In this case we round down the length to the closest multiple of 2.
+     */
+    ByteCount = min(Request->DataTransferLength, 0xFFFE);
+
+    /* Prepare to transfer a device command */
+    ATA_WRITE(DeviceUnit->Registers.ByteCountLow, (UCHAR)(ByteCount >> 0));
+    ATA_WRITE(DeviceUnit->Registers.ByteCountHigh, (UCHAR)(ByteCount >> 8));
+    ATA_WRITE(DeviceUnit->Registers.Features, IDE_FEATURE_PIO);
+    ATA_WRITE(DeviceUnit->Registers.Command, IDE_COMMAND_ATAPI_PACKET);
+}
+
+static
 VOID
-AtaFree(VOID)
+AtapLoadTaskFile(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request)
 {
-    UCHAR i;
+    PATA_TASKFILE TaskFile = &Request->TaskFile;
+    ULONG i, BlockCount;
-    for (i = 0; i < RTL_NUMBER_OF(Units); ++i)
+    /* Store the extra information in the second byte of FIFO for 48-bit commands */
+    i = (Request->Flags & REQUEST_FLAG_LBA48) ? 2 : 1;
+
+    while (i--)
+    {
+        ATA_WRITE(DeviceUnit->Registers.Features, TaskFile->Data[i].Feature);
+        ATA_WRITE(DeviceUnit->Registers.SectorCount,
TaskFile->Data[i].SectorCount);
+        ATA_WRITE(DeviceUnit->Registers.LbaLow, TaskFile->Data[i].LowLba);
+        ATA_WRITE(DeviceUnit->Registers.LbaMid, TaskFile->Data[i].MidLba);
+        ATA_WRITE(DeviceUnit->Registers.LbaHigh, TaskFile->Data[i].HighLba);
+    }
+    if (Request->Flags & REQUEST_FLAG_SET_DEVICE_REGISTER)
     {
-        if (Units[i])
-            FrLdrTempFree(Units[i], TAG_ATA_DEVICE);
+        ATA_WRITE(DeviceUnit->Registers.Device, TaskFile->DriveSelect);
     }
+    ATA_WRITE(DeviceUnit->Registers.Command, TaskFile->Command);
+
+    /* Set the byte count per DRQ data block */
+    if (Request->Flags & REQUEST_FLAG_READ_WRITE_MULTIPLE)
+        BlockCount = DeviceUnit->MultiSectorTransfer;
+    else
+        BlockCount = 1;
+    DeviceUnit->DrqByteCount = BlockCount * DeviceUnit->P.SectorSize;
 }
-PDEVICE_UNIT
-AtaGetDevice(IN UCHAR UnitNumber)
+static
+UCHAR
+AtapSendCommand(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request)
 {
-    if (UnitNumber < RTL_NUMBER_OF(Units))
-        return Units[UnitNumber];
+    UCHAR AtaStatus;
+
+    DeviceUnit->BytesToTransfer = Request->DataTransferLength;
+    DeviceUnit->DataBuffer = Request->DataBuffer;
+
+    /* Select the device */
+    AtapSelectDevice(&DeviceUnit->Registers, DeviceUnit->DeviceNumber);
+    if (!AtapWaitForNotBusy(&DeviceUnit->Registers, ATA_TIME_BUSY_SELECT, NULL))
+        return ATA_STATUS_RETRY;
+
+    /* Always disable interrupts, otherwise it may lead to problems in underlying BIOS
firmware */
+    ATA_WRITE(DeviceUnit->Registers.Control, IDE_DC_DISABLE_INTERRUPTS |
IDE_DC_ALWAYS);
+
+    if (Request->Flags & REQUEST_FLAG_PACKET_COMMAND)
+        AtapIssuePacketCommand(DeviceUnit, Request);
     else
-        return NULL;
+        AtapLoadTaskFile(DeviceUnit, Request);
+
+    while (TRUE)
+    {
+        UCHAR IdeStatus;
+
+        ATA_IO_WAIT();
+
+        if (!AtapWaitForNotBusy(&DeviceUnit->Registers, ATA_TIME_BUSY_POLL,
&IdeStatus))
+            return ATA_STATUS_RESET;
+
+        AtaStatus = AtapProcessRequest(DeviceUnit, Request, IdeStatus);
+        if (AtaStatus != ATA_STATUS_PENDING)
+            break;
+    }
+
+    return AtaStatus;
 }
+static
+VOID
+AtapAtapiBuildRequestSense(
+    _In_ PATA_DEVICE_REQUEST Request,
+    _Out_ PSENSE_DATA SenseData)
+{
+    Request->Flags = REQUEST_FLAG_PACKET_COMMAND;
+    Request->DataBuffer = SenseData;
+    Request->DataTransferLength = sizeof(*SenseData);
+    Request->Cdb[0] = SCSIOP_REQUEST_SENSE;
+    Request->Cdb[4] = (UCHAR)Request->DataTransferLength;
+}
+
+static
 BOOLEAN
-AtaAtapiReadLogicalSectorsLBA(
-    IN OUT PDEVICE_UNIT DeviceUnit,
-    IN ULONGLONG SectorNumber,
-    IN ULONG SectorCount,
-    OUT PVOID Buffer)
+AtapAtapiHandleError(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
 {
-    UCHAR RetryCount;
-    BOOLEAN Success;
+    ATA_DEVICE_REQUEST Request = { 0 };
+    SENSE_DATA SenseData;
-    if (DeviceUnit == NULL || SectorCount == 0)
+    AtapAtapiBuildRequestSense(&Request, &SenseData);
+    if (AtapSendCommand(DeviceUnit, &Request) != ATA_STATUS_SUCCESS)
         return FALSE;
-    if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
+    ERR("SK %02X, ASC %02X, ASCQ %02X\n",
+        SenseData.SenseKey,
+        SenseData.AdditionalSenseCode,
+        SenseData.AdditionalSenseCodeQualifier);
+
+    return TRUE;
+}
+
+static
+BOOLEAN
+AtapIssueCommand(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request)
+{
+    ULONG RetryCount;
+
+    for (RetryCount = 0; RetryCount < 3; ++RetryCount)
     {
-        if ((DeviceUnit->Flags & ATA_DEVICE_NO_MEDIA) || (DeviceUnit->Flags
& ATA_DEVICE_NOT_READY))
+        UCHAR AtaStatus;
+
+        AtaStatus = AtapSendCommand(DeviceUnit, Request);
+
+        if ((AtaStatus != ATA_STATUS_SUCCESS) &&
+            !(Request->Flags & REQUEST_FLAG_IDENTIFY_COMMAND))
         {
-            /* Retry 4 times */
-            for (RetryCount = 0; RetryCount < 4; ++RetryCount)
+            ERR("ATA%s command %02X failed %u %02X:%02X at %X:%u\n",
+                (Request->Flags & REQUEST_FLAG_PACKET_COMMAND) ? "PI" :
"",
+                (Request->Flags & REQUEST_FLAG_PACKET_COMMAND) ?
+                Request->Cdb[0] : Request->TaskFile.Command,
+                AtaStatus,
+                ATA_READ(DeviceUnit->Registers.Status),
+                ATA_READ(DeviceUnit->Registers.Error),
+                DeviceUnit->Registers.Data,
+                DeviceUnit->DeviceNumber);
+        }
+
+        switch (AtaStatus)
+        {
+            case ATA_STATUS_SUCCESS:
+                return TRUE;
+
+            case ATA_STATUS_RETRY:
+                break;
+
+            case ATA_STATUS_RESET:
             {
-                /* Make the device ready */
-                if (AtapiReadyCheck(DeviceUnit))
-                    break;
+                if (Request->Flags & REQUEST_FLAG_IDENTIFY_COMMAND)
+                {
+                    /*
+                     * Some controllers indicate status 0x00
+                     * when the selected device does not exist,
+                     * no point in going further.
+                     */
+                    if (ATA_READ(DeviceUnit->Registers.Status) == 0)
+                        return FALSE;
+                }
+
+                /* Turn off various things and retry the command */
+                DeviceUnit->MultiSectorTransfer = 0;
+                DeviceUnit->P.Flags &= ~ATA_DEVICE_FLAG_IO32;
+
+                if (!AtapPerformSoftwareReset(DeviceUnit))
+                    return FALSE;
+
+                break;
             }
-            if (RetryCount >= 4)
+
+            default:
             {
-                ERR("AtaAtapiReadLogicalSectorsLBA(): Device not ready.\n");
-                return FALSE;
-            }
-        }
-        if (SectorNumber + SectorCount > DeviceUnit->TotalSectors + 1)
-        {
-            ERR("AtaAtapiReadLogicalSectorsLBA(): Attempt to read more than there is
to read.\n");
-            return FALSE;
-        }
+                if (Request->Flags & REQUEST_FLAG_PACKET_COMMAND)
+                {
+                    if (!AtapAtapiHandleError(DeviceUnit))
+                        return FALSE;
+                }
-        while (SectorCount > 0)
-        {
-            /* Read a single sector */
-            Success = AtapiReadLogicalSectorLBA(DeviceUnit, SectorNumber, Buffer);
-            if (!Success)
-                return FALSE;
-
-            --SectorCount;
-            ++SectorNumber;
-            Buffer = (PVOID)((ULONG_PTR)Buffer + DeviceUnit->SectorSize);
+                /* Only retry failed read commands */
+                if (!(Request->Flags & REQUEST_FLAG_READ_COMMAND))
+                    return FALSE;
+
+                break;
+            }
         }
     }
-    else
+
+    return FALSE;
+}
+
+static
+UCHAR
+AtapGetReadCommand(
+    _In_ PATA_DEVICE_REQUEST Request)
+{
+    static const UCHAR AtapReadCommandMap[2][2] =
     {
-        /* Retry 3 times */
-        for (RetryCount = 0; RetryCount < 3; ++RetryCount)
-        {
-            /* Read a multiple sectors */
-            Success = AtaReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount,
Buffer);
-            if (Success)
-                return TRUE;
-        }
-        return FALSE;
-    }
+        /* Read                      Read EXT */
+        { IDE_COMMAND_READ,          IDE_COMMAND_READ_EXT          }, // PIO single
+        { IDE_COMMAND_READ_MULTIPLE, IDE_COMMAND_READ_MULTIPLE_EXT }, // PIO multiple
+    };
-    return TRUE;
+    return AtapReadCommandMap[(Request->Flags & REQUEST_FLAG_READ_WRITE_MULTIPLE)
? 1 : 0]
+                             [(Request->Flags & REQUEST_FLAG_LBA48) ? 1 : 0];
 }
 static
-BOOLEAN
-AtaReadLogicalSectorsLBA(
-    IN PDEVICE_UNIT DeviceUnit,
-    IN ULONGLONG SectorNumber,
-    IN ULONG SectorCount,
-    OUT PVOID Buffer)
-{
-    UCHAR Command;
-    ULONG ChsTemp;
-    USHORT Cylinder;
-    UCHAR Head;
-    UCHAR Sector;
-    ULONG BlockCount;
-    ULONG RemainingBlockCount;
-    ULONGLONG Lba;
-    BOOLEAN UseLBA48;
-
-    UseLBA48 = (DeviceUnit->Flags & ATA_DEVICE_LBA48) &&
-                (((SectorNumber + SectorCount) >= UINT64_C(0x0FFFFF80)) || SectorCount
> 256);
+VOID
+AtapBuildReadTaskFile(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ PATA_DEVICE_REQUEST Request,
+    _In_ ULONG64 Lba,
+    _In_ ULONG SectorCount)
+{
+    PATA_TASKFILE TaskFile = &Request->TaskFile;
+    UCHAR DriveSelect;
-    while (SectorCount > 0)
+    Request->Flags = REQUEST_FLAG_READ_COMMAND | REQUEST_FLAG_SET_DEVICE_REGISTER;
+
+    if (DeviceUnit->MultiSectorTransfer != 0)
     {
-        /* Prevent sector count overflow, divide it into maximum possible chunks and loop
each one */
-        if (UseLBA48)
-            BlockCount = min(SectorCount, USHRT_MAX);
-        else
-            BlockCount = min(SectorCount, UCHAR_MAX);
+        Request->Flags |= REQUEST_FLAG_READ_WRITE_MULTIPLE;
+    }
-        /* Convert LBA into a format CHS if needed */
-        if (DeviceUnit->Flags & ATA_DEVICE_CHS)
+    if (DeviceUnit->P.Flags & ATA_DEVICE_LBA)
+    {
+        DriveSelect = IDE_LBA_MODE;
+
+        TaskFile->Data[0].SectorCount = (UCHAR)SectorCount;
+        TaskFile->Data[0].LowLba = (UCHAR)Lba;              // LBA bits 0-7
+        TaskFile->Data[0].MidLba = (UCHAR)(Lba >> 8);       // LBA bits 8-15
+        TaskFile->Data[0].HighLba = (UCHAR)(Lba >> 16);     // LBA bits 16-23
+
+        if ((DeviceUnit->P.Flags & ATA_DEVICE_LBA48) &&
(AtaCommandUseLba48(Lba, SectorCount)))
         {
-            ChsTemp = DeviceUnit->IdentifyData.SectorsPerTrack *
DeviceUnit->IdentifyData.NumberOfHeads;
-            if (ChsTemp)
-            {
-                Cylinder = SectorNumber / ChsTemp;
-                Head = (SectorNumber % ChsTemp) /
DeviceUnit->IdentifyData.SectorsPerTrack;
-                Sector = (SectorNumber % DeviceUnit->IdentifyData.SectorsPerTrack) +
1;
-            }
-            else
-            {
-                Cylinder = 0;
-                Head = 0;
-                Sector = 1;
-            }
-            Lba = (Sector & 0xFF) | ((Cylinder & 0xFFFFF) << 8) | ((Head
& 0x0F) << 24);
+            ASSERT((Lba + SectorCount) <= ATA_MAX_LBA_48);
+
+            /* 48-bit command */
+            TaskFile->Data[1].SectorCount = (UCHAR)(SectorCount >> 8);
+            TaskFile->Data[1].LowLba = (UCHAR)(Lba >> 24);  // LBA bits 24-31
+            TaskFile->Data[1].MidLba = (UCHAR)(Lba >> 32);  // LBA bits 32-39
+            TaskFile->Data[1].HighLba = (UCHAR)(Lba >> 40); // LBA bits 40-47
+
+            Request->Flags |= REQUEST_FLAG_LBA48;
         }
         else
         {
-            Lba = SectorNumber;
+            ASSERT((Lba + SectorCount) <= ATA_MAX_LBA_28);
+
+            /* 28-bit command */
+            DriveSelect |= ((Lba >> 24) & 0x0F);      // LBA bits 24-27
         }
+    }
+    else
+    {
+        ULONG ChsTemp, Cylinder, Head, Sector;
+
+        ChsTemp = (ULONG)Lba / DeviceUnit->P.SectorsPerTrack;
+
+        /* Legacy CHS translation */
+        Cylinder = ChsTemp / DeviceUnit->P.Heads;
+        Head = ChsTemp % DeviceUnit->P.Heads;
+        Sector = ((ULONG)Lba % DeviceUnit->P.SectorsPerTrack) + 1;
+
+        ASSERT(Cylinder <= 65535 && Head <= 15 && Sector <=
255);
+
+        TaskFile->Data[0].SectorCount = (UCHAR)SectorCount;
+        TaskFile->Data[0].LowLba = (UCHAR)Sector;
+        TaskFile->Data[0].MidLba = (UCHAR)Cylinder;
+        TaskFile->Data[0].HighLba = (UCHAR)(Cylinder >> 8);
+
+        DriveSelect = Head;
+    }
+    TaskFile->DriveSelect = DeviceUnit->DeviceSelect | DriveSelect;
+    TaskFile->Command = AtapGetReadCommand(Request);
+}
-        /* Select the drive */
-        SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
-        if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
-        {
-            ERR("AtaReadLogicalSectorsLBA() failed. Device is busy.\n");
-            return FALSE;
-        }
+static
+VOID
+AtapBuildReadPacketCommand(
+    _In_ PATA_DEVICE_REQUEST Request,
+    _In_ ULONG64 Lba,
+    _In_ ULONG SectorCount)
+{
+    Request->Flags = REQUEST_FLAG_READ_COMMAND | REQUEST_FLAG_PACKET_COMMAND;
-        /* Disable interrupts */
-        AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_Control,
IDE_DC_DISABLE_INTERRUPTS);
-        StallExecutionProcessor(1);
+    RtlZeroMemory(Request->Cdb, sizeof(Request->Cdb));
-        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
>> 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);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 32)
& 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 8)
& 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >>
40) & 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >>
16) & 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_DriveSelect,
-                         IDE_USE_LBA | (DeviceUnit->DeviceNumber ? IDE_DRIVE_2 :
IDE_DRIVE_1));
-            Command = IDE_COMMAND_READ_EXT;
-        }
-        else
-        {
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, ATA_PIO);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, BlockCount &
0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, Lba & 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 8)
& 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >>
16) & 0xFF);
-            AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_DriveSelect,
-                         ((Lba >> 24) & 0x0F) |
-                         (DeviceUnit->Flags & ATA_DEVICE_CHS ? 0x00 : IDE_USE_LBA)
|
-                         (DeviceUnit->DeviceNumber ? IDE_DRIVE_SELECT_2 :
IDE_DRIVE_SELECT_1));
-            Command = IDE_COMMAND_READ;
-        }
+    if (Lba > MAXULONG)
+    {
+        /* READ (16) */
+        Request->Cdb[0] = SCSIOP_READ16;
+        Request->Cdb[2] = (UCHAR)(Lba >> 56);
+        Request->Cdb[3] = (UCHAR)(Lba >> 48);
+        Request->Cdb[4] = (UCHAR)(Lba >> 40);
+        Request->Cdb[5] = (UCHAR)(Lba >> 32);
+        Request->Cdb[6] = (UCHAR)(Lba >> 24);
+        Request->Cdb[7] = (UCHAR)(Lba >> 16);
+        Request->Cdb[8] = (UCHAR)(Lba >> 8);
+        Request->Cdb[9] = (UCHAR)(Lba >> 0);
+        Request->Cdb[10] = (UCHAR)(SectorCount >> 24);
+        Request->Cdb[11] = (UCHAR)(SectorCount >> 16);
+        Request->Cdb[12] = (UCHAR)(SectorCount >> 8);
+        Request->Cdb[13] = (UCHAR)(SectorCount >> 0);
+    }
+    else
+    {
+        /* READ (10) */
+        Request->Cdb[0] = SCSIOP_READ;
+        Request->Cdb[2] = (UCHAR)(Lba >> 24);
+        Request->Cdb[3] = (UCHAR)(Lba >> 16);
+        Request->Cdb[4] = (UCHAR)(Lba >> 8);
+        Request->Cdb[5] = (UCHAR)(Lba >> 0);
+        Request->Cdb[7] = (UCHAR)(SectorCount >> 8);
+        Request->Cdb[8] = (UCHAR)(SectorCount >> 0);
+    }
+}
+
+static
+BOOLEAN
+AtapIsDevicePresent(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+    PIDE_REGISTERS Registers = &DeviceUnit->Registers;
+    UCHAR IdeStatus;
-        /* Send read command */
-        AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Command, Command);
-        StallExecutionProcessor(5);
+    AtapSelectDevice(Registers, DeviceUnit->DeviceNumber);
-        for (RemainingBlockCount = BlockCount; RemainingBlockCount > 0;
--RemainingBlockCount)
-        {
-            /* Wait for ready to transfer data block */
-            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),
-                    AtaReadPort(DeviceUnit->Channel, IDX_IO1_i_Error));
-                return FALSE;
-            }
+    IdeStatus = ATA_READ(Registers->Status);
+    if (IdeStatus == 0xFF || IdeStatus == 0x7F)
+        return FALSE;
-            /* Transfer the data block */
-            AtaReadBuffer(DeviceUnit->Channel, Buffer, DeviceUnit->SectorSize);
+    ATA_WRITE(Registers->ByteCountLow, 0x55);
+    ATA_WRITE(Registers->ByteCountLow, 0xAA);
+    ATA_WRITE(Registers->ByteCountLow, 0x55);
+    if (ATA_READ(Registers->ByteCountLow) != 0x55)
+        return FALSE;
+    ATA_WRITE(Registers->ByteCountHigh, 0xAA);
+    ATA_WRITE(Registers->ByteCountHigh, 0x55);
+    ATA_WRITE(Registers->ByteCountHigh, 0xAA);
+    if (ATA_READ(Registers->ByteCountHigh) != 0xAA)
+        return FALSE;
-            Buffer = (PVOID)((ULONG_PTR)Buffer + DeviceUnit->SectorSize);
-        }
+    if (!AtapWaitForNotBusy(Registers, ATA_TIME_BUSY_ENUM, &IdeStatus))
+    {
+        ERR("Device %X:%u is busy %02x\n", Registers->Data,
DeviceUnit->DeviceNumber, IdeStatus);
-        SectorNumber += BlockCount;
-        SectorCount -= BlockCount;
+        /* Bring the device into a known state */
+        if (!AtapPerformSoftwareReset(DeviceUnit))
+            return FALSE;
     }
     return TRUE;
@@ -373,569 +752,577 @@ AtaReadLogicalSectorsLBA(
 static
 BOOLEAN
-AtaSendAtapiPacket(
-    IN UCHAR Channel,
-    IN PUCHAR AtapiPacket,
-    IN UCHAR PacketSize,
-    IN USHORT ByteCount)
+AtapReadIdentifyData(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ UCHAR Command)
 {
+    ATA_DEVICE_REQUEST Request = { 0 };
+    PIDENTIFY_DEVICE_DATA Id = &DeviceUnit->IdentifyDeviceData;
+
+    /* Send the identify command */
+    Request.Flags = REQUEST_FLAG_IDENTIFY_COMMAND;
+    Request.DataBuffer = Id;
+    Request.DataTransferLength = sizeof(*Id);
+    Request.TaskFile.Command = Command;
+
+    return AtapIssueCommand(DeviceUnit, &Request);
+}
+
+static
+ATA_DEVICE_CLASS
+AtapIdentifyDevice(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+    if (!AtapIsDevicePresent(DeviceUnit))
+        return DEV_NONE;
+
     /*
-     * REQUEST SENSE is used by driver to clear the ATAPI 'Bus reset' indication.
-     * TEST UNIT READY doesn't require space for returned data.
+     * We don't check the device signature here,
+     * because the NEC CDR-260 drive reports an ATA signature.
      */
-    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);
-
-    /* Maximum byte count that is to be transferred */
-    AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountLow, ByteCount & 0xFF);
-    AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountHigh, (ByteCount >> 8) &
0xFF);
-
-    /* Prepare to transfer a device command via a command packet */
-    AtaWritePort(Channel, IDX_ATAPI_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
-    StallExecutionProcessor(50);
-    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));
-        return FALSE;
-    }
-    /* Command packet transfer */
-    AtaWriteBuffer(Channel, AtapiPacket, PacketSize);
-    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));
-        return FALSE;
-    }
+    /* Check for ATA */
+    if (AtapReadIdentifyData(DeviceUnit, IDE_COMMAND_IDENTIFY))
+        return DEV_ATA;
-    return TRUE;
+    /* Check for ATAPI */
+    if (AtapReadIdentifyData(DeviceUnit, IDE_COMMAND_ATAPI_IDENTIFY))
+        return DEV_ATAPI;
+
+    return DEV_NONE;
 }
 static
 BOOLEAN
-AtapiReadLogicalSectorLBA(
-    IN PDEVICE_UNIT DeviceUnit,
-    IN ULONGLONG SectorNumber,
-    OUT PVOID Buffer)
+AtapAtapiReadCapacity16(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _Out_ PREAD_CAPACITY16_DATA CapacityData)
 {
-    UCHAR AtapiPacket[16];
-    USHORT DataSize;
-    BOOLEAN Success;
+    ATA_DEVICE_REQUEST Request = { 0 };
-    /* Select the drive */
-    SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
-    if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
-    {
-        ERR("AtapiReadLogicalSectorLBA() failed. Device is busy!\n");
-        return FALSE;
-    }
+    /* Send the SCSI READ CAPACITY(16) command */
+    Request.Flags = REQUEST_FLAG_PACKET_COMMAND;
+    Request.DataBuffer = CapacityData;
+    Request.DataTransferLength = sizeof(*CapacityData);
+    Request.Cdb[0] = SCSIOP_SERVICE_ACTION_IN16;
+    Request.Cdb[1] = SERVICE_ACTION_READ_CAPACITY16;
+    Request.Cdb[13] = sizeof(*CapacityData);
-    /* Disable interrupts */
-    AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS);
-    StallExecutionProcessor(1);
-
-    /* Send the SCSI READ command */
-    RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-    AtapiPacket[0] = SCSIOP_READ;
-    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),
-                                 DeviceUnit->SectorSize);
-    if (!Success)
-    {
-        ERR("AtapiReadLogicalSectorLBA() failed. A read error occurred.\n");
-        AtapiPrintSenseData(DeviceUnit);
-        return FALSE;
-    }
+    return AtapIssueCommand(DeviceUnit, &Request);
+}
-    DataSize = (AtaReadPort(DeviceUnit->Channel, IDX_ATAPI_IO1_i_ByteCountHigh)
<< 8) |
-                AtaReadPort(DeviceUnit->Channel, IDX_ATAPI_IO1_i_ByteCountLow);
+static
+BOOLEAN
+AtapAtapiReadCapacity10(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _Out_ PREAD_CAPACITY_DATA CapacityData)
+{
+    ATA_DEVICE_REQUEST Request = { 0 };
-    /* Transfer the data block */
-    AtaReadBuffer(DeviceUnit->Channel, Buffer, DataSize);
+    /* Send the SCSI READ CAPACITY(10) command */
+    Request.Flags = REQUEST_FLAG_PACKET_COMMAND;
+    Request.DataBuffer = CapacityData;
+    Request.DataTransferLength = sizeof(*CapacityData);
+    Request.Cdb[0] = SCSIOP_READ_CAPACITY;
-    return TRUE;
+    return AtapIssueCommand(DeviceUnit, &Request);
 }
 static
 VOID
-AtapiCapacityDetect(
-    IN PDEVICE_UNIT DeviceUnit,
-    OUT PULONGLONG TotalSectors,
-    OUT PULONG SectorSize)
+AtapAtapiDetectCapacity(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _Out_ PULONG64 TotalSectors,
+    _Out_ PULONG SectorSize)
 {
-    UCHAR AtapiPacket[16];
-    UCHAR AtapiCapacity[8];
-
-    /* Send the SCSI READ CAPACITY(10) command */
-    RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-    AtapiPacket[0] = SCSIOP_READ_CAPACITY;
-    if (AtaSendAtapiPacket(DeviceUnit->Channel, AtapiPacket,
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData), 8))
+    union
     {
-        AtaReadBuffer(DeviceUnit->Channel, &AtapiCapacity, 8);
+        READ_CAPACITY_DATA Cmd10;
+        READ_CAPACITY16_DATA Cmd16;
+    } CapacityData;
+    ULONG LastLba;
-        *TotalSectors = (AtapiCapacity[0] << 24) | (AtapiCapacity[1] << 16) |
-                        (AtapiCapacity[2] << 8) | AtapiCapacity[3];
+    *TotalSectors = 0;
+    *SectorSize = 0;
-        *SectorSize = (AtapiCapacity[4] << 24) | (AtapiCapacity[5] << 16) |
-                      (AtapiCapacity[6] << 8) | AtapiCapacity[7];
+    if (!AtapAtapiReadCapacity10(DeviceUnit, &CapacityData.Cmd10))
+        return;
-        /* If device reports a non-zero block length, reset to defaults (we use READ
command instead of READ CD) */
-        if (*SectorSize != 0)
-            *SectorSize = 2048;
+    LastLba = RtlUlongByteSwap(CapacityData.Cmd10.LogicalBlockAddress);
+    if (LastLba == MAXULONG)
+    {
+        if (!AtapAtapiReadCapacity16(DeviceUnit, &CapacityData.Cmd16))
+            return;
+
+        *TotalSectors =
RtlUlonglongByteSwap(CapacityData.Cmd16.LogicalBlockAddress.QuadPart) + 1;
+        *SectorSize = RtlUlongByteSwap(CapacityData.Cmd16.BytesPerBlock);
     }
     else
     {
-        *TotalSectors = 0;
-        *SectorSize = 0;
-
-        AtapiPrintSenseData(DeviceUnit);
+        *TotalSectors = LastLba + 1;
+        *SectorSize = RtlUlongByteSwap(CapacityData.Cmd10.BytesPerBlock);
     }
+
+    /*
+     * If device reports a non-zero block length, reset to defaults
+     * (we use a READ command instead of READ CD).
+     */
+    if (*SectorSize != 0)
+        *SectorSize = 2048;
 }
 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;
-    }
+AtapAtapiTestUnitReady(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+    ATA_DEVICE_REQUEST Request = { 0 };
+
+    /* Send the SCSI TEST UNIT READY command */
+    Request.Flags = REQUEST_FLAG_PACKET_COMMAND;
+    Request.Cdb[0] = SCSIOP_TEST_UNIT_READY;
+
+    return AtapIssueCommand(DeviceUnit, &Request);
 }
 static
-VOID
-AtapiPrintSenseData(IN PDEVICE_UNIT DeviceUnit)
+BOOLEAN
+AtapAtapiRequestSense(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _Out_ PSENSE_DATA SenseData)
 {
-    SENSE_DATA SenseData;
+    ATA_DEVICE_REQUEST Request = { 0 };
-    if (AtapiRequestSense(DeviceUnit, &SenseData))
-    {
-        ERR("SK 0x%x, ASC 0x%x, ASCQ 0x%x\n",
-            SenseData.SenseKey,
-            SenseData.AdditionalSenseCode,
-            SenseData.AdditionalSenseCodeQualifier);
-    }
+    AtapAtapiBuildRequestSense(&Request, SenseData);
+    return AtapIssueCommand(DeviceUnit, &Request);
 }
 static
 BOOLEAN
-AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
+AtapAtapiReadToc(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
 {
-    UCHAR AtapiPacket[16];
+    ATA_DEVICE_REQUEST Request = { 0 };
     UCHAR DummyData[MAXIMUM_CDROM_SIZE];
+
+    /* Send the SCSI READ TOC command */
+    Request.Flags = REQUEST_FLAG_PACKET_COMMAND;
+    Request.DataBuffer = DummyData;
+    Request.DataTransferLength = sizeof(DummyData);
+    Request.Cdb[0] = SCSIOP_READ_TOC;
+    Request.Cdb[7] = (MAXIMUM_CDROM_SIZE >> 8) & 0xFF;
+    Request.Cdb[8] = MAXIMUM_CDROM_SIZE & 0xFF;
+    Request.Cdb[9] = READ_TOC_FORMAT_SESSION << 6;
+
+    return AtapIssueCommand(DeviceUnit, &Request);
+}
+
+static
+BOOLEAN
+AtapAtapiReadyCheck(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
     SENSE_DATA SenseData;
-    BOOLEAN Success;
-    /* Select the drive */
-    SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber);
-    if (!WaitForBusy(DeviceUnit->Channel, ATA_STATUS_TIMEOUT))
+    if (!AtapAtapiTestUnitReady(DeviceUnit))
         return FALSE;
-    /* Send the SCSI TEST UNIT READY command */
-    RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-    AtapiPacket[0] = SCSIOP_TEST_UNIT_READY;
-    AtaSendAtapiPacket(DeviceUnit->Channel,
-                       AtapiPacket,
-                       ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
-                       0);
-
-    if (!AtapiRequestSense(DeviceUnit, &SenseData))
+    if (!AtapAtapiRequestSense(DeviceUnit, &SenseData))
         return FALSE;
-    AtaReadBuffer(DeviceUnit->Channel, &SenseData, SENSE_BUFFER_SIZE);
-    TRACE("SK 0x%x, ASC 0x%x, ASCQ 0x%x\n",
-          SenseData.SenseKey,
-          SenseData.AdditionalSenseCode,
-          SenseData.AdditionalSenseCodeQualifier);
-
     if (SenseData.SenseKey == SCSI_SENSE_NOT_READY)
     {
+        if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
+            return FALSE;
+
         if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)
         {
             switch (SenseData.AdditionalSenseCodeQualifier)
             {
                 case SCSI_SENSEQ_BECOMING_READY:
                     /* Wait until the CD is spun up */
-                    StallExecutionProcessor(4e6);
+                    StallExecutionProcessor(2e6);
                     return FALSE;
                 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
-                    /* The drive needs to be spun up, send the SCSI READ TOC command */
-                    RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
-                    AtapiPacket[0] = SCSIOP_READ_TOC;
-                    AtapiPacket[7] = (MAXIMUM_CDROM_SIZE << 8) & 0xFF;
-                    AtapiPacket[8] = MAXIMUM_CDROM_SIZE & 0xFF;
-                    AtapiPacket[9] = READ_TOC_FORMAT_SESSION << 6;
-                    Success = AtaSendAtapiPacket(DeviceUnit->Channel,
-                                                 AtapiPacket,
-
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
-                                                 MAXIMUM_CDROM_SIZE);
-                    if (!Success)
-                    {
-                        AtapiPrintSenseData(DeviceUnit);
-                        return FALSE;
-                    }
-
-                    AtaReadBuffer(DeviceUnit->Channel, &DummyData,
MAXIMUM_CDROM_SIZE);
-                    /* fall through */
+                    /* The drive needs to be spun up */
+                    AtapAtapiReadToc(DeviceUnit);
+                    return FALSE;
                 default:
-                    DeviceUnit->Flags &= ~ATA_DEVICE_NOT_READY;
                     return FALSE;
-
             }
         }
-        else if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
+    }
+
+    return TRUE;
+}
+
+static
+VOID
+AtapAtapiClearUnitAttention(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+    SENSE_DATA SenseData;
+    ULONG i;
+
+    for (i = 0; i < 5; ++i)
+    {
+        if (!AtapAtapiRequestSense(DeviceUnit, &SenseData))
+            continue;
+
+        if ((SenseData.SenseKey != SCSI_SENSE_UNIT_ATTENTION) &&
+            (SenseData.AdditionalSenseCode != SCSI_ADSENSE_BUS_RESET))
         {
-            DeviceUnit->Flags |= ATA_DEVICE_NO_MEDIA;
-            return FALSE;
+            break;
         }
     }
-    else
+}
+
+static
+BOOLEAN
+AtapAtapiInitDevice(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
+{
+    PIDENTIFY_PACKET_DATA IdentifyPacketData = &DeviceUnit->IdentifyPacketData;
+    ULONG i;
+
+    DeviceUnit->CdbSize = AtaDevCdbSizeInWords(IdentifyPacketData);
+
+    /* Clear the ATAPI 'Bus reset' indication */
+    AtapAtapiClearUnitAttention(DeviceUnit);
+
+    /* Make the device ready */
+    for (i = 4; i > 0; i--)
+    {
+        if (AtapAtapiReadyCheck(DeviceUnit))
+            break;
+    }
+    if (i == 0)
     {
-        DeviceUnit->Flags &= ~ATA_DEVICE_NOT_READY;
+        ERR("Device not ready\n");
+        return FALSE;
     }
-    if (DeviceUnit->Flags & ATA_DEVICE_NO_MEDIA)
+    /* Detect a medium's capacity */
+    AtapAtapiDetectCapacity(DeviceUnit,
+                            &DeviceUnit->P.TotalSectors,
+                            &DeviceUnit->P.SectorSize);
+    if (DeviceUnit->P.SectorSize == 0 || DeviceUnit->P.TotalSectors == 0)
     {
-        /* Detect a medium's capacity */
-        AtapiCapacityDetect(DeviceUnit, &DeviceUnit->TotalSectors,
&DeviceUnit->SectorSize);
+        TRACE("No media found\n");
+        return FALSE;
+    }
-        /* If nothing was returned, reset to defaults */
-        if (DeviceUnit->SectorSize == 0)
-            DeviceUnit->SectorSize = 2048;
-        if (DeviceUnit->TotalSectors == 0)
-            DeviceUnit->TotalSectors = 0xFFFFFFFF;
+    DeviceUnit->P.Cylinders = MAXULONG;
+    DeviceUnit->P.Heads = MAXULONG;
+    DeviceUnit->P.SectorsPerTrack = MAXULONG;
-        DeviceUnit->Flags &= ~ATA_DEVICE_NO_MEDIA;
-    }
+    DeviceUnit->MaximumTransferLength = 0xFFFF;
     return TRUE;
 }
 static
-BOOLEAN
-WaitForFlags(
-    IN UCHAR Channel,
-    IN UCHAR Flags,
-    IN UCHAR ExpectedValue,
-    IN ULONG Timeout)
+VOID
+AtapAtaSetMultipleMode(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
 {
-    UCHAR Status;
+    ATA_DEVICE_REQUEST Request = { 0 };
-    ASSERT(Timeout != 0);
+#if !defined(ATA_ENABLE_MULTIPLE_MODE)
+    /* Inherit multiple mode from the state the BIOS firmware left the device in during
boot */
+    DeviceUnit->MultiSectorTransfer =
AtaDevCurrentSectorsPerDrq(&DeviceUnit->IdentifyDeviceData);
+    if (DeviceUnit->MultiSectorTransfer != 0)
+        return;
+#endif
-    WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
+    /* Use the maximum possible value */
+    DeviceUnit->MultiSectorTransfer =
AtaDevMaximumSectorsPerDrq(&DeviceUnit->IdentifyDeviceData);
+    if (DeviceUnit->MultiSectorTransfer == 0)
+        return;
-    while (Timeout--)
+    Request.TaskFile.Command = IDE_COMMAND_SET_MULTIPLE;
+    Request.TaskFile.Data[0].SectorCount = DeviceUnit->MultiSectorTransfer;
+    if (!AtapIssueCommand(DeviceUnit, &Request))
     {
-        StallExecutionProcessor(10);
-
-        Status = AtaReadPort(Channel, IDX_IO1_i_Status);
-        if (Status & IDE_STATUS_ERROR)
-            return FALSE;
-        else if ((Status & Flags) == ExpectedValue)
-            return TRUE;
+        DeviceUnit->MultiSectorTransfer = 0;
     }
-    return FALSE;
 }
 static
 BOOLEAN
-WaitForFlagsOr(
-    IN UCHAR Channel,
-    IN UCHAR FirstValue,
-    IN UCHAR SecondValue,
-    IN ULONG Timeout)
+AtapAtaInitDevice(
+    _In_ PHW_DEVICE_UNIT DeviceUnit)
 {
-    UCHAR Status;
+    PIDENTIFY_DEVICE_DATA IdentifyData = &DeviceUnit->IdentifyDeviceData;
+    ULONG64 TotalSectors;
+    USHORT Cylinders, Heads, SectorsPerTrack;
-    ASSERT(Timeout != 0);
+    DeviceUnit->MaximumTransferLength = 0xFF;
-    WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
+    if (AtaDevIsCurrentGeometryValid(IdentifyData))
+        AtaDevCurrentChsTranslation(IdentifyData, &Cylinders, &Heads,
&SectorsPerTrack);
+    else
+        AtaDevDefaultChsTranslation(IdentifyData, &Cylinders, &Heads,
&SectorsPerTrack);
-    while (Timeout--)
+    /* Using LBA addressing mode */
+    if (AtaDevHasLbaTranslation(IdentifyData))
     {
-        StallExecutionProcessor(10);
+        DeviceUnit->P.Flags |= ATA_DEVICE_LBA;
-        Status = AtaReadPort(Channel, IDX_IO1_i_Status);
-        if (Status & IDE_STATUS_ERROR)
-            return FALSE;
-        else if ((Status & FirstValue) || (Status & SecondValue))
-            return TRUE;
+        if (AtaDevHas48BitAddressFeature(IdentifyData))
+        {
+            /* Using LBA48 addressing mode */
+            TotalSectors = AtaDevUserAddressableSectors48Bit(IdentifyData);
+            ASSERT(TotalSectors <= ATA_MAX_LBA_48);
+
+            DeviceUnit->P.Flags |= ATA_DEVICE_LBA48;
+            DeviceUnit->MaximumTransferLength = 0x10000;
+        }
+        else
+        {
+            /* Using LBA28 addressing mode */
+            TotalSectors = AtaDevUserAddressableSectors28Bit(IdentifyData);
+            ASSERT(TotalSectors <= ATA_MAX_LBA_28);
+        }
     }
-    return FALSE;
+    else
+    {
+        /* Using CHS addressing mode */
+        TotalSectors = Cylinders * Heads * SectorsPerTrack;
+    }
+
+    if (TotalSectors == 0)
+    {
+        ERR("Unknown geometry\n");
+        return FALSE;
+    }
+
+    DeviceUnit->P.TotalSectors = TotalSectors;
+    DeviceUnit->P.Cylinders = Cylinders;
+    DeviceUnit->P.Heads = Heads;
+    DeviceUnit->P.SectorsPerTrack = SectorsPerTrack;
+    DeviceUnit->P.SectorSize = AtaDevBytesPerLogicalSector(IdentifyData);
+    ASSERT(DeviceUnit->P.SectorSize >= 512);
+    DeviceUnit->P.SectorSize = max(DeviceUnit->P.SectorSize, 512);
+
+    AtapAtaSetMultipleMode(DeviceUnit);
+
+    TRACE("Multiple sector setting %u\n", DeviceUnit->MultiSectorTransfer);
+
+    return TRUE;
 }
 static
 BOOLEAN
-WaitForBusy(
-    IN UCHAR Channel,
-    IN ULONG Timeout)
+AtapAnalyzeIdentifyData(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ ATA_DEVICE_CLASS DeviceClass)
 {
-    ASSERT(Timeout != 0);
+    PIDENTIFY_DEVICE_DATA Id = &DeviceUnit->IdentifyDeviceData;
+    ULONG i;
-    while (Timeout--)
+    /* Verify the checksum */
+    if (!AtaDevIsIdentifyDataValid(Id))
     {
-        StallExecutionProcessor(10);
+        ERR("Identify data CRC error\n");
+        return FALSE;
+    }
-        if ((AtaReadPort(Channel, IDX_IO1_i_Status) & IDE_STATUS_BUSY) == 0)
-            return TRUE;
+    if (DeviceClass == DEV_ATAPI)
+    {
+        DeviceUnit->P.Flags |= ATA_DEVICE_ATAPI | ATA_DEVICE_LBA;
+
+        /* The returned string is not byteswapped */
+        if (Id->ModelNumber[0] == 'N' &&
+            Id->ModelNumber[1] == 'E' &&
+            Id->ModelNumber[2] == 'C' &&
+            Id->ModelNumber[3] == ' ')
+        {
+            DeviceUnit->P.Flags |= ATA_DEVICE_IS_NEC_CDR260;
+        }
     }
-    return FALSE;
+
+    /* Swap byte order of the ASCII data */
+    for (i = 0; i < sizeof(Id->SerialNumber) / 2; ++i)
+        ((PUSHORT)Id->SerialNumber)[i] =
RtlUshortByteSwap(((PUSHORT)Id->SerialNumber)[i]);
+
+    for (i = 0; i < sizeof(Id->FirmwareRevision) / 2; ++i)
+        ((PUSHORT)Id->FirmwareRevision)[i] =
RtlUshortByteSwap(((PUSHORT)Id->FirmwareRevision)[i]);
+
+    for (i = 0; i < sizeof(Id->ModelNumber) / 2; ++i)
+        ((PUSHORT)Id->ModelNumber)[i] =
RtlUshortByteSwap(((PUSHORT)Id->ModelNumber)[i]);
+
+    TRACE("MN  '%.*s'\n", sizeof(Id->ModelNumber),
Id->ModelNumber);
+    TRACE("FR  '%.*s'\n", sizeof(Id->FirmwareRevision),
Id->FirmwareRevision);
+    TRACE("S/N '%.*s'\n", sizeof(Id->SerialNumber),
Id->SerialNumber);
+
+    return TRUE;
 }
 static
-VOID
-AtaHardReset(IN UCHAR Channel)
+BOOLEAN
+AtapInitDevice(
+    _In_ PHW_DEVICE_UNIT DeviceUnit,
+    _In_ ATA_DEVICE_CLASS DeviceClass)
 {
-    TRACE("AtaHardReset(Controller %d)\n", Channel);
+    if (!AtapAnalyzeIdentifyData(DeviceUnit, DeviceClass))
+        return FALSE;
-    AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER);
-    StallExecutionProcessor(100000);
-    AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
-    StallExecutionProcessor(5);
-    WaitForBusy(Channel, ATA_STATUS_TIMEOUT);
+    if (DeviceClass == DEV_ATAPI)
+        return AtapAtapiInitDevice(DeviceUnit);
+    else
+        return AtapAtaInitDevice(DeviceUnit);
 }
 static
-VOID
-SelectDevice(IN UCHAR Channel, IN UCHAR DeviceNumber)
+BOOLEAN
+AtapIdentifyChannel(
+    _In_ ULONG ChannelNumber,
+    _Out_ PIDE_REGISTERS Registers)
 {
+    const IDE_REG IoBase = AtapChannelBaseArray[ChannelNumber];
+    ULONG Spare;
+
+#if defined(SARCH_PC98)
+    if (ATA_READ(0x432) == 0xFF)
+        return FALSE;
+#endif
+
 #if defined(SARCH_PC98)
-    /* Select IDE Channel */
-    WRITE_PORT_UCHAR((PUCHAR)IDE_IO_o_BankSelect, Channel);
-    StallExecutionProcessor(5);
+    Spare = 2;
+    Registers->Control     = 0x74C;
+#else
+    Spare = 1;
+    Registers->Control     = IoBase + 0x206;
 #endif
+    Registers->Data        = IoBase + 0 * Spare;
+    Registers->Error       = IoBase + 1 * Spare;
+    Registers->SectorCount = IoBase + 2 * Spare;
+    Registers->LbaLow      = IoBase + 3 * Spare;
+    Registers->LbaMid      = IoBase + 4 * Spare;
+    Registers->LbaHigh     = IoBase + 5 * Spare;
+    Registers->Device      = IoBase + 6 * Spare;
+    Registers->Status      = IoBase + 7 * Spare;
-    AtaWritePort(Channel, IDX_IO1_o_DriveSelect,
-                 DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1);
-    StallExecutionProcessor(5);
+    return TRUE;
 }
-static
+/* PUBLIC FUNCTIONS ***********************************************************/
+
 BOOLEAN
-IdentifyDevice(
-    IN UCHAR Channel,
-    IN UCHAR DeviceNumber,
-    OUT PDEVICE_UNIT *DeviceUnit)
-{
-    UCHAR SignatureLow, SignatureHigh, SignatureCount, SignatureNumber;
-    UCHAR Command;
-    IDENTIFY_DATA Id;
-    SENSE_DATA SenseData;
-    ULONG i;
-    ULONG SectorSize;
-    ULONGLONG TotalSectors;
-    USHORT Flags = 0;
-
-    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 */
-    SelectDevice(Channel, DeviceNumber);
-    if (!WaitForBusy(Channel, ATA_STATUS_TIMEOUT))
-        goto Failure;
-
-    /* Signature check */
-    SignatureLow = AtaReadPort(Channel, IDX_IO1_i_CylinderLow);
-    SignatureHigh = AtaReadPort(Channel, IDX_IO1_i_CylinderHigh);
-    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)
-    {
-        TRACE("IdentifyDevice(): Found ATAPI device at %d:%d\n", Channel,
DeviceNumber);
-        Flags |= ATA_DEVICE_ATAPI | ATA_DEVICE_LBA | ATA_DEVICE_NOT_READY;
-        Command = IDE_COMMAND_ATAPI_IDENTIFY;
-    }
-    else
-    {
-        goto Failure;
-    }
+AtaReadLogicalSectors(
+    _In_ PDEVICE_UNIT DeviceUnit,
+    _In_ ULONG64 SectorNumber,
+    _In_ ULONG SectorCount,
+    _Out_writes_bytes_all_(SectorCount * DeviceUnit->SectorSize) PVOID Buffer)
+{
+    PHW_DEVICE_UNIT Unit = (PHW_DEVICE_UNIT)DeviceUnit;
+    ATA_DEVICE_REQUEST Request = { 0 };
-    /* Disable interrupts */
-    AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS);
-    StallExecutionProcessor(5);
+    ASSERT((SectorNumber + SectorCount) <= Unit->P.TotalSectors);
+    ASSERT(SectorCount != 0);
-    /* 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))
+    while (SectorCount > 0)
     {
-        ERR("IdentifyDevice(): Identify command failed.\n");
-        goto Failure;
-    }
+        ULONG BlockCount;
-    /* Receive parameter information from the device */
-    AtaReadBuffer(Channel, &Id, IDENTIFY_DATA_SIZE);
+        BlockCount = min(SectorCount, Unit->MaximumTransferLength);
-    /* Swap byte order of the ASCII data */
-    for (i = 0; i < RTL_NUMBER_OF(Id.SerialNumber); ++i)
-        Id.SerialNumber[i] = RtlUshortByteSwap(Id.SerialNumber[i]);
+        Request.DataBuffer = Buffer;
+        Request.DataTransferLength = BlockCount * Unit->P.SectorSize;
-    for (i = 0; i < RTL_NUMBER_OF(Id.FirmwareRevision); ++i)
-        Id.FirmwareRevision[i] = RtlUshortByteSwap(Id.FirmwareRevision[i]);
+        if (Unit->P.Flags & ATA_DEVICE_ATAPI)
+            AtapBuildReadPacketCommand(&Request, SectorNumber, BlockCount);
+        else
+            AtapBuildReadTaskFile(Unit, &Request, SectorNumber, BlockCount);
-    for (i = 0; i < RTL_NUMBER_OF(Id.ModelNumber); ++i)
-        Id.ModelNumber[i] = RtlUshortByteSwap(Id.ModelNumber[i]);
+        if (!AtapIssueCommand(Unit, &Request))
+            return FALSE;
-    TRACE("S/N %.*s\n", sizeof(Id.SerialNumber), Id.SerialNumber);
-    TRACE("FR %.*s\n", sizeof(Id.FirmwareRevision), Id.FirmwareRevision);
-    TRACE("MN %.*s\n", sizeof(Id.ModelNumber), Id.ModelNumber);
+        SectorNumber += BlockCount;
+        SectorCount -= BlockCount;
-    /* Allocate a new device unit structure */
-    *DeviceUnit = FrLdrTempAlloc(sizeof(DEVICE_UNIT), TAG_ATA_DEVICE);
-    if (*DeviceUnit == NULL)
-    {
-        ERR("Failed to allocate device unit!\n");
-        return FALSE;
+        Buffer = (PVOID)((ULONG_PTR)Buffer + Unit->P.SectorSize);
     }
-    RtlZeroMemory(*DeviceUnit, sizeof(DEVICE_UNIT));
-    (*DeviceUnit)->Channel = Channel;
-    (*DeviceUnit)->DeviceNumber = DeviceNumber;
-    (*DeviceUnit)->IdentifyData = Id;
+    return TRUE;
+}
-    if (Flags & ATA_DEVICE_ATAPI)
-    {
-        /* Clear the ATAPI 'Bus reset' indication */
-        for (i = 0; i < 10; ++i)
-        {
-            AtapiRequestSense(*DeviceUnit, &SenseData);
-            StallExecutionProcessor(10);
-        }
+PDEVICE_UNIT
+AtaGetDevice(
+    _In_ UCHAR UnitNumber)
+{
+    if (UnitNumber < RTL_NUMBER_OF(AtapUnits))
+        return (PDEVICE_UNIT)AtapUnits[UnitNumber];
-        /* Detect a medium's capacity */
-        AtapiCapacityDetect(*DeviceUnit, &TotalSectors, &SectorSize);
-        if (SectorSize == 0 || TotalSectors == 0)
-        {
-            /* It's ok and can be used to show alert like "Please insert the
CD" */
-            TRACE("No media found.\n");
-            Flags |= ATA_DEVICE_NO_MEDIA;
-        }
-    }
-    else
+    return NULL;
+}
+
+BOOLEAN
+AtaInit(
+    _Out_ PUCHAR DetectedCount)
+{
+    ULONG ChannelNumber;
+
+    *DetectedCount = 0;
+
+    /* Enumerate IDE channels */
+    for (ChannelNumber = 0; ChannelNumber < CHANNEL_MAX_CHANNELS; ++ChannelNumber)
     {
-        if (Id.SupportLba || (Id.MajorRevision && Id.UserAddressableSectors))
-        {
-            if (Id.FeaturesSupport.Address48)
-            {
-                TRACE("Using LBA48 addressing mode.\n");
-                Flags |= ATA_DEVICE_LBA48 | ATA_DEVICE_LBA;
-                TotalSectors = Id.UserAddressableSectors48;
-            }
-            else
-            {
-                TRACE("Using LBA28 addressing mode.\n");
-                Flags |= ATA_DEVICE_LBA;
-                TotalSectors = Id.UserAddressableSectors;
-            }
+        UCHAR DeviceNumber;
+        IDE_REGISTERS Registers;
-            /* LBA ATA drives always have a sector size of 512 */
-            SectorSize = 512;
-        }
-        else
+        if (!AtapIdentifyChannel(ChannelNumber, &Registers))
+            continue;
+
+        /* Check for devices attached to the bus */
+        for (DeviceNumber = 0; DeviceNumber < CHANNEL_MAX_DEVICES; ++DeviceNumber)
         {
-            TRACE("Using CHS addressing mode.\n");
-            Flags |= ATA_DEVICE_CHS;
+            PHW_DEVICE_UNIT DeviceUnit;
+            ATA_DEVICE_CLASS DeviceClass;
-            if (Id.UnformattedBytesPerSector == 0)
-            {
-                SectorSize = 512;
-            }
-            else
+            /* Allocate a new device unit structure */
+            DeviceUnit = FrLdrTempAlloc(sizeof(*DeviceUnit), TAG_ATA_DEVICE);
+            if (!DeviceUnit)
             {
-                for (i = 1 << 15; i > 0; i >>= 1)
-                {
-                    if ((Id.UnformattedBytesPerSector & i) != 0)
-                    {
-                        SectorSize = i;
-                        break;
-                    }
-                }
+                ERR("Failed to allocate device unit!\n");
+                continue;
             }
-            TotalSectors = Id.NumberOfCylinders * Id.NumberOfHeads * Id.SectorsPerTrack;
-        }
-    }
-    TRACE("Sector size %d ; Total sectors %I64d\n", SectorSize, TotalSectors);
+            RtlZeroMemory(DeviceUnit, sizeof(*DeviceUnit));
-    (*DeviceUnit)->Flags = Flags;
-    (*DeviceUnit)->SectorSize = SectorSize;
-    (*DeviceUnit)->TotalSectors = TotalSectors;
-    if (Flags & ATA_DEVICE_ATAPI)
-    {
-        (*DeviceUnit)->Cylinders = 0xFFFFFFFF;
-        (*DeviceUnit)->Heads = 0xFFFFFFFF;
-        (*DeviceUnit)->Sectors = 0xFFFFFFFF;
-    }
-    else
-    {
-        (*DeviceUnit)->Cylinders = Id.NumberOfCylinders;
-        (*DeviceUnit)->Heads = Id.NumberOfHeads;
-        (*DeviceUnit)->Sectors = Id.SectorsPerTrack;
-    }
+            /* Perform a minimal initialization */
+            RtlCopyMemory(&DeviceUnit->Registers, &Registers,
sizeof(Registers));
+            DeviceUnit->DeviceNumber = DeviceNumber;
+            DeviceUnit->P.SectorSize = 512;
+            DeviceUnit->DeviceSelect = (DEV_SLAVE(DeviceNumber) << 4) |
IDE_DRIVE_SELECT;
-#if DBG
-    DbgDumpBuffer(DPRINT_DISK, &Id, IDENTIFY_DATA_SIZE);
-#endif
+            /* Let's see what kind of device this is */
+            DeviceClass = AtapIdentifyDevice(DeviceUnit);
+            if (DeviceClass == DEV_NONE)
+                goto NextDevice;
-    TRACE("IdentifyDevice() done.\n");
-    return TRUE;
+            TRACE("Found %lu device at %X:%u\n", DeviceClass, Registers.Data,
DeviceNumber);
-Failure:
-    TRACE("IdentifyDevice() done. No device present at %d:%d\n", Channel,
DeviceNumber);
-    return FALSE;
+            if (!AtapInitDevice(DeviceUnit, DeviceClass))
+                goto NextDevice;
+
+            TRACE("Total sectors %I64u of size %lu, CHS %lu:%lu:%lu, %lx\n",
+                  DeviceUnit->P.TotalSectors,
+                  DeviceUnit->P.SectorSize,
+                  DeviceUnit->P.Cylinders,
+                  DeviceUnit->P.Heads,
+                  DeviceUnit->P.SectorsPerTrack,
+                  DeviceUnit->P.Flags);
+
+            AtapUnits[(*DetectedCount)++] = DeviceUnit;
+            continue;
+
+NextDevice:
+            FrLdrTempFree(DeviceUnit, TAG_ATA_DEVICE);
+        }
+    }
+
+    return (*DetectedCount > 0);
 }
diff --git a/boot/freeldr/freeldr/arch/drivers/hwidep.h
b/boot/freeldr/freeldr/arch/drivers/hwidep.h
new file mode 100644
index 00000000000..748b58b2440
--- /dev/null
+++ b/boot/freeldr/freeldr/arch/drivers/hwidep.h
@@ -0,0 +1,387 @@
+/*
+ * PROJECT:     FreeLoader
+ * LICENSE:     MIT (
https://spdx.org/licenses/MIT)
+ * PURPOSE:     Private header for ATA/ATAPI programmed I/O driver.
+ * COPYRIGHT:   Copyright 2019-2025 Dmitry Borisov (di.sean(a)protonmail.com)
+ */
+
+#pragma once
+
+#define TAG_ATA_DEVICE 'dATA'
+
+#define ATA_STATUS_SUCCESS   0
+#define ATA_STATUS_PENDING   1
+#define ATA_STATUS_ERROR     2
+#define ATA_STATUS_RESET     3
+#define ATA_STATUS_RETRY     4
+
+#if defined(SARCH_PC98)
+/* Master/Slave devices for Bank 0 and Bank 1 */
+#define CHANNEL_MAX_DEVICES       4
+#define DEV_SLAVE(DeviceNumber)   ((DeviceNumber) & 1)
+#else
+/* Master/Slave devices */
+#define CHANNEL_MAX_DEVICES       2
+#define DEV_SLAVE(DeviceNumber)   (DeviceNumber)
+#endif
+
+#if defined(SARCH_XBOX)
+/* It's safe to enable the multiple mode */
+#define ATA_ENABLE_MULTIPLE_MODE
+#endif
+
+/* Delay of 400ns */
+#if defined(SARCH_PC98)
+#define ATA_IO_WAIT()    WRITE_PORT_UCHAR((PUCHAR)0x5F, 0)
+#else
+#define ATA_IO_WAIT()    StallExecutionProcessor(1)
+#endif
+
+#if defined(_M_IX86) || defined(_M_AMD64)
+/* x86 I/O address space spans from 0 to 0xFFFF */
+typedef USHORT IDE_REG;
+#else
+typedef ULONG_PTR IDE_REG;
+#endif
+
+#define ATA_MAX_LBA_28    0x0FFFFFFFULL
+#define ATA_MAX_LBA_48    (1ULL << 48)
+
+#define IDE_FEATURE_PIO         0x00
+
+#define IDE_DC_ALWAYS           0x08
+
+#define IDE_DRIVE_SELECT        0xA0
+
+#define ATAPI_INT_REASON_COD              0x01
+#define ATAPI_INT_REASON_IO               0x02
+#define ATAPI_INT_REASON_MASK             (ATAPI_INT_REASON_IO | ATAPI_INT_REASON_COD)
+
+#define ATAPI_INT_REASON_STATUS_NEC       0x00
+#define ATAPI_INT_REASON_STATUS           (ATAPI_INT_REASON_IO | ATAPI_INT_REASON_COD)
+#define ATAPI_INT_REASON_AWAIT_CDB        (IDE_STATUS_DRQ | ATAPI_INT_REASON_COD)
+#define ATAPI_INT_REASON_DATA_IN          (ATAPI_INT_REASON_IO | IDE_STATUS_DRQ)
+
+#define MAXIMUM_CDROM_SIZE      804 // == sizeof(CDROM_TOC)
+
+#define ATA_TIME_BUSY_SELECT    2000    ///< 20 ms
+#define ATA_TIME_BUSY_POLL      500000  ///< 5 s
+#define ATA_TIME_BUSY_ENUM      100     ///< 1 ms
+#define ATA_TIME_BUSY_RESET     1000000 ///< 10 s
+#define ATA_TIME_RESET_SELECT   200000  ///< 2 s
+#define ATA_TIME_DRQ_CLEAR      100     ///< 200 us
+#define ATA_TIME_PHASE_CHANGE   100     ///< 1 ms
+
+#define ATA_WRITE(Port, Value) \
+    WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)(Port), (Value))
+
+#define ATA_WRITE_BLOCK_16(Port, Buffer, Count) \
+    WRITE_PORT_BUFFER_USHORT((PUSHORT)(ULONG_PTR)(Port), (PUSHORT)(Buffer), (Count))
+
+#define ATA_WRITE_BLOCK_32(Port, Buffer, Count) \
+    WRITE_PORT_BUFFER_ULONG((PULONG)(ULONG_PTR)(Port), (PULONG)(Buffer), (Count))
+
+#define ATA_READ(Port) \
+    READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)(Port))
+
+#define ATA_READ_BLOCK_16(Port, Buffer, Count) \
+    READ_PORT_BUFFER_USHORT((PUSHORT)(ULONG_PTR)(Port), (PUSHORT)(Buffer), (Count))
+
+#define ATA_READ_BLOCK_32(Port, Buffer, Count) \
+    READ_PORT_BUFFER_ULONG((PULONG)(ULONG_PTR)(Port), (PULONG)(Buffer), (Count))
+
+typedef enum _ATA_DEVICE_CLASS
+{
+    DEV_ATA,
+    DEV_ATAPI,
+    DEV_NONE,
+} ATA_DEVICE_CLASS, *PATA_DEVICE_CLASS;
+
+typedef struct _IDE_REGISTERS
+{
+    IDE_REG Data;
+    union
+    {
+        IDE_REG Features;
+        IDE_REG Error;
+    };
+    union
+    {
+        IDE_REG SectorCount;
+        IDE_REG InterruptReason;
+    };
+    IDE_REG LbaLow;             ///< LBA bits 0-7, 24-31
+    union
+    {
+        IDE_REG LbaMid;         ///< LBA bits 8-15, 32-39
+        IDE_REG ByteCountLow;
+        IDE_REG SignatureLow;
+    };
+    union
+    {
+        IDE_REG LbaHigh;        ///< LBA bits 16-23, 40-47
+        IDE_REG ByteCountHigh;
+        IDE_REG SignatureHigh;
+    };
+    IDE_REG Device;
+    union
+    {
+        IDE_REG Command;
+        IDE_REG Status;
+    };
+    union
+    {
+        IDE_REG Control;
+        IDE_REG AlternateStatus;
+    };
+} IDE_REGISTERS, *PIDE_REGISTERS;
+
+typedef struct _ATA_TASKFILE
+{
+    UCHAR DriveSelect;
+    UCHAR Command;
+    struct
+    {
+        UCHAR Feature;
+        UCHAR SectorCount;
+        UCHAR LowLba;
+        UCHAR MidLba;
+        UCHAR HighLba;
+    } Data[2]; // 0 - low part, 1 - high part
+} ATA_TASKFILE, *PATA_TASKFILE;
+
+typedef struct _ATA_DEVICE_REQUEST
+{
+    union
+    {
+        UCHAR Cdb[16];
+        ATA_TASKFILE TaskFile;
+    };
+    PVOID DataBuffer;
+    ULONG Flags;
+#define REQUEST_FLAG_LBA48                  0x00000001
+#define REQUEST_FLAG_READ_WRITE_MULTIPLE    0x00000002
+#define REQUEST_FLAG_PACKET_COMMAND         0x00000004
+#define REQUEST_FLAG_SET_DEVICE_REGISTER    0x00000008
+#define REQUEST_FLAG_AWAIT_CDB              0x00000010
+#define REQUEST_FLAG_READ_COMMAND           0x00000020
+#define REQUEST_FLAG_IDENTIFY_COMMAND       0x00000040
+
+    ULONG DataTransferLength;
+} ATA_DEVICE_REQUEST, *PATA_DEVICE_REQUEST;
+
+typedef struct _HW_DEVICE_UNIT
+{
+    /* Public data, must be the first member */
+    DEVICE_UNIT P;
+
+    IDE_REGISTERS Registers;
+    ULONG BytesToTransfer;
+    PUCHAR DataBuffer;
+    ULONG DrqByteCount;
+    ULONG MaximumTransferLength;
+    UCHAR DeviceNumber;
+    UCHAR DeviceSelect;
+    UCHAR CdbSize;
+    UCHAR MultiSectorTransfer;
+    union
+    {
+        IDENTIFY_DEVICE_DATA IdentifyDeviceData;
+        IDENTIFY_PACKET_DATA IdentifyPacketData;
+    };
+} HW_DEVICE_UNIT, *PHW_DEVICE_UNIT;
+
+FORCEINLINE
+BOOLEAN
+AtaDevIsIdentifyDataValid(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    ULONG i;
+    UCHAR Crc;
+
+    /* Bits 0:8 of word 255 */
+    if (IdentifyData->Signature != 0xA5)
+    {
+        /* The integrity word is missing, assume the data provided by the device is valid
*/
+        return TRUE;
+    }
+
+    /* Verify the checksum */
+    Crc = 0;
+    for (i = 0; i < sizeof(*IdentifyData); ++i)
+    {
+        Crc += ((PUCHAR)IdentifyData)[i];
+    }
+
+    return (Crc == 0);
+}
+
+FORCEINLINE
+UCHAR
+AtaDevCdbSizeInWords(
+    _In_ PIDENTIFY_PACKET_DATA IdentifyPacketData)
+{
+    /* Bits 0:2 of word 0 */
+    return (IdentifyPacketData->GeneralConfiguration.PacketType != 0) ? 8 : 6;
+}
+
+FORCEINLINE
+BOOLEAN
+AtaDevHasLbaTranslation(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    /* Bit 9 of word 49 */
+    return IdentifyData->Capabilities.LbaSupported;
+}
+
+FORCEINLINE
+ULONG
+AtaDevUserAddressableSectors28Bit(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    /* Words 60-61 */
+    return IdentifyData->UserAddressableSectors;
+}
+
+FORCEINLINE
+ULONG64
+AtaDevUserAddressableSectors48Bit(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    /* Words 100-103 */
+    return ((ULONG64)IdentifyData->Max48BitLBA[1] << 32) |
IdentifyData->Max48BitLBA[0];
+}
+
+FORCEINLINE
+BOOLEAN
+AtaDevHas48BitAddressFeature(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    /* Word 83: 15 = 0, 14 = 1 */
+   if (IdentifyData->CommandSetSupport.WordValid83 == 1)
+   {
+        /* Bit 10 of word 83 */
+        return IdentifyData->CommandSetSupport.BigLba;
+   }
+
+   return FALSE;
+}
+
+FORCEINLINE
+BOOLEAN
+AtaDevIsCurrentGeometryValid(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    return ((IdentifyData->TranslationFieldsValid & 1) &&
+            (IdentifyData->NumberOfCurrentCylinders != 0) &&
+            (IdentifyData->NumberOfCurrentCylinders <= 63) &&
+            (IdentifyData->NumberOfCurrentHeads != 0) &&
+            (IdentifyData->NumberOfCurrentHeads <= 16) &&
+            (IdentifyData->CurrentSectorsPerTrack != 0));
+}
+
+FORCEINLINE
+VOID
+AtaDevDefaultChsTranslation(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData,
+    _Out_ PUSHORT Cylinders,
+    _Out_ PUSHORT Heads,
+    _Out_ PUSHORT SectorsPerTrack)
+{
+    /* Word 1 */
+    *Cylinders = IdentifyData->NumCylinders;
+
+    /* Word 3 */
+    *Heads = IdentifyData->NumHeads;
+
+    /* Word 6 */
+    *SectorsPerTrack = IdentifyData->NumSectorsPerTrack;
+}
+
+FORCEINLINE
+VOID
+AtaDevCurrentChsTranslation(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData,
+    _Out_ PUSHORT Cylinders,
+    _Out_ PUSHORT Heads,
+    _Out_ PUSHORT SectorsPerTrack)
+{
+    /* Word 54 */
+    *Cylinders = IdentifyData->NumberOfCurrentCylinders;
+
+    /* Word 55 */
+    *Heads = IdentifyData->NumberOfCurrentHeads;
+
+    /* Word 55 */
+    *SectorsPerTrack = IdentifyData->CurrentSectorsPerTrack;
+}
+
+FORCEINLINE
+UCHAR
+AtaDevCurrentSectorsPerDrq(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    UCHAR MultiSectorCurrent;
+
+    /* Bit 8 of word 59 */
+    if (!(IdentifyData->MultiSectorSettingValid))
+        return 0;
+
+    /* The word 59 should be a power of 2 */
+    MultiSectorCurrent = IdentifyData->CurrentMultiSectorSetting;
+
+    if ((MultiSectorCurrent > 0) && ((MultiSectorCurrent &
(MultiSectorCurrent - 1)) == 0))
+        return MultiSectorCurrent;
+
+    return 0;
+}
+
+FORCEINLINE
+UCHAR
+AtaDevMaximumSectorsPerDrq(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    UCHAR MultiSectorMax;
+
+    /* The word 47 should be a power of 2 */
+    MultiSectorMax = IdentifyData->MaximumBlockTransfer;
+
+    if ((MultiSectorMax > 0) && ((MultiSectorMax & (MultiSectorMax - 1))
== 0))
+        return MultiSectorMax;
+
+    return 0;
+}
+
+FORCEINLINE
+ULONG
+AtaDevBytesPerLogicalSector(
+    _In_ PIDENTIFY_DEVICE_DATA IdentifyData)
+{
+    ULONG WordCount;
+
+    /* Word 106: 15 = 0, 14 = 1, 12 = 1 */
+    if (IdentifyData->PhysicalLogicalSectorSize.Reserved1 == 1 &&
+        IdentifyData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words)
+    {
+        /* Words 116-117 */
+        WordCount = IdentifyData->WordsPerLogicalSector[0];
+        WordCount |= (ULONG)IdentifyData->WordsPerLogicalSector[1] << 16;
+    }
+    else
+    {
+        /* 256 words = 512 bytes */
+        WordCount = 256;
+    }
+
+    return WordCount * sizeof(USHORT);
+}
+
+FORCEINLINE
+BOOLEAN
+AtaCommandUseLba48(
+    _In_ ULONG64 SectorNumber,
+    _In_ ULONG SectorCount)
+{
+    /* Use the 48-bit command when reasonable */
+    return (((SectorNumber + SectorCount) >= ATA_MAX_LBA_28) || (SectorCount >
0x100));
+}
diff --git a/boot/freeldr/freeldr/arch/i386/pc98/machpc98.c
b/boot/freeldr/freeldr/arch/i386/pc98/machpc98.c
index 2ba4707de7a..7fd9e292b55 100644
--- a/boot/freeldr/freeldr/arch/i386/pc98/machpc98.c
+++ b/boot/freeldr/freeldr/arch/i386/pc98/machpc98.c
@@ -34,7 +34,6 @@ Pc98HwIdle(VOID)
 VOID
 Pc98PrepareForReactOS(VOID)
 {
-    Pc98DiskPrepareForReactOS();
     Pc98VideoPrepareForReactOS();
     DiskStopFloppyMotor();
     DebugDisableScreenPort();
diff --git a/boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
b/boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
index e6f98d136f7..0f9fdf1eb27 100644
--- a/boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
+++ b/boot/freeldr/freeldr/arch/i386/pc98/pc98disk.c
@@ -132,11 +132,6 @@ BOOLEAN DiskResetController(IN PPC98_DISK_DRIVE DiskDrive)
     return INT386_SUCCESS(Regs);
 }
-VOID Pc98DiskPrepareForReactOS(VOID)
-{
-    AtaFree();
-}
-
 PPC98_DISK_DRIVE
 Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber)
 {
@@ -187,7 +182,7 @@ Pc98DiskReadLogicalSectorsLBA(
     if (DiskDrive->Type & DRIVE_IDE && DiskDrive->Type &
DRIVE_CDROM)
     {
-        return AtaAtapiReadLogicalSectorsLBA(AtaGetDevice(DiskDrive->IdeUnitNumber),
SectorNumber, SectorCount, Buffer);
+        return AtaReadLogicalSectors(AtaGetDevice(DiskDrive->IdeUnitNumber),
SectorNumber, SectorCount, Buffer);
     }
     else
     {
@@ -503,7 +498,7 @@ InitIdeDrive(
     {
         DiskDrive->Geometry.Cylinders = DeviceUnit->Cylinders;
         DiskDrive->Geometry.Heads = DeviceUnit->Heads;
-        DiskDrive->Geometry.SectorsPerTrack = DeviceUnit->Sectors;
+        DiskDrive->Geometry.SectorsPerTrack = DeviceUnit->SectorsPerTrack;
         DiskDrive->Geometry.BytesPerSector = DeviceUnit->SectorSize;
         DiskDrive->Geometry.Sectors = DeviceUnit->TotalSectors;
diff --git a/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c
b/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c
index 6c0b094f49b..ab3f8020041 100644
--- a/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c
+++ b/boot/freeldr/freeldr/arch/i386/xbox/machxbox.c
@@ -374,7 +374,6 @@ XboxPrepareForReactOS(VOID)
 {
     /* On Xbox, prepare video and disk support */
     XboxVideoPrepareForReactOS();
-    XboxDiskInit(FALSE);
     DiskStopFloppyMotor();
     /* Turn off debug messages to screen */
diff --git a/boot/freeldr/freeldr/arch/i386/xbox/xboxdisk.c
b/boot/freeldr/freeldr/arch/i386/xbox/xboxdisk.c
index 4afdc99c398..6d6fee8ce40 100644
--- a/boot/freeldr/freeldr/arch/i386/xbox/xboxdisk.c
+++ b/boot/freeldr/freeldr/arch/i386/xbox/xboxdisk.c
@@ -3,7 +3,7 @@
  * LICENSE:     GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
  * PURPOSE:     Xbox specific disk access routines
  * COPYRIGHT:   Copyright 2004 Gé van Geldorp (gvg(a)reactos.com)
- *              Copyright 2019 Dmitry Borisov (di.sean(a)protonmail.com)
+ *              Copyright 2019-2025 Dmitry Borisov (di.sean(a)protonmail.com)
  */
 /* INCLUDES *******************************************************************/
@@ -22,39 +22,36 @@ static BOOLEAN AtaInitialized = FALSE;
 /* FUNCTIONS ******************************************************************/
+static
 VOID
-XboxDiskInit(BOOLEAN Init)
+XboxDiskInit(VOID)
 {
     UCHAR DetectedCount;
     UCHAR UnitNumber;
     PDEVICE_UNIT DeviceUnit = NULL;
-    if (Init & !AtaInitialized)
+    ASSERT(!AtaInitialized);
+
+    AtaInitialized = TRUE;
+
+    /* Find first HDD and CD */
+    AtaInit(&DetectedCount);
+    for (UnitNumber = 0; UnitNumber <= DetectedCount; UnitNumber++)
     {
-        /* Find first HDD and CD */
-        AtaInit(&DetectedCount);
-        for (UnitNumber = 0; UnitNumber <= DetectedCount; UnitNumber++)
+        DeviceUnit = AtaGetDevice(UnitNumber);
+        if (DeviceUnit)
         {
-            DeviceUnit = AtaGetDevice(UnitNumber);
-            if (DeviceUnit)
+            if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
+            {
+                if (!CdDrive)
+                    CdDrive = DeviceUnit;
+            }
+            else
             {
-                if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
-                {
-                    if (!CdDrive)
-                        CdDrive = DeviceUnit;
-                }
-                else
-                {
-                    if (!HardDrive)
-                        HardDrive = DeviceUnit;
-                }
+                if (!HardDrive)
+                    HardDrive = DeviceUnit;
             }
         }
-        AtaInitialized = TRUE;
-    }
-    else
-    {
-        AtaFree();
     }
 }
@@ -67,7 +64,7 @@ XboxDiskDriveNumberToDeviceUnit(UCHAR DriveNumber)
         return NULL;
     if (!AtaInitialized)
-        XboxDiskInit(TRUE);
+        XboxDiskInit();
     /* HDD */
     if ((DriveNumber == 0x80) && HardDrive)
@@ -96,7 +93,7 @@ XboxDiskReadLogicalSectors(
     if (!DeviceUnit)
         return FALSE;
-    return AtaAtapiReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer);
+    return AtaReadLogicalSectors(DeviceUnit, SectorNumber, SectorCount, Buffer);
 }
 BOOLEAN
@@ -112,7 +109,7 @@ XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
     Geometry->Cylinders = DeviceUnit->Cylinders;
     Geometry->Heads = DeviceUnit->Heads;
-    Geometry->SectorsPerTrack = DeviceUnit->Sectors;
+    Geometry->SectorsPerTrack = DeviceUnit->SectorsPerTrack;
     Geometry->BytesPerSector = DeviceUnit->SectorSize;
     Geometry->Sectors = DeviceUnit->TotalSectors;
@@ -135,7 +132,7 @@ XboxDiskGetCacheableBlockCount(UCHAR DriveNumber)
     if (DeviceUnit->Flags & ATA_DEVICE_LBA)
         return 64;
     else
-        return DeviceUnit->Sectors;
+        return DeviceUnit->SectorsPerTrack;
 }
 /* EOF */
diff --git a/boot/freeldr/freeldr/include/arch/i386/machpc98.h
b/boot/freeldr/freeldr/include/arch/i386/machpc98.h
index 23e268e9d98..737d5d84ced 100644
--- a/boot/freeldr/freeldr/include/arch/i386/machpc98.h
+++ b/boot/freeldr/freeldr/include/arch/i386/machpc98.h
@@ -151,7 +151,6 @@ UCHAR Pc98GetFloppyCount(VOID);
 PPC98_DISK_DRIVE Pc98DiskDriveNumberToDrive(IN UCHAR DriveNumber);
 ULONG Pc98GetBootSectorLoadAddress(IN UCHAR DriveNumber);
-VOID Pc98DiskPrepareForReactOS(VOID);
 /* hwdisk.c */
 BOOLEAN PcInitializeBootDevices(VOID);
diff --git a/boot/freeldr/freeldr/include/arch/i386/machxbox.h
b/boot/freeldr/freeldr/include/arch/i386/machxbox.h
index 4d3a4510263..9591729784d 100644
--- a/boot/freeldr/freeldr/include/arch/i386/machxbox.h
+++ b/boot/freeldr/freeldr/include/arch/i386/machxbox.h
@@ -51,7 +51,6 @@ VOID XboxPrepareForReactOS(VOID);
 VOID XboxMemInit(VOID);
 PFREELDR_MEMORY_DESCRIPTOR XboxMemGetMemoryMap(ULONG *MemoryMapSize);
-VOID XboxDiskInit(BOOLEAN Init);
 BOOLEAN XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG
SectorCount, PVOID Buffer);
 BOOLEAN XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY DriveGeometry);
 ULONG XboxDiskGetCacheableBlockCount(UCHAR DriveNumber);
diff --git a/boot/freeldr/freeldr/include/hwide.h b/boot/freeldr/freeldr/include/hwide.h
index 23f7fd94ad0..60b2cce415c 100644
--- a/boot/freeldr/freeldr/include/hwide.h
+++ b/boot/freeldr/freeldr/include/hwide.h
@@ -1,331 +1,52 @@
 /*
  * PROJECT:     FreeLoader
- * LICENSE:     GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * LICENSE:     MIT (
https://spdx.org/licenses/MIT)
  * PURPOSE:     ATA/ATAPI programmed I/O driver header file.
- * COPYRIGHT:   Copyright 2019-2020 Dmitry Borisov (di.sean(a)protonmail.com)
+ * COPYRIGHT:   Copyright 2019-2025 Dmitry Borisov (di.sean(a)protonmail.com)
  */
-/* GLOBALS ********************************************************************/
+#pragma once
-/* Some definitions were taken from UniATA driver by Alter */
-
-/*
- * IDE registers offsets
- */
-#if defined(SARCH_PC98)
-#define IDX_IO1_i_Data          0x00
-#define IDX_IO1_i_Error         0x02
-#define IDX_IO1_i_BlockCount    0x04
-#define IDX_IO1_i_BlockNumber   0x06
-#define IDX_IO1_i_CylinderLow   0x08
-#define IDX_IO1_i_CylinderHigh  0x0A
-#define IDX_IO1_i_DriveSelect   0x0C
-#define IDX_IO1_i_Status        0x0E
-
-#define IDX_IO2_i_AltStatus     0x10C
-#define IDX_IO2_i_DriveAddress  0x10E
-#define IDE_IO_i_Bank           0x432
-
-#define IDX_IO1_o_Data          0x00
-#define IDX_IO1_o_Feature       0x02
-#define IDX_IO1_o_BlockCount    0x04
-#define IDX_IO1_o_BlockNumber   0x06
-#define IDX_IO1_o_CylinderLow   0x08
-#define IDX_IO1_o_CylinderHigh  0x0A
-#define IDX_IO1_o_DriveSelect   0x0C
-#define IDX_IO1_o_Command       0x0E
-
-#define IDX_IO2_o_Control       0x10C
-#define IDE_IO_o_BankSelect     0x432
-#else /* SARCH_PC98 */
-#define IDX_IO1_i_Data          0x00
-#define IDX_IO1_i_Error         0x01
-#define IDX_IO1_i_BlockCount    0x02
-#define IDX_IO1_i_BlockNumber   0x03
-#define IDX_IO1_i_CylinderLow   0x04
-#define IDX_IO1_i_CylinderHigh  0x05
-#define IDX_IO1_i_DriveSelect   0x06
-#define IDX_IO1_i_Status        0x07
-
-#define IDX_IO2_i_AltStatus     0x206
-#define IDX_IO2_i_DriveAddress  0x207
-
-#define IDX_IO1_o_Data          0x00
-#define IDX_IO1_o_Feature       0x01
-#define IDX_IO1_o_BlockCount    0x02
-#define IDX_IO1_o_BlockNumber   0x03
-#define IDX_IO1_o_CylinderLow   0x04
-#define IDX_IO1_o_CylinderHigh  0x05
-#define IDX_IO1_o_DriveSelect   0x06
-#define IDX_IO1_o_Command       0x07
-
-#define IDX_IO2_o_Control       0x206
-#endif
-
-/*
- * ATAPI registers offsets
- */
-#if defined(SARCH_PC98)
-#define IDX_ATAPI_IO1_i_Data              0x00
-#define IDX_ATAPI_IO1_i_Error             0x02
-#define IDX_ATAPI_IO1_i_InterruptReason   0x04
-#define IDX_ATAPI_IO1_i_Unused1           0x06
-#define IDX_ATAPI_IO1_i_ByteCountLow      0x08
-#define IDX_ATAPI_IO1_i_ByteCountHigh     0x0A
-#define IDX_ATAPI_IO1_i_DriveSelect       0x0C
-#define IDX_ATAPI_IO1_i_Status            0x0E
-
-#define IDX_ATAPI_IO1_o_Data              0x00
-#define IDX_ATAPI_IO1_o_Feature           0x02
-#define IDX_ATAPI_IO1_o_Unused0           0x04
-#define IDX_ATAPI_IO1_o_Unused1           0x06
-#define IDX_ATAPI_IO1_o_ByteCountLow      0x08
-#define IDX_ATAPI_IO1_o_ByteCountHigh     0x0A
-#define IDX_ATAPI_IO1_o_DriveSelect       0x0C
-#define IDX_ATAPI_IO1_o_Command           0x0E
-#else /* SARCH_PC98 */
-#define IDX_ATAPI_IO1_i_Data              0x00
-#define IDX_ATAPI_IO1_i_Error             0x01
-#define IDX_ATAPI_IO1_i_InterruptReason   0x02
-#define IDX_ATAPI_IO1_i_Unused1           0x03
-#define IDX_ATAPI_IO1_i_ByteCountLow      0x04
-#define IDX_ATAPI_IO1_i_ByteCountHigh     0x05
-#define IDX_ATAPI_IO1_i_DriveSelect       0x06
-#define IDX_ATAPI_IO1_i_Status            0x07
-
-#define IDX_ATAPI_IO1_o_Data              0x00
-#define IDX_ATAPI_IO1_o_Feature           0x01
-#define IDX_ATAPI_IO1_o_Unused0           0x02
-#define IDX_ATAPI_IO1_o_Unused1           0x03
-#define IDX_ATAPI_IO1_o_ByteCountLow      0x04
-#define IDX_ATAPI_IO1_o_ByteCountHigh     0x05
-#define IDX_ATAPI_IO1_o_DriveSelect       0x06
-#define IDX_ATAPI_IO1_o_Command           0x07
-#endif
-
-/*
- * IDE status definitions
- */
-#define IDE_STATUS_SUCCESS           0x00
-#define IDE_STATUS_ERROR             0x01
-#define IDE_STATUS_INDEX             0x02
-#define IDE_STATUS_CORRECTED_ERROR   0x04
-#define IDE_STATUS_DRQ               0x08
-#define IDE_STATUS_DSC               0x10
-#define IDE_STATUS_DMA               0x20      /* DMA ready */
-#define IDE_STATUS_DWF               0x20      /* drive write fault */
-#define IDE_STATUS_DRDY              0x40
-#define IDE_STATUS_IDLE              0x50
-#define IDE_STATUS_BUSY              0x80
-
-#define IDE_STATUS_WRONG             0xff
-#define IDE_STATUS_MASK              0xff
-
-/*
- * IDE drive select/head definitions
- */
-#define IDE_DRIVE_SELECT             0xA0
-#define IDE_DRIVE_1                  0x00
-#define IDE_DRIVE_2                  0x10
-#define IDE_DRIVE_SELECT_1           (IDE_DRIVE_SELECT | IDE_DRIVE_1)
-#define IDE_DRIVE_SELECT_2           (IDE_DRIVE_SELECT | IDE_DRIVE_2)
-#define IDE_DRIVE_MASK               (IDE_DRIVE_SELECT_1 | IDE_DRIVE_SELECT_2)
-#define IDE_USE_LBA                  0x40
-
-/*
- * IDE drive control definitions
- */
-#define IDE_DC_DISABLE_INTERRUPTS    0x02
-#define IDE_DC_RESET_CONTROLLER      0x04
-#define IDE_DC_A_4BIT                0x80
-#define IDE_DC_USE_HOB               0x80 // use high-order byte(s)
-#define IDE_DC_REENABLE_CONTROLLER   0x00
+/** @brief Data structure for the ATA device. */
+typedef struct _DEVICE_UNIT
+{
+    /** Number of cylinders on the device */
+    ULONG Cylinders;
-/*
- * IDE error definitions
- */
-#define IDE_ERROR_ICRC               0x80
-#define IDE_ERROR_BAD_BLOCK          0x80
-#define IDE_ERROR_DATA_ERROR         0x40
-#define IDE_ERROR_MEDIA_CHANGE       0x20
-#define IDE_ERROR_ID_NOT_FOUND       0x10
-#define IDE_ERROR_MEDIA_CHANGE_REQ   0x08
-#define IDE_ERROR_COMMAND_ABORTED    0x04
-#define IDE_ERROR_END_OF_MEDIA       0x02
-#define IDE_ERROR_NO_MEDIA           0x02
-#define IDE_ERROR_ILLEGAL_LENGTH     0x01
+    /** Number of heads on the device */
+    ULONG Heads;
-/*
- * Values for TransferMode
- */
-#define ATA_PIO                      0x00
+    /** Number of sectors per track */
+    ULONG SectorsPerTrack;
-/*
- * IDENTIFY data
- */
-#include <pshpack1.h>
-typedef struct _IDENTIFY_DATA
-{
-    UCHAR  AtapiCmdSize:2;                  // 00 00 General configuration
-    UCHAR  Unused1:3;
-    UCHAR  DrqType:2;
-    UCHAR  Removable:1;
-    UCHAR  DeviceType:5;
-    UCHAR  Unused2:1;
-    UCHAR  CmdProtocol:2;
-    USHORT NumberOfCylinders;               // 02  1
-    USHORT Reserved1;                       // 04  2
-    USHORT NumberOfHeads;                   // 06  3
-    USHORT UnformattedBytesPerTrack;        // 08  4
-    USHORT UnformattedBytesPerSector;       // 0A  5
-    USHORT SectorsPerTrack;                 // 0C  6
-    USHORT VendorUnique1[3];                // 0E  7-9
-    USHORT SerialNumber[10];                // 14  10-19
-    USHORT BufferType;                      // 28  20
-    USHORT BufferSectorSize;                // 2A  21
-    USHORT NumberOfEccBytes;                // 2C  22
-    USHORT FirmwareRevision[4];             // 2E  23-26
-    USHORT ModelNumber[20];                 // 36  27-46
-    UCHAR  ReadWriteMultipleSupport;        // 5E  47
-    UCHAR  VendorUnique2;                   // 5F
-    USHORT DoubleWordIo;                    // 60  48
-    USHORT Reserved62_0:8;                  // 62  49 Capabilities
-    USHORT SupportDma:1;
-    USHORT SupportLba:1;
-    USHORT DisableIordy:1;
-    USHORT SupportIordy:1;
-    USHORT SoftReset:1;
-    USHORT StandbyOverlap:1;
-    USHORT SupportQTag:1;
-    USHORT SupportIDma:1;
-    USHORT Reserved2;                       // 64  50
-    UCHAR  VendorUnique3;                   // 66  51
-    UCHAR  PioCycleTimingMode;              // 67
-    UCHAR  VendorUnique4;                   // 68  52
-    UCHAR  DmaCycleTimingMode;              // 69
-    USHORT TranslationFieldsValid:1;        // 6A  53
-    USHORT Reserved3:15;
-    USHORT NumberOfCurrentCylinders;        // 6C  54
-    USHORT NumberOfCurrentHeads;            // 6E  55
-    USHORT CurrentSectorsPerTrack;          // 70  56
-    ULONG  CurrentSectorCapacity;           // 72  57-58
-    USHORT CurrentMultiSectorSetting;       //     59
-    ULONG  UserAddressableSectors;          //     60-61
-    USHORT SingleWordDMASupport:8;          //     62
-    USHORT SingleWordDMAActive:8;
-    USHORT MultiWordDMASupport:8;           //     63
-    USHORT MultiWordDMAActive:8;
-    USHORT AdvancedPIOModes:8;              //     64
-    USHORT Reserved4:8;
-    USHORT MinimumMWXferCycleTime;          //     65
-    USHORT RecommendedMWXferCycleTime;      //     66
-    USHORT MinimumPIOCycleTime;             //     67
-    USHORT MinimumPIOCycleTimeIORDY;        //     68
-    USHORT Reserved5[2];                    //     69-70
-    USHORT ReleaseTimeOverlapped;           //     71
-    USHORT ReleaseTimeServiceCommand;       //     72
-    USHORT Reserved73_74[2];                //     73-74
-    USHORT QueueLength:5;                   //     75
-    USHORT Reserved75_6:11;
-    USHORT SataCapabilities;                //     76
-    USHORT Reserved77;                      //     77
-    USHORT SataSupport;                     //     78
-    USHORT SataEnable;                      //     79
-    USHORT MajorRevision;                   //     80
-    USHORT MinorRevision;                   //     81
-    struct {
-        USHORT Smart:1;                     //     82
-        USHORT Security:1;
-        USHORT Removable:1;
-        USHORT PowerMngt:1;
-        USHORT Packet:1;
-        USHORT WriteCache:1;
-        USHORT LookAhead:1;
-        USHORT ReleaseDRQ:1;
-        USHORT ServiceDRQ:1;
-        USHORT Reset:1;
-        USHORT Protected:1;
-        USHORT Reserved_82_11:1;
-        USHORT WriteBuffer:1;
-        USHORT ReadBuffer:1;
-        USHORT Nop:1;
-        USHORT Reserved_82_15:1;
-        USHORT Microcode:1;                 //     83/86
-        USHORT Queued:1;
-        USHORT CFA:1;
-        USHORT APM:1;
-        USHORT Notify:1;
-        USHORT Standby:1;
-        USHORT Spinup:1;
-        USHORT Reserver_83_7:1;
-        USHORT MaxSecurity:1;
-        USHORT AutoAcoustic:1;
-        USHORT Address48:1;
-        USHORT ConfigOverlay:1;
-        USHORT FlushCache:1;
-        USHORT FlushCache48:1;
-        USHORT SupportOne:1;
-        USHORT SupportZero:1;
-        USHORT SmartErrorLog:1;             //     84/87
-        USHORT SmartSelfTest:1;
-        USHORT MediaSerialNo:1;
-        USHORT MediaCardPass:1;
-        USHORT Streaming:1;
-        USHORT Logging:1;
-        USHORT Reserver_84_6:8;
-        USHORT ExtendedOne:1;
-        USHORT ExtendedZero:1;
-    } FeaturesSupport, FeaturesEnabled;
-    USHORT Reserved6[13];                   //     88-99
-    ULONGLONG UserAddressableSectors48;     //     100-103
-    USHORT Reserved7[151];                  //     104-255
-} IDENTIFY_DATA, *PIDENTIFY_DATA;
-#include <poppack.h>
-#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
+    /** Number of bytes per sector */
+    ULONG SectorSize;
-#define ATAPI_MAGIC_LSB         0x14
-#define ATAPI_MAGIC_MSB         0xEB
-#define MAXIMUM_CDROM_SIZE      804
+    /** Total number of device sectors/LBA blocks */
+    ULONG64 TotalSectors;
-typedef struct _DEVICE_UNIT
-{
-    UCHAR         Channel;
-    UCHAR         DeviceNumber;
-    ULONG         Cylinders;
-    ULONG         Heads;
-    ULONG         Sectors;
-    ULONG         SectorSize;
-    ULONGLONG     TotalSectors; /* This number starts from 0 */
-    USHORT        Flags;
-    IDENTIFY_DATA IdentifyData;
+    /** Device-specific flags */
+    ULONG Flags;
+#define ATA_DEVICE_ATAPI                         0x00000001
+#define ATA_DEVICE_LBA                           0x00000002
+#define ATA_DEVICE_LBA48                         0x00000004
+#define ATA_DEVICE_IS_NEC_CDR260                 0x00000008
+#define ATA_DEVICE_FLAG_IO32                     0x00000010
 } DEVICE_UNIT, *PDEVICE_UNIT;
-#define ATA_DEVICE_ATAPI        (1 << 0)
-#define ATA_DEVICE_NO_MEDIA     (1 << 1)
-#define ATA_DEVICE_NOT_READY    (1 << 2)
-#define ATA_DEVICE_LBA48        (1 << 3)
-#define ATA_DEVICE_LBA          (1 << 4)
-#define ATA_DEVICE_CHS          (1 << 5)
-
-/* PROTOTYPES ****************************************************************/
+/* FUNCTIONS ******************************************************************/
 BOOLEAN
 AtaInit(
-    OUT PUCHAR DetectedCount
-);
-
-VOID
-AtaFree();
+    _Out_ PUCHAR DetectedCount);
 PDEVICE_UNIT
 AtaGetDevice(
-    IN UCHAR UnitNumber
-);
+    _In_ UCHAR UnitNumber);
 BOOLEAN
-AtaAtapiReadLogicalSectorsLBA(
-    IN OUT PDEVICE_UNIT DeviceUnit,
-    IN ULONGLONG SectorNumber,
-    IN ULONG SectorCount,
-    OUT PVOID Buffer
-);
+AtaReadLogicalSectors(
+    _In_ PDEVICE_UNIT DeviceUnit,
+    _In_ ULONG64 SectorNumber,
+    _In_ ULONG SectorCount,
+    _Out_writes_bytes_all_(SectorCount * DeviceUnit->SectorSize) PVOID Buffer);
diff --git a/sdk/include/ddk/ata.h b/sdk/include/ddk/ata.h
index a0c59a69837..d5b749f0c13 100644
--- a/sdk/include/ddk/ata.h
+++ b/sdk/include/ddk/ata.h
@@ -14,7 +14,7 @@ typedef struct _IDENTIFY_DEVICE_DATA {
     USHORT DeviceType  :1;
   } GeneralConfiguration;
   USHORT NumCylinders;
-  USHORT ReservedWord2;
+  USHORT SpecificConfiguration;
   USHORT NumHeads;
   USHORT Retired1[2];
   USHORT NumSectorsPerTrack;
@@ -26,9 +26,13 @@ typedef struct _IDENTIFY_DEVICE_DATA {
   UCHAR  ModelNumber[40];
   UCHAR  MaximumBlockTransfer;
   UCHAR  VendorUnique2;
-  USHORT ReservedWord48;
   struct {
-    UCHAR  ReservedByte49;
+    USHORT FeatureSupported  :1;
+    USHORT Reserved  :15;
+  } TrustedComputing;
+  struct {
+    UCHAR  CurrentLongPhysicalSectorAlignment  :2;
+    UCHAR  ReservedByte49  :6;
     UCHAR  DmaSupported  :1;
     UCHAR  LbaSupported  :1;
     UCHAR  IordyDisable  :1;
@@ -40,14 +44,19 @@ typedef struct _IDENTIFY_DEVICE_DATA {
   } Capabilities;
   USHORT ObsoleteWords51[2];
   USHORT TranslationFieldsValid  :3;
-  USHORT Reserved3  :13;
+  USHORT Reserved3  :5;
+  USHORT FreeFallControlSensitivity  :8;
   USHORT NumberOfCurrentCylinders;
   USHORT NumberOfCurrentHeads;
   USHORT CurrentSectorsPerTrack;
   ULONG  CurrentSectorCapacity;
   UCHAR  CurrentMultiSectorSetting;
   UCHAR  MultiSectorSettingValid  :1;
-  UCHAR  ReservedByte59  :7;
+  UCHAR  ReservedByte59  :3;
+  UCHAR  SanitizeFeatureSupported  :1;
+  UCHAR  CryptoScrambleExtCommandSupported  :1;
+  UCHAR  OverwriteExtCommandSupported  :1;
+  UCHAR  BlockEraseExtCommandSupported  :1;
   ULONG  UserAddressableSectors;
   USHORT ObsoleteWord62;
   USHORT MultiWordDMASupport  :8;
@@ -58,10 +67,74 @@ typedef struct _IDENTIFY_DEVICE_DATA {
   USHORT RecommendedMWXferCycleTime;
   USHORT MinimumPIOCycleTime;
   USHORT MinimumPIOCycleTimeIORDY;
-  USHORT ReservedWords69[6];
+  struct {
+    USHORT ZonedCapabilities  :2;
+    USHORT NonVolatileWriteCache  :1;
+    USHORT ExtendedUserAddressableSectorsSupported  :1;
+    USHORT DeviceEncryptsAllUserData  :1;
+    USHORT ReadZeroAfterTrimSupported  :1;
+    USHORT Optional28BitCommandsSupported  :1;
+    USHORT IEEE1667  :1;
+    USHORT DownloadMicrocodeDmaSupported  :1;
+    USHORT SetMaxSetPasswordUnlockDmaSupported  :1;
+    USHORT WriteBufferDmaSupported  :1;
+    USHORT ReadBufferDmaSupported  :1;
+    USHORT DeviceConfigIdentifySetDmaSupported  :1;
+    USHORT LPSAERCSupported  :1;
+    USHORT DeterministicReadAfterTrimSupported  :1;
+    USHORT CFastSpecSupported  :1;
+  } AdditionalSupported;
+  USHORT ReservedWords70[5];
   USHORT QueueDepth  :5;
   USHORT ReservedWord75  :11;
-  USHORT ReservedWords76[4];
+  struct {
+    USHORT Reserved0  :1;
+    USHORT SataGen1  :1;
+    USHORT SataGen2  :1;
+    USHORT SataGen3  :1;
+    USHORT Reserved1  :4;
+    USHORT NCQ  :1;
+    USHORT HIPM  :1;
+    USHORT PhyEvents  :1;
+    USHORT NcqUnload  :1;
+    USHORT NcqPriority  :1;
+    USHORT HostAutoPS  :1;
+    USHORT DeviceAutoPS  :1;
+    USHORT ReadLogDMA  :1;
+    USHORT Reserved2  :1;
+    USHORT CurrentSpeed  :3;
+    USHORT NcqStreaming  :1;
+    USHORT NcqQueueMgmt  :1;
+    USHORT NcqReceiveSend  :1;
+    USHORT DEVSLPtoReducedPwrState  :1;
+    USHORT Reserved3  :8;
+  } SerialAtaCapabilities;
+  struct {
+    USHORT Reserved0  :1;
+    USHORT NonZeroOffsets  :1;
+    USHORT DmaSetupAutoActivate  :1;
+    USHORT DIPM  :1;
+    USHORT InOrderData  :1;
+    USHORT HardwareFeatureControl  :1;
+    USHORT SoftwareSettingsPreservation  :1;
+    USHORT NCQAutosense  :1;
+    USHORT DEVSLP  :1;
+    USHORT HybridInformation  :1;
+    USHORT Reserved1  :6;
+  } SerialAtaFeaturesSupported;
+  struct {
+    USHORT Reserved0  :1;
+    USHORT NonZeroOffsets  :1;
+    USHORT DmaSetupAutoActivate  :1;
+    USHORT DIPM  :1;
+    USHORT InOrderData  :1;
+    USHORT HardwareFeatureControl  :1;
+    USHORT SoftwareSettingsPreservation  :1;
+    USHORT DeviceAutoPS  :1;
+    USHORT DEVSLP  :1;
+    USHORT HybridInformation  :1;
+    USHORT Reserved1  :6;
+  } SerialAtaFeaturesEnabled;
   USHORT MajorRevision;
   USHORT MinorRevision;
   struct {
@@ -95,7 +168,7 @@ typedef struct _IDENTIFY_DEVICE_DATA {
     USHORT DeviceConfigOverlay  :1;
     USHORT FlushCache  :1;
     USHORT FlushCacheExt  :1;
-    USHORT Resrved3  :2;
+    USHORT WordValid83  :2;
     USHORT SmartErrorLog  :1;
     USHORT SmartSelfTest  :1;
     USHORT MediaSerialNumber  :1;
@@ -109,7 +182,7 @@ typedef struct _IDENTIFY_DEVICE_DATA {
     USHORT URGWriteStream  :1;
     USHORT ReservedForTechReport  :2;
     USHORT IdleWithUnloadFeature  :1;
-    USHORT Reserved4  :2;
+    USHORT WordValid  :2;
   } CommandSetSupport;
   struct {
     USHORT SmartCommands  :1;
@@ -142,7 +215,8 @@ typedef struct _IDENTIFY_DEVICE_DATA {
     USHORT DeviceConfigOverlay  :1;
     USHORT FlushCache  :1;
     USHORT FlushCacheExt  :1;
-    USHORT Resrved3  :2;
+    USHORT Resrved3  :1;
+    USHORT Words119_120Valid  :1;
     USHORT SmartErrorLog  :1;
     USHORT SmartSelfTest  :1;
     USHORT MediaSerialNumber  :1;
@@ -160,14 +234,27 @@ typedef struct _IDENTIFY_DEVICE_DATA {
   } CommandSetActive;
   USHORT UltraDMASupport  :8;
   USHORT UltraDMAActive  :8;
-  USHORT ReservedWord89[4];
+  struct {
+    USHORT TimeRequired  :15;
+    USHORT ExtendedTimeReported  :1;
+  } NormalSecurityEraseUnit;
+  struct {
+    USHORT TimeRequired  :15;
+    USHORT ExtendedTimeReported  :1;
+  } EnhancedSecurityEraseUnit;
+  USHORT CurrentAPMLevel  :8;
+  USHORT ReservedWord91  :8;
+  USHORT MasterPasswordID;
   USHORT HardwareResetResult;
   USHORT CurrentAcousticValue  :8;
   USHORT RecommendedAcousticValue  :8;
-  USHORT ReservedWord95[5];
+  USHORT StreamMinRequestSize;
+  USHORT StreamingTransferTimeDMA;
+  USHORT StreamingAccessLatencyDMAPIO;
+  ULONG  StreamingPerfGranularity;
   ULONG  Max48BitLBA[2];
   USHORT StreamingTransferTime;
-  USHORT ReservedWord105;
+  USHORT DsmCap;
   struct {
     USHORT LogicalSectorsPerPhysicalSector  :4;
     USHORT Reserved0  :8;
@@ -182,19 +269,31 @@ typedef struct _IDENTIFY_DEVICE_DATA {
   USHORT WordsPerLogicalSector[2];
   struct {
     USHORT ReservedForDrqTechnicalReport  :1;
-    USHORT WriteReadVerifySupported  :1;
-    USHORT Reserved01  :11;
-    USHORT Reserved1  :2;
+    USHORT WriteReadVerify  :1;
+    USHORT WriteUncorrectableExt  :1;
+    USHORT ReadWriteLogDmaExt  :1;
+    USHORT DownloadMicrocodeMode3  :1;
+    USHORT FreefallControl  :1;
+    USHORT SenseDataReporting  :1;
+    USHORT ExtendedPowerConditions  :1;
+    USHORT Reserved0  :6;
+    USHORT WordValid  :2;
   } CommandSetSupportExt;
   struct {
     USHORT ReservedForDrqTechnicalReport  :1;
-    USHORT WriteReadVerifyEnabled  :1;
-    USHORT Reserved01  :11;
+    USHORT WriteReadVerify  :1;
+    USHORT WriteUncorrectableExt  :1;
+    USHORT ReadWriteLogDmaExt  :1;
+    USHORT DownloadMicrocodeMode3  :1;
+    USHORT FreefallControl  :1;
+    USHORT SenseDataReporting  :1;
+    USHORT ExtendedPowerConditions  :1;
+    USHORT Reserved0  :6;
     USHORT Reserved1  :2;
   } CommandSetActiveExt;
   USHORT ReservedForExpandedSupportandActive[6];
   USHORT MsnSupport  :2;
-  USHORT ReservedWord1274  :14;
+  USHORT ReservedWord127  :14;
   struct {
     USHORT SecuritySupported  :1;
     USHORT SecurityEnabled  :1;
@@ -208,20 +307,32 @@ typedef struct _IDENTIFY_DEVICE_DATA {
   } SecurityStatus;
   USHORT ReservedWord129[31];
   struct {
-    USHORT MaximumCurrentInMA2  :12;
+    USHORT MaximumCurrentInMA  :12;
     USHORT CfaPowerMode1Disabled  :1;
     USHORT CfaPowerMode1Required  :1;
     USHORT Reserved0  :1;
     USHORT Word160Supported  :1;
-  } CfaPowerModel;
-  USHORT ReservedForCfaWord161[8];
+  } CfaPowerMode1;
+  USHORT ReservedForCfaWord161[7];
+  USHORT NominalFormFactor  :4;
+  USHORT ReservedWord168  :12;
   struct {
     USHORT SupportsTrim  :1;
     USHORT Reserved0  :15;
   } DataSetManagementFeature;
-  USHORT ReservedForCfaWord170[6];
+  USHORT AdditionalProductID[4];
+  USHORT ReservedForCfaWord174[2];
   USHORT CurrentMediaSerialNumber[30];
-  USHORT ReservedWord206;
+  struct {
+    USHORT Supported  :1;
+    USHORT Reserved0  :1;
+    USHORT WriteSameSuported  :1;
+    USHORT ErrorRecoveryControlSupported  :1;
+    USHORT FeatureControlSuported  :1;
+    USHORT DataTablesSuported  :1;
+    USHORT Reserved1  :6;
+    USHORT VendorSpecific  :4;
+  } SCTCommandTransport;
   USHORT ReservedWord207[2];
   struct {
     USHORT AlignmentOfLogicalWithinPhysical  :14;
@@ -246,56 +357,367 @@ typedef struct _IDENTIFY_DEVICE_DATA {
     UCHAR NVCacheEstimatedTimeToSpinUpInSeconds;
     UCHAR Reserved;
   } NVCacheOptions;
-  USHORT ReservedWord220[35];
+  USHORT WriteReadVerifySectorCountMode  :8;
+  USHORT ReservedWord220  :8;
+  USHORT ReservedWord221;
+  struct {
+    USHORT MajorVersion  :12;
+    USHORT TransportType  :4;
+  } TransportMajorVersion;
+  USHORT TransportMinorVersion;
+  USHORT ReservedWord224[6];
+  ULONG  ExtendedNumberOfUserAddressableSectors[2];
+  USHORT MinBlocksPerDownloadMicrocodeMode03;
+  USHORT MaxBlocksPerDownloadMicrocodeMode03;
+  USHORT ReservedWord236[19];
   USHORT Signature  :8;
   USHORT CheckSum  :8;
 } IDENTIFY_DEVICE_DATA, *PIDENTIFY_DEVICE_DATA;
+
+typedef struct _IDENTIFY_PACKET_DATA {
+  struct {
+    USHORT PacketType  :2;
+    USHORT IncompleteResponse  :1;
+    USHORT Reserved1  :2;
+    USHORT DrqDelay  :2;
+    USHORT RemovableMedia  :1;
+    USHORT CommandPacketType  :5;
+    USHORT Reserved2  :1;
+    USHORT DeviceType  :2;
+  } GeneralConfiguration;
+  USHORT ResevedWord1;
+  USHORT UniqueConfiguration;
+  USHORT ReservedWords3[7];
+  UCHAR  SerialNumber[20];
+  USHORT ReservedWords20[3];
+  UCHAR  FirmwareRevision[8];
+  UCHAR  ModelNumber[40];
+  USHORT ReservedWords47[2];
+  struct {
+    USHORT VendorSpecific  :8;
+    USHORT DmaSupported  :1;
+    USHORT LbaSupported  :1;
+    USHORT IordyDisabled  :1;
+    USHORT IordySupported  :1;
+    USHORT Obsolete  :1;
+    USHORT OverlapSupported  :1;
+    USHORT QueuedCommandsSupported  :1;
+    USHORT InterleavedDmaSupported  :1;
+    USHORT DeviceSpecificStandbyTimerValueMin  :1;
+    USHORT Obsolete1  :1;
+    USHORT ReservedWord50  :12;
+    USHORT WordValid  :2;
+  } Capabilities;
+  USHORT ObsoleteWords51[2];
+  USHORT TranslationFieldsValid  :3;
+  USHORT Reserved3  :13;
+  USHORT ReservedWords54[8];
+  struct {
+    USHORT UDMA0Supported  :1;
+    USHORT UDMA1Supported  :1;
+    USHORT UDMA2Supported  :1;
+    USHORT UDMA3Supported  :1;
+    USHORT UDMA4Supported  :1;
+    USHORT UDMA5Supported  :1;
+    USHORT UDMA6Supported  :1;
+    USHORT MDMA0Supported  :1;
+    USHORT MDMA1Supported  :1;
+    USHORT MDMA2Supported  :1;
+    USHORT DMASupported  :1;
+    USHORT ReservedWord62  :4;
+    USHORT DMADIRBitRequired  :1;
+  } DMADIR;
+  USHORT MultiWordDMASupport  :8;
+  USHORT MultiWordDMAActive  :8;
+  USHORT AdvancedPIOModes  :8;
+  USHORT ReservedByte64  :8;
+  USHORT MinimumMWXferCycleTime;
+  USHORT RecommendedMWXferCycleTime;
+  USHORT MinimumPIOCycleTime;
+  USHORT MinimumPIOCycleTimeIORDY;
+  USHORT ReservedWords69[2];
+  USHORT BusReleaseDelay;
+  USHORT ServiceCommandDelay;
+  USHORT ReservedWords73[2];
+  USHORT QueueDepth  :5;
+  USHORT ReservedWord75  :11;
+  struct {
+    USHORT Reserved0  :1;
+    USHORT SataGen1  :1;
+    USHORT SataGen2  :1;
+    USHORT SataGen3  :1;
+    USHORT Reserved1  :5;
+    USHORT HIPM  :1;
+    USHORT PhyEvents  :1;
+    USHORT Reserved3  :2;
+    USHORT HostAutoPS  :1;
+    USHORT DeviceAutoPS  :1;
+    USHORT Reserved4  :1;
+    USHORT Reserved5  :1;
+    USHORT CurrentSpeed  :3;
+    USHORT SlimlineDeviceAttention  :1;
+    USHORT HostEnvironmentDetect  :1;
+    USHORT Reserved  :10;
+  } SerialAtaCapabilities;
+  struct {
+    USHORT Reserved0  :1;
+    USHORT Reserved1  :2;
+    USHORT DIPM  :1;
+    USHORT Reserved2  :1;
+    USHORT AsynchronousNotification  :1;
+    USHORT SoftwareSettingsPreservation  :1;
+    USHORT Reserved3  :9;
+  } SerialAtaFeaturesSupported;
+  struct {
+    USHORT Reserved0  :1;
+    USHORT Reserved1  :2;
+    USHORT DIPM  :1;
+    USHORT Reserved2  :1;
+    USHORT AsynchronousNotification  :1;
+    USHORT SoftwareSettingsPreservation  :1;
+    USHORT DeviceAutoPS  :1;
+    USHORT Reserved3  :8;
+  } SerialAtaFeaturesEnabled;
+  USHORT MajorRevision;
+  USHORT MinorRevision;
+  struct {
+    USHORT SmartCommands  :1;
+    USHORT SecurityMode  :1;
+    USHORT RemovableMedia  :1;
+    USHORT PowerManagement  :1;
+    USHORT PacketCommands  :1;
+    USHORT WriteCache  :1;
+    USHORT LookAhead  :1;
+    USHORT ReleaseInterrupt  :1;
+    USHORT ServiceInterrupt  :1;
+    USHORT DeviceReset  :1;
+    USHORT HostProtectedArea  :1;
+    USHORT Obsolete1  :1;
+    USHORT WriteBuffer  :1;
+    USHORT ReadBuffer  :1;
+    USHORT Nop  :1;
+    USHORT Obsolete2  :1;
+    USHORT DownloadMicrocode  :1;
+    USHORT Reserved1  :2;
+    USHORT AdvancedPm  :1;
+    USHORT Msn  :1;
+    USHORT PowerUpInStandby  :1;
+    USHORT ManualPowerUp  :1;
+    USHORT Reserved2  :1;
+    USHORT SetMax  :1;
+    USHORT Reserved3  :3;
+    USHORT FlushCache  :1;
+    USHORT Reserved4  :1;
+    USHORT WordValid  :2;
+  } CommandSetSupport;
+  struct {
+    USHORT Reserved0  :5;
+    USHORT GpLogging  :1;
+    USHORT Reserved1  :2;
+    USHORT WWN64Bit  :1;
+    USHORT Reserved2  :5;
+    USHORT WordValid  :2;
+  } CommandSetSupportExt;
+  struct {
+    USHORT SmartCommands  :1;
+    USHORT SecurityMode  :1;
+    USHORT RemovableMedia  :1;
+    USHORT PowerManagement  :1;
+    USHORT PacketCommands  :1;
+    USHORT WriteCache  :1;
+    USHORT LookAhead  :1;
+    USHORT ReleaseInterrupt  :1;
+    USHORT ServiceInterrupt  :1;
+    USHORT DeviceReset  :1;
+    USHORT HostProtectedArea  :1;
+    USHORT Obsolete1  :1;
+    USHORT WriteBuffer  :1;
+    USHORT ReadBuffer  :1;
+    USHORT Nop  :1;
+    USHORT Obsolete2  :1;
+    USHORT DownloadMicrocode  :1;
+    USHORT Reserved1  :2;
+    USHORT AdvancedPm  :1;
+    USHORT Msn  :1;
+    USHORT PowerUpInStandby  :1;
+    USHORT ManualPowerUp  :1;
+    USHORT Reserved2  :1;
+    USHORT SetMax  :1;
+    USHORT Reserved3  :3;
+    USHORT FlushCache  :1;
+    USHORT Reserved  :3;
+  } CommandSetActive;
+  struct {
+    USHORT Reserved0  :5;
+    USHORT GpLogging  :1;
+    USHORT Reserved1  :2;
+    USHORT WWN64Bit  :1;
+    USHORT Reserved2  :5;
+    USHORT WordValid  :2;
+  } CommandSetActiveExt;
+  USHORT UltraDMASupport  :8;
+  USHORT UltraDMAActive  :8;
+  USHORT TimeRequiredForNormalEraseModeSecurityEraseUnit;
+  USHORT TimeRequiredForEnhancedEraseModeSecurityEraseUnit;
+  USHORT CurrentAPMLevel;
+  USHORT MasterPasswordID;
+  USHORT HardwareResetResult;
+  USHORT ReservedWords94[14];
+  USHORT WorldWideName[4];
+  USHORT ReservedWords112[13];
+  USHORT AtapiZeroByteCount;
+  USHORT ReservedWord126;
+  USHORT MsnSupport  :2;
+  USHORT ReservedWord127  :14;
+  USHORT SecurityStatus;
+  USHORT VendorSpecific[31];
+  USHORT ReservedWord160[16];
+  USHORT ReservedWord176[46];
+  struct {
+    USHORT MajorVersion  :12;
+    USHORT TransportType  :4;
+  } TransportMajorVersion;
+  USHORT TransportMinorVersion;
+  USHORT ReservedWord224[31];
+  USHORT Signature  :8;
+  USHORT CheckSum  :8;
+} IDENTIFY_PACKET_DATA, *PIDENTIFY_PACKET_DATA;
+
+typedef struct _GP_LOG_NCQ_COMMAND_ERROR {
+  UCHAR NcqTag : 5;
+  UCHAR Reserved0 : 1;
+  UCHAR UNL : 1;
+  UCHAR NonQueuedCmd : 1;
+  UCHAR Reserved1;
+  UCHAR Status;
+  UCHAR Error;
+  UCHAR LBA7_0;
+  UCHAR LBA15_8;
+  UCHAR LBA23_16;
+  UCHAR Device;
+  UCHAR LBA31_24;
+  UCHAR LBA39_32;
+  UCHAR LBA47_40;
+  UCHAR Reserved2;
+  UCHAR Count7_0;
+  UCHAR Count15_8;
+  UCHAR SenseKey;
+  UCHAR ASC;
+  UCHAR ASCQ;
+  UCHAR Reserved3[239];
+  UCHAR Vendor[255];
+  UCHAR Checksum;
+} GP_LOG_NCQ_COMMAND_ERROR, *PGP_LOG_NCQ_COMMAND_ERROR;
 #include <poppack.h>
 #define IDE_LBA_MODE                          (1 << 6)
-#define IDE_COMMAND_NOP                       0x00
-#define IDE_COMMAND_DATA_SET_MANAGEMENT       0x06
-#define IDE_COMMAND_ATAPI_RESET               0x08
-#define IDE_COMMAND_READ                      0x20
-#define IDE_COMMAND_READ_EXT                  0x24
-#define IDE_COMMAND_READ_DMA_EXT              0x25
-#define IDE_COMMAND_READ_DMA_QUEUED_EXT       0x26
-#define IDE_COMMAND_READ_MULTIPLE_EXT         0x29
-#define IDE_COMMAND_WRITE                     0x30
-#define IDE_COMMAND_WRITE_EXT                 0x34
-#define IDE_COMMAND_WRITE_DMA_EXT             0x35
-#define IDE_COMMAND_WRITE_DMA_QUEUED_EXT      0x36
-#define IDE_COMMAND_WRITE_MULTIPLE_EXT        0x39
-#define IDE_COMMAND_WRITE_DMA_FUA_EXT         0x3D
-#define IDE_COMMAND_WRITE_DMA_QUEUED_FUA_EXT  0x3E
-#define IDE_COMMAND_VERIFY                    0x40
-#define IDE_COMMAND_VERIFY_EXT                0x42
-#define IDE_COMMAND_EXECUTE_DEVICE_DIAGNOSTIC 0x90
-#define IDE_COMMAND_SET_DRIVE_PARAMETERS      0x91
-#define IDE_COMMAND_ATAPI_PACKET              0xA0
-#define IDE_COMMAND_ATAPI_IDENTIFY            0xA1
-#define IDE_COMMAND_SMART                     0xB0
-#define IDE_COMMAND_READ_MULTIPLE             0xC4
-#define IDE_COMMAND_WRITE_MULTIPLE            0xC5
-#define IDE_COMMAND_SET_MULTIPLE              0xC6
-#define IDE_COMMAND_READ_DMA                  0xC8
-#define IDE_COMMAND_WRITE_DMA                 0xCA
-#define IDE_COMMAND_WRITE_DMA_QUEUED          0xCC
-#define IDE_COMMAND_WRITE_MULTIPLE_FUA_EXT    0xCE
-#define IDE_COMMAND_GET_MEDIA_STATUS          0xDA
-#define IDE_COMMAND_DOOR_LOCK                 0xDE
-#define IDE_COMMAND_DOOR_UNLOCK               0xDF
-#define IDE_COMMAND_STANDBY_IMMEDIATE         0xE0
-#define IDE_COMMAND_IDLE_IMMEDIATE            0xE1
-#define IDE_COMMAND_CHECK_POWER               0xE5
-#define IDE_COMMAND_SLEEP                     0xE6
-#define IDE_COMMAND_FLUSH_CACHE               0xE7
-#define IDE_COMMAND_FLUSH_CACHE_EXT           0xEA
-#define IDE_COMMAND_IDENTIFY                  0xEC
-#define IDE_COMMAND_MEDIA_EJECT               0xED
-#define IDE_COMMAND_SET_FEATURE               0xEF
-#define IDE_COMMAND_SECURITY_FREEZE_LOCK      0xF5
-#define IDE_COMMAND_NOT_VALID                 0xFF
+#define IDE_DC_DISABLE_INTERRUPTS    0x02
+#define IDE_DC_RESET_CONTROLLER      0x04
+#define IDE_DC_REENABLE_CONTROLLER   0x00
+
+#define IDE_STATUS_ERROR             0x01
+#define IDE_STATUS_INDEX             0x02
+#define IDE_STATUS_CORRECTED_ERROR   0x04
+#define IDE_STATUS_DRQ               0x08
+#define IDE_STATUS_DSC               0x10
+#define IDE_STATUS_DEVICE_FAULT      0x20
+#define IDE_STATUS_DRDY              0x40
+#define IDE_STATUS_IDLE              0x50
+#define IDE_STATUS_BUSY              0x80
+
+#define IDE_ERROR_ILLEGAL_LENGTH     0x01
+#define IDE_ERROR_ADDRESS_NOT_FOUND  IDE_ERROR_ILLEGAL_LENGTH
+#define IDE_ERROR_END_OF_MEDIA       0x02
+#define IDE_ERROR_COMMAND_ABORTED    0x04
+#define IDE_ERROR_MEDIA_CHANGE_REQ   0x08
+#define IDE_ERROR_ID_NOT_FOUND       0x10
+#define IDE_ERROR_MEDIA_CHANGE       0x20
+#define IDE_ERROR_DATA_ERROR         0x40
+#define IDE_ERROR_BAD_BLOCK          0x80
+#define IDE_ERROR_CRC_ERROR          IDE_ERROR_BAD_BLOCK
+
+#define IDE_COMMAND_NOP                         0x00
+#define IDE_COMMAND_DATA_SET_MANAGEMENT         0x06
+#define IDE_COMMAND_ATAPI_RESET                 0x08
+#define IDE_COMMAND_GET_PHYSICAL_ELEMENT_STATUS 0x12
+#define IDE_COMMAND_READ                        0x20
+#define IDE_COMMAND_READ_EXT                    0x24
+#define IDE_COMMAND_READ_DMA_EXT                0x25
+#define IDE_COMMAND_READ_DMA_QUEUED_EXT         0x26
+#define IDE_COMMAND_READ_MULTIPLE_EXT           0x29
+#define IDE_COMMAND_READ_LOG_EXT                0x2F
+#define IDE_COMMAND_WRITE                       0x30
+#define IDE_COMMAND_WRITE_EXT                   0x34
+#define IDE_COMMAND_WRITE_DMA_EXT               0x35
+#define IDE_COMMAND_WRITE_DMA_QUEUED_EXT        0x36
+#define IDE_COMMAND_WRITE_MULTIPLE_EXT          0x39
+#define IDE_COMMAND_WRITE_DMA_FUA_EXT           0x3D
+#define IDE_COMMAND_WRITE_DMA_QUEUED_FUA_EXT    0x3E
+#define IDE_COMMAND_WRITE_LOG_EXT               0x3F
+#define IDE_COMMAND_VERIFY                      0x40
+#define IDE_COMMAND_VERIFY_EXT                  0x42
+#define IDE_COMMAND_ZAC_MANAGEMENT_IN           0x4A
+#define IDE_COMMAND_WRITE_LOG_DMA_EXT           0x57
+#define IDE_COMMAND_TRUSTED_NON_DATA            0x5B
+#define IDE_COMMAND_TRUSTED_RECEIVE             0x5C
+#define IDE_COMMAND_TRUSTED_RECEIVE_DMA         0x5D
+#define IDE_COMMAND_TRUSTED_SEND                0x5E
+#define IDE_COMMAND_TRUSTED_SEND_DMA            0x5F
+#define IDE_COMMAND_READ_FPDMA_QUEUED           0x60
+#define IDE_COMMAND_WRITE_FPDMA_QUEUED          0x61
+#define IDE_COMMAND_NCQ_NON_DATA                0x63
+#define IDE_COMMAND_SEND_FPDMA_QUEUED           0x64
+#define IDE_COMMAND_RECEIVE_FPDMA_QUEUED        0x65
+#define IDE_COMMAND_SET_DATE_AND_TIME           0x77
+#define IDE_COMMAND_REMOVE_ELEMENT_AND_TRUNCATE 0x7C
+#define IDE_COMMAND_EXECUTE_DEVICE_DIAGNOSTIC   0x90
+#define IDE_COMMAND_SET_DRIVE_PARAMETERS        0x91
+#define IDE_COMMAND_DOWNLOAD_MICROCODE          0x92
+#define IDE_COMMAND_DOWNLOAD_MICROCODE_DMA      0x93
+#define IDE_COMMAND_ZAC_MANAGEMENT_OUT          0x9F
+#define IDE_COMMAND_ATAPI_PACKET                0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY              0xA1
+#define IDE_COMMAND_SMART                       0xB0
+#define IDE_COMMAND_READ_LOG_DMA_EXT            0xB1
+#define IDE_COMMAND_SANITIZE_DEVICE             0xB4
+#define IDE_COMMAND_READ_MULTIPLE               0xC4
+#define IDE_COMMAND_WRITE_MULTIPLE              0xC5
+#define IDE_COMMAND_SET_MULTIPLE                0xC6
+#define IDE_COMMAND_READ_DMA                    0xC8
+#define IDE_COMMAND_WRITE_DMA                   0xCA
+#define IDE_COMMAND_WRITE_DMA_QUEUED            0xCC
+#define IDE_COMMAND_WRITE_MULTIPLE_FUA_EXT      0xCE
+#define IDE_COMMAND_GET_MEDIA_STATUS            0xDA
+#define IDE_COMMAND_DOOR_LOCK                   0xDE
+#define IDE_COMMAND_DOOR_UNLOCK                 0xDF
+#define IDE_COMMAND_STANDBY_IMMEDIATE           0xE0
+#define IDE_COMMAND_IDLE_IMMEDIATE              0xE1
+#define IDE_COMMAND_CHECK_POWER                 0xE5
+#define IDE_COMMAND_SLEEP                       0xE6
+#define IDE_COMMAND_FLUSH_CACHE                 0xE7
+#define IDE_COMMAND_FLUSH_CACHE_EXT             0xEA
+#define IDE_COMMAND_IDENTIFY                    0xEC
+#define IDE_COMMAND_MEDIA_EJECT                 0xED
+#define IDE_COMMAND_SET_FEATURE                 0xEF
+#define IDE_COMMAND_SECURITY_SET_PASSWORD       0xF1
+#define IDE_COMMAND_SECURITY_UNLOCK             0xF2
+#define IDE_COMMAND_SECURITY_ERASE_PREPARE      0xF3
+#define IDE_COMMAND_SECURITY_ERASE_UNIT         0xF4
+#define IDE_COMMAND_SECURITY_FREEZE_LOCK        0xF5
+#define IDE_COMMAND_SECURITY_DISABLE_PASSWORD   0xF6
+#define IDE_COMMAND_NOT_VALID                   0xFF
+
+#define IDE_FEATURE_ENABLE_WRITE_CACHE          0x2
+#define IDE_FEATURE_SET_TRANSFER_MODE           0x3
+#define IDE_FEATURE_ENABLE_PUIS                 0x6
+#define IDE_FEATURE_PUIS_SPIN_UP                0x7
+#define IDE_FEATURE_ENABLE_SATA_FEATURE         0x10
+#define IDE_FEATURE_DISABLE_MSN                 0x31
+#define IDE_FEATURE_DISABLE_REVERT_TO_POWER_ON  0x66
+#define IDE_FEATURE_DISABLE_WRITE_CACHE         0x82
+#define IDE_FEATURE_DISABLE_PUIS                0x86
+#define IDE_FEATURE_DISABLE_SATA_FEATURE        0x90
+#define IDE_FEATURE_ENABLE_MSN                  0x95
 #endif