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