https://git.reactos.org/?p=reactos.git;a=commitdiff;h=787f81f3f5552a23890b24...
commit 787f81f3f5552a23890b244b2ab1eb07d80737e4 Author: Dmitry Borisov di.sean@protonmail.com AuthorDate: Wed Mar 19 02:56:25 2025 +0600 Commit: GitHub noreply@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@protonmail.com) + * COPYRIGHT: Copyright 2019-2025 Dmitry Borisov (di.sean@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@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@reactos.com) - * Copyright 2019 Dmitry Borisov (di.sean@protonmail.com) + * Copyright 2019-2025 Dmitry Borisov (di.sean@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@protonmail.com) + * COPYRIGHT: Copyright 2019-2025 Dmitry Borisov (di.sean@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