Files
reactos/drivers/storage/ide/atapi/dev_config.c
Dmitry Borisov ac33647888 [ATAPI] Add ATA storage driver
CORE-17256
CORE-17191
CORE-17716
CORE-17977
CORE-13976
CORE-16216
2026-04-21 15:01:22 -05:00

397 lines
11 KiB
C

/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Device initialization and configuration code
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
#include <acpiioct.h>
/* FUNCTIONS ******************************************************************/
static
NTSTATUS
AtaDeviceSetGeometry(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
NTSTATUS Status;
if (IS_ATAPI(&DevExt->Device) || (DevExt->Device.DeviceFlags & DEVICE_LBA_MODE))
return STATUS_SUCCESS;
Request->Flags = REQUEST_FLAG_SET_DEVICE_REGISTER;
Request->TimeOut = 5;
RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
Request->TaskFile.Command = IDE_COMMAND_SET_DRIVE_PARAMETERS;
Request->TaskFile.SectorCount = (UCHAR)DevExt->Device.SectorsPerTrack;
Request->TaskFile.DriveSelect = (UCHAR)(DevExt->Device.Heads - 1) |
DevExt->Device.DeviceSelect;
Status = AtaPortSendRequest(PortData, DevExt);
if (!NT_SUCCESS(Status))
{
WARN("CH %lu: Failed to set geometry for '%s'\n",
PortData->PortNumber,
DevExt->TransferModeSelectedBitmap,
DevExt->FriendlyName);
}
return Status;
}
static
VOID
AtaDeviceBuildSetTransferModeTaskFile(
_In_ PATA_DEVICE_REQUEST Request,
_In_ UCHAR Mode)
{
Request->Flags = 0;
Request->TimeOut = 3;
RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
Request->TaskFile.Command = IDE_COMMAND_SET_FEATURE;
Request->TaskFile.Feature = IDE_FEATURE_SET_TRANSFER_MODE;
Request->TaskFile.SectorCount = Mode;
}
static
NTSTATUS
AtaDeviceSetPioTransferMode(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
NTSTATUS Status;
ULONG Mode;
NT_VERIFY(_BitScanReverse(&Mode, DevExt->TransferModeSelectedBitmap & PIO_ALL) != 0);
Mode = IDE_SET_ADVANCE_PIO_MODE(Mode);
AtaDeviceBuildSetTransferModeTaskFile(Request, Mode);
Status = AtaPortSendRequest(PortData, DevExt);
if (!NT_SUCCESS(Status))
{
WARN("CH %lu: Failed to set %lu PIO settings for '%s'\n",
PortData->PortNumber,
Mode,
DevExt->FriendlyName);
}
return Status;
}
static
NTSTATUS
AtaDeviceSetDmaTransferMode(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
NTSTATUS Status;
ULONG Mode;
if (!_BitScanReverse(&Mode, DevExt->TransferModeSelectedBitmap & ~PIO_ALL))
return STATUS_SUCCESS;
if (Mode >= UDMA_MODE(0))
Mode = IDE_SET_UDMA_MODE(Mode - UDMA_MODE(0));
else if (Mode >= MWDMA_MODE(0))
Mode = IDE_SET_MWDMA_MODE(Mode - MWDMA_MODE(0));
else
Mode = IDE_SET_SWDMA_MODE(Mode - SWDMA_MODE(0));
AtaDeviceBuildSetTransferModeTaskFile(Request, Mode);
Status = AtaPortSendRequest(PortData, DevExt);
if (NT_SUCCESS(Status))
{
DevExt->Device.DeviceFlags &= ~DEVICE_PIO_ONLY;
}
else
{
WARN("CH %lu: Failed to set 0x%lx DMA settings for '%s'\n",
PortData->PortNumber,
Mode,
DevExt->FriendlyName);
DevExt->Device.DeviceFlags &= ~DEVICE_NCQ;
DevExt->TransferModeSelectedBitmap &= PIO_ALL;
}
return Status;
}
static
NTSTATUS
AtaDeviceSetMultipleMode(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
NTSTATUS Status;
if (IS_ATAPI(&DevExt->Device))
return STATUS_SUCCESS;
DevExt->Device.MultiSectorCount = AtaDevMaximumSectorsPerDrq(&DevExt->IdentifyDeviceData);
if (DevExt->Device.MultiSectorCount == 0)
return STATUS_SUCCESS;
Request->Flags = 0;
Request->TimeOut = 3;
RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
Request->TaskFile.Command = IDE_COMMAND_SET_MULTIPLE;
Request->TaskFile.SectorCount = DevExt->Device.MultiSectorCount;
Status = AtaPortSendRequest(PortData, DevExt);
if (!NT_SUCCESS(Status))
{
WARN("CH %lu: Failed to set %u multiple mode for '%s'\n",
PortData->PortNumber,
DevExt->Device.MultiSectorCount,
DevExt->FriendlyName);
DevExt->Device.MultiSectorCount = 0;
}
return Status;
}
static
BOOLEAN
AtaDeviceFilterAcpiTaskFile(
_In_ PATA_ACPI_TASK_FILE AcpiTaskFile)
{
switch (AcpiTaskFile->Command)
{
/* These features are managed by the driver */
case IDE_COMMAND_SET_FEATURE:
{
if (AcpiTaskFile->Feature == IDE_FEATURE_SET_TRANSFER_MODE)
return FALSE;
break;
}
case IDE_COMMAND_SET_DRIVE_PARAMETERS:
case IDE_COMMAND_SET_MULTIPLE:
return FALSE;
// TODO: Anything else to check?
default:
break;
}
return TRUE;
}
static
VOID
AtaDeviceAcpiTaskFileToInternalTaskFile(
_In_ ATA_ACPI_TASK_FILE* __restrict AcpiTaskFile,
_Out_ ATA_DEVICE_REQUEST* __restrict Request)
{
Request->Flags = REQUEST_FLAG_SET_DEVICE_REGISTER;
Request->TimeOut = 6;
Request->TaskFile.Feature = AcpiTaskFile->Feature;
Request->TaskFile.SectorCount = AcpiTaskFile->SectorCount;
Request->TaskFile.LowLba = AcpiTaskFile->LowLba;
Request->TaskFile.MidLba = AcpiTaskFile->MidLba;
Request->TaskFile.HighLba = AcpiTaskFile->HighLba;
Request->TaskFile.DriveSelect = AcpiTaskFile->DriveSelect;
Request->TaskFile.Command = AcpiTaskFile->Command;
}
static
NTSTATUS
AtaDeviceExecuteAcpiTaskFile(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PACPI_EVAL_OUTPUT_BUFFER GtfDataBuffer = DevExt->GtfDataBuffer;
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
PATA_ACPI_TASK_FILE AcpiTaskFile;
NTSTATUS Status;
ULONG i;
if (!GtfDataBuffer)
return STATUS_SUCCESS;
ASSERT(GtfDataBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
AcpiTaskFile = (PATA_ACPI_TASK_FILE)GtfDataBuffer->Argument[0].Data;
for (i = 0; i < GtfDataBuffer->Argument[0].DataLength / sizeof(*AcpiTaskFile); ++i)
{
PCSTR Result;
if (!AtaDeviceFilterAcpiTaskFile(AcpiTaskFile))
{
Result = "filtered out";
}
else
{
AtaDeviceAcpiTaskFileToInternalTaskFile(AcpiTaskFile, Request);
Status = AtaPortSendRequest(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Result = NT_SUCCESS(Status) ? "completed" : "aborted";
}
INFO("CH %lu: GTF[%lu]: %02x:%02x:%02x:%02x:%02x:%02x:%02x -- %s\n",
PortData->PortNumber,
i,
AcpiTaskFile->Feature,
AcpiTaskFile->SectorCount,
AcpiTaskFile->LowLba,
AcpiTaskFile->MidLba,
AcpiTaskFile->HighLba,
AcpiTaskFile->DriveSelect,
AcpiTaskFile->Command,
Result);
++AcpiTaskFile;
}
return STATUS_SUCCESS;
}
/*
* See MSDN note:
* https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/security-group-commands
*/
static
NTSTATUS
AtaDeviceLockSecurityModeFeatureCommands(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
if (IS_ATAPI(&DevExt->Device) ||
AtapInPEMode ||
!AtaDevHasSecurityModeFeature(&DevExt->IdentifyDeviceData))
{
return STATUS_SUCCESS;
}
Request->Flags = 0;
Request->TimeOut = 3;
RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
Request->TaskFile.Command = IDE_COMMAND_SECURITY_FREEZE_LOCK;
return AtaPortSendRequest(PortData, DevExt);
}
static
NTSTATUS
AtaDeviceLockDeviceParameters(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
Request->Flags = 0;
Request->TimeOut = 3;
RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
Request->TaskFile.Command = IDE_COMMAND_SET_FEATURE;
Request->TaskFile.Feature = IDE_FEATURE_DISABLE_REVERT_TO_POWER_ON;
return AtaPortSendRequest(PortData, DevExt);
}
static
NTSTATUS
AtaDeviceEnableMsnFeature(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
PATA_DEVICE_REQUEST Request = &PortData->Worker.InternalRequest;
NTSTATUS Status;
if (!AtaDevHasRemovableMediaStatusNotification(&DevExt->IdentifyDeviceData))
return STATUS_SUCCESS;
Request->Flags = 0;
Request->TimeOut = 3;
RtlZeroMemory(&Request->TaskFile, sizeof(Request->TaskFile));
Request->TaskFile.Command = IDE_COMMAND_SET_FEATURE;
Request->TaskFile.Feature = IDE_FEATURE_ENABLE_MSN;
Status = AtaPortSendRequest(PortData, DevExt);
if (NT_SUCCESS(Status))
{
DevExt->Device.DeviceFlags |= DEVICE_HAS_MEDIA_STATUS;
}
return Status;
}
NTSTATUS
AtaPortDeviceProcessConfig(
_In_ PATAPORT_PORT_DATA PortData,
_In_ PATAPORT_DEVICE_EXTENSION DevExt)
{
NTSTATUS Status;
DevExt->Device.DeviceFlags |= DEVICE_PIO_ONLY;
DevExt->Device.DeviceFlags &= ~(DEVICE_HAS_MEDIA_STATUS | DEVICE_SENSE_DATA_REPORTING);
DevExt->Device.MultiSectorCount = 0;
Status = AtaDeviceSetGeometry(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceSetPioTransferMode(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceSetDmaTransferMode(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceSetMultipleMode(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceExecuteAcpiTaskFile(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceLockSecurityModeFeatureCommands(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceLockDeviceParameters(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
Status = AtaDeviceEnableMsnFeature(PortData, DevExt);
if (Status == STATUS_ADAPTER_HARDWARE_ERROR)
return Status;
/* Identify data might have changed during the configuration, so update it here */
Status = AtaDeviceSendIdentify(PortData,
DevExt,
IS_ATAPI(&DevExt->Device) ?
IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY);
if (NT_SUCCESS(Status))
{
RtlCopyMemory(&DevExt->IdentifyDeviceData,
DevExt->Device.LocalBuffer,
sizeof(DevExt->IdentifyDeviceData));
}
return Status;
}