Files
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

299 lines
8.5 KiB
C

/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: SMART Feature Set support
* COPYRIGHT: Copyright 2026 Dmitry Borisov <[email protected]>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* FUNCTIONS ******************************************************************/
static
VOID
AtaIdeRegsToTaskFile(
_In_ ATAPORT_DEVICE_EXTENSION* __restrict DevExt,
_In_ IDEREGS* __restrict IdeRegs,
_Out_ ATA_DEVICE_REQUEST* __restrict Request)
{
PATA_TASKFILE TaskFile = &Request->TaskFile;
TaskFile->Feature = IdeRegs->bFeaturesReg;
TaskFile->SectorCount = IdeRegs->bSectorCountReg;
TaskFile->LowLba = IdeRegs->bSectorNumberReg;
TaskFile->MidLba = IdeRegs->bCylLowReg;
TaskFile->HighLba = IdeRegs->bCylHighReg;
TaskFile->Command = IDE_COMMAND_SMART; // SMART_CMD
/* Set the master/slave bit to the correct value */
TaskFile->DriveSelect = IdeRegs->bDriveHeadReg & ~IDE_DRIVE_SELECT_SLAVE;
TaskFile->DriveSelect |= DevExt->Device.DeviceSelect & IDE_DRIVE_SELECT_SLAVE;
}
static
VOID
AtaTaskFileToIdeRegs(
_In_ ATA_DEVICE_REQUEST* __restrict Request,
_Out_ IDEREGS* __restrict IdeRegs)
{
PATA_TASKFILE TaskFile = &Request->Output;
IdeRegs->bFeaturesReg = TaskFile->Feature;
IdeRegs->bSectorCountReg = TaskFile->SectorCount;
IdeRegs->bSectorNumberReg = TaskFile->LowLba;
IdeRegs->bCylLowReg = TaskFile->MidLba;
IdeRegs->bCylHighReg = TaskFile->HighLba;
IdeRegs->bCommandReg = TaskFile->Command;
IdeRegs->bDriveHeadReg = TaskFile->DriveSelect;
}
static
ATA_COMPLETION_ACTION
AtaReqCompleteSmartIoControl(
_In_ PATA_DEVICE_REQUEST Request)
{
PSENDCMDOUTPARAMS CmdOut;
CmdOut = (PSENDCMDOUTPARAMS)(((PUCHAR)Request->Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
if (Request->SrbStatus == SRB_STATUS_SUCCESS)
{
CmdOut->DriverStatus.bDriverError = SMART_NO_ERROR;
CmdOut->DriverStatus.bIDEError = 0;
}
else
{
CmdOut->DriverStatus.bDriverError = SMART_IDE_ERROR;
CmdOut->DriverStatus.bIDEError = Request->Output.Error;
}
/* Return the SMART status */
if (Request->Flags & REQUEST_FLAG_SAVE_TASK_FILE)
{
if (Request->Flags & REQUEST_FLAG_HAS_TASK_FILE)
{
PIDEREGS IdeRegs = (PIDEREGS)&CmdOut->bBuffer;
AtaTaskFileToIdeRegs(Request, IdeRegs);
}
else
{
CmdOut->DriverStatus.bDriverError = SMART_IDE_ERROR;
CmdOut->DriverStatus.bIDEError = Request->Output.Error;
}
}
return COMPLETE_IRP;
}
UCHAR
AtaReqSmartIoControl(
_In_ PATAPORT_DEVICE_EXTENSION DevExt,
_In_ PATA_DEVICE_REQUEST Request,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
union _PARAMS
{
PSENDCMDINPARAMS CmdIn;
PSENDCMDOUTPARAMS CmdOut;
} Buffer;
if (Srb->DataTransferLength < (sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdIn) - 1))
return SRB_STATUS_INVALID_REQUEST;
Buffer.CmdIn = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
if (Buffer.CmdIn->irDriveRegs.bCommandReg != SMART_CMD)
return SRB_STATUS_INVALID_REQUEST;
switch (Buffer.CmdIn->irDriveRegs.bFeaturesReg)
{
case READ_ATTRIBUTES:
{
Request->DataTransferLength = READ_ATTRIBUTE_BUFFER_SIZE;
Request->Flags = REQUEST_FLAG_DATA_IN;
break;
}
case READ_THRESHOLDS:
{
Request->DataTransferLength = READ_THRESHOLD_BUFFER_SIZE;
Request->Flags = REQUEST_FLAG_DATA_IN;
break;
}
case SMART_READ_LOG:
{
Request->DataTransferLength =
Buffer.CmdIn->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
Request->Flags = REQUEST_FLAG_DATA_IN;
break;
}
case SMART_WRITE_LOG:
{
Request->DataTransferLength =
Buffer.CmdIn->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
Request->Flags = REQUEST_FLAG_DATA_OUT;
break;
}
case RETURN_SMART_STATUS:
{
Request->DataTransferLength = sizeof(IDEREGS);
Request->Flags = REQUEST_FLAG_SAVE_TASK_FILE;
break;
}
case EXECUTE_OFFLINE_DIAGS:
{
UCHAR Subcommand = Buffer.CmdIn->irDriveRegs.bSectorNumberReg;
if (Subcommand == SMART_SHORT_SELFTEST_CAPTIVE ||
Subcommand == SMART_EXTENDED_SELFTEST_CAPTIVE)
{
return SRB_STATUS_INVALID_REQUEST;
}
__fallthrough;
}
case ENABLE_DISABLE_AUTOSAVE:
case SAVE_ATTRIBUTE_VALUES:
case ENABLE_SMART:
case DISABLE_SMART:
case ENABLE_DISABLE_AUTO_OFFLINE:
{
Request->DataTransferLength = 0;
Request->Flags = 0;
break;
}
default:
return SRB_STATUS_INVALID_REQUEST;
}
if (Request->Flags & (REQUEST_FLAG_DATA_IN | REQUEST_FLAG_SAVE_TASK_FILE))
{
if (Srb->DataTransferLength <
(sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdOut) - 1 + Request->DataTransferLength))
{
return SRB_STATUS_INVALID_REQUEST;
}
Request->DataBuffer = Buffer.CmdOut->bBuffer;
}
else if (Request->Flags & REQUEST_FLAG_DATA_OUT)
{
if (Srb->DataTransferLength <
(sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdIn) - 1 + Request->DataTransferLength))
{
return SRB_STATUS_INVALID_REQUEST;
}
Request->DataBuffer = Buffer.CmdIn->bBuffer;
}
Request->Complete = AtaReqCompleteSmartIoControl;
AtaIdeRegsToTaskFile(DevExt, &Buffer.CmdIn->irDriveRegs, Request);
return SRB_STATUS_PENDING;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleMiniportIdentify(
_In_ PATAPORT_DEVICE_EXTENSION DevExt,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
union _PARAMS
{
PSENDCMDINPARAMS CmdIn;
PSENDCMDOUTPARAMS CmdOut;
} Buffer;
PAGED_CODE();
if (Srb->DataTransferLength <
(sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdOut) - 1 + IDENTIFY_BUFFER_SIZE))
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_BUFFER_TOO_SMALL;
}
Buffer.CmdIn = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
if (IS_ATAPI(&DevExt->Device) || (Buffer.CmdIn->irDriveRegs.bCommandReg != ID_CMD))
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_INVALID_DEVICE_REQUEST;
}
Buffer.CmdOut->cBufferSize = IDENTIFY_BUFFER_SIZE;
Buffer.CmdOut->DriverStatus.bDriverError = 0;
Buffer.CmdOut->DriverStatus.bIDEError = 0;
RtlCopyMemory(Buffer.CmdOut->bBuffer, &DevExt->IdentifyDeviceData, IDENTIFY_BUFFER_SIZE);
Srb->SrbStatus = SRB_STATUS_SUCCESS;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleMiniportSmartVersion(
_In_ PATAPORT_DEVICE_EXTENSION DevExt,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
PATAPORT_CHANNEL_EXTENSION ChanExt = DevExt->Common.FdoExt;
PATAPORT_PORT_DATA PortData = &ChanExt->PortData;
PGETVERSIONINPARAMS VersionParameters;
ULONG i;
PAGED_CODE();
if (Srb->DataTransferLength < (sizeof(*VersionParameters) + sizeof(SRB_IO_CONTROL)))
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_BUFFER_TOO_SMALL;
}
VersionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
/* SMART 1.03 */
VersionParameters->bVersion = 1;
VersionParameters->bRevision = 1;
VersionParameters->bReserved = 0;
VersionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
VersionParameters->bIDEDeviceMap = 0;
/* Emulate the PATA behavior */
for (i = 0; i < MAX_IDE_DEVICE; ++i)
{
PATAPORT_DEVICE_EXTENSION DevExt;
ULONG DeviceFlag;
DevExt = AtaFdoFindDeviceByPath(ChanExt,
AtaMarshallScsiAddress(PortData->PortNumber, i, 0),
Srb);
if (!DevExt)
continue;
DeviceFlag = 1 << i;
if (PortData->PortNumber != 0)
DeviceFlag <<= 2;
if (IS_ATAPI(&DevExt->Device))
DeviceFlag <<= 4;
VersionParameters->bIDEDeviceMap |= DeviceFlag;
IoReleaseRemoveLock(&DevExt->Common.RemoveLock, Srb);
}
Srb->SrbStatus = SRB_STATUS_SUCCESS;
return STATUS_SUCCESS;
}