[FREELDR] Fix IDE driver failures on real hardware. (#2255)

- Changes in device detection code:
    * Properly check device signature.
    * Сorrectly reset the IDE controller.
    * Remove check for device type code.
- Fix CD-ROM sector read issue:
    * Changed ATAPI packet opcode to be more universal (Some devices may not have READ12 support).
    * Always use 2048 bytes as sector size when reading the data from a disc.
    * Modify WaitForFlags() to stop polling if the error bit was set.
    * Changed timeout to 31 seconds (ATA default value).
- Add more informational messages in DEBUG mode.
- Fix invalid IDE register value.
- Fix registers names.

Tested by Stanislav Motylkov and Daniel Reimer on XQEMU and on real
hardware MS Xbox revision 1.3 with Philips DVD drive.
It has also been tested manually on PC with a SONY DVD drive.

CORE-16628 CORE-16216
This commit is contained in:
Dmitry Borisov 2020-01-17 19:39:28 +06:00 committed by Hermès Bélusca-Maïto
parent dc81ecf84b
commit a55bab8d1d
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
2 changed files with 231 additions and 114 deletions

View file

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

View file

@ -1,8 +1,8 @@
/*
* PROJECT: FreeLoader
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: ATA/ATAPI polled I/O driver header file.
* COPYRIGHT: Copyright 2019 Dmitry Borisov (di.sean@protonmail.com)
* PURPOSE: ATA/ATAPI programmed I/O driver header file.
* COPYRIGHT: Copyright 2019-2020 Dmitry Borisov (di.sean@protonmail.com)
*/
/* GLOBALS ********************************************************************/
@ -35,8 +35,7 @@
#define IDX_IO1_o_DriveSelect 0x0C
#define IDX_IO1_o_Command 0x0E
#define IDX_IO2_o_AltStatus 0x10C
#define IDX_IO2_o_Control 0x10E
#define IDX_IO2_o_Control 0x10C
#define IDE_IO_o_BankSelect 0x432
#else /* SARCH_PC98 */
#define IDX_IO1_i_Data 0x00
@ -60,8 +59,7 @@
#define IDX_IO1_o_DriveSelect 0x06
#define IDX_IO1_o_Command 0x07
#define IDX_IO2_o_AltStatus 0x206
#define IDX_IO2_o_Control 0x207
#define IDX_IO2_o_Control 0x206
#endif
/*