ReactOS 0.4.16-dev-2633-g8dc9e50
ahci_hw.c File Reference
#include "pciidex.h"
Include dependency graph for ahci_hw.c:

Go to the source code of this file.

Functions

static BOOLEAN AtaAhciPollRegister (_In_ PVOID IoBase, _In_ AHCI_PORT_REGISTER Register, _In_ ULONG Mask, _In_ ULONG Value, _In_range_(>, 0) ULONG TimeOut)
 
VOID AtaAhciEnableInterrupts (_In_ PVOID ChannelContext, _In_ BOOLEAN Enable)
 
static BOOLEAN AtaAhciIsHbaHotRemoved (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciSendComReset (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciStopCommandListProcess (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciStartCommandListProcess (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciStopCommandListProcessAndWait (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciStopFisReceiveProcess (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciStartFisReceiveProcess (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciStopFisReceiveProcessAndWait (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciStartFisReceiveProcessAndWait (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciPhyEnterListenMode (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciPerformCommandListOverride (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciAtapiLedControl (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ BOOLEAN DoEnable)
 
static VOID AtaAhciFbsControl (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ BOOLEAN DoEnable)
 
static BOOLEAN AtaAhciEnterIdleState (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciSetupDmaMemoryAddress (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static VOID AtaAhciSpinUp (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciPhyCheckDevicePresence (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciPhyWaitForReady (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciWaitForDeviceReady (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG TimeOut)
 
static UCHAR AtaAhciPostRequestPolled (_In_ PCHANNEL_DATA_AHCI ChanData, _In_range_(>, 0) ULONG TimeOutMs)
 
static UCHAR AtaAhciSendResetFis (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ UCHAR PortNumber, _In_ BOOLEAN AssertSRST, _In_range_(>, 0) ULONG TimeOutMs)
 
static UCHAR AtaAhciPmpRead (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ UCHAR PortNumber, _In_ USHORT Register, _Out_ PULONG Result)
 
static UCHAR AtaAhciPmpWrite (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ UCHAR PortNumber, _In_ USHORT Register, _In_ ULONG Value)
 
static BOOLEAN AtaAhciPmpDisableSilXmitEarlyAck (_In_ PCHANNEL_DATA_AHCI ChanData)
 
static BOOLEAN AtaAhciPmpIdentifyPmp (_In_ PCHANNEL_DATA_AHCI ChanData, _Out_ PULONG PortCountResult)
 
static ATA_CONNECTION_STATUS AtaAhciPmpDetect (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ PBOOLEAN CheckForPmp)
 
static ATA_CONNECTION_STATUS AtaAhciPhyCheckConnection (_In_ PCHANNEL_DATA_AHCI ChanData)
 
ULONG AtaAhciEnumerateChannel (_In_ PVOID ChannelContext)
 
static BOOLEAN AtaAhciPmpCheckSendComReset (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
 
static ATA_CONNECTION_STATUS AtaAhciPmpPhyCheckDevicePresence (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
 
static ATA_CONNECTION_STATUS AtaAhciPmpPhyWaitForReady (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
 
static ATA_CONNECTION_STATUS AtaPmpCheckConnection (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
 
static ATA_CONNECTION_STATUS AtaAhciPmpIdentifyDeviceBehindPmp (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
 
ATA_CONNECTION_STATUS AtaAhciIdentifyDevice (_In_ PVOID ChannelContext, _In_ ULONG DeviceNumber)
 
VOID AtaAhciStopDma (_In_ PCHANNEL_DATA_AHCI ChanData)
 
VOID AtaAhciResetChannel (_In_ PVOID ChannelContext)
 
static VOID AtaAhciSaveReceivedFisArea (_In_ AHCI_FIS_DEVICE_TO_HOST *__restrict Fis, _Inout_ ATA_DEVICE_REQUEST *__restrict Request)
 Captures and saves a dump of the AHCI task file registers, except the values in the Fis->Status and Fis->Error fields.
 
VOID AtaAhciSaveTaskFile (_In_ PCHANNEL_DATA_AHCI ChanData, _Inout_ PATA_DEVICE_REQUEST Request, _In_ BOOLEAN ProcessErrorStatus)
 
VOID AtaAhciHandleFatalError (_In_ PCHANNEL_DATA_AHCI ChanData)
 
VOID AtaAhciHandlePortStateChange (_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG InterruptStatus)
 
BOOLEAN AtaAhciDowngradeInterfaceSpeed (_In_ PCHANNEL_DATA_AHCI ChanData)
 
ULONG AtaAhciChannelGetMaximumDeviceCount (_In_ PVOID ChannelContext)
 

Function Documentation

◆ AtaAhciAtapiLedControl()

static VOID AtaAhciAtapiLedControl ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ BOOLEAN  DoEnable 
)
static

Definition at line 288 of file ahci_hw.c.

291{
292 ULONG CmdStatus, NewCmdStatus;
293
294 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
295 if (DoEnable)
296 NewCmdStatus = CmdStatus | AHCI_PXCMD_ATAPI;
297 else
298 NewCmdStatus = CmdStatus & ~AHCI_PXCMD_ATAPI;
299
300 if (CmdStatus != NewCmdStatus)
301 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, NewCmdStatus);
302}
FORCEINLINE VOID AHCI_PORT_WRITE(_In_ PVOID PortIoBase, _In_ AHCI_PORT_REGISTER Register, _In_ ULONG Value)
Definition: ahci.h:557
#define AHCI_PXCMD_ATAPI
Definition: ahci.h:167
FORCEINLINE ULONG AHCI_PORT_READ(_In_ PVOID PortIoBase, _In_ AHCI_PORT_REGISTER Register)
Definition: ahci.h:548
@ PxCmdStatus
Definition: ahci.h:104
uint32_t ULONG
Definition: typedefs.h:59

Referenced by AtaAhciIdentifyDevice().

◆ AtaAhciChannelGetMaximumDeviceCount()

ULONG AtaAhciChannelGetMaximumDeviceCount ( _In_ PVOID  ChannelContext)

Definition at line 1569 of file ahci_hw.c.

1571{
1572 PCHANNEL_DATA_AHCI ChanData = ChannelContext;
1573 PATA_CONTROLLER Controller = ChanData->Controller;
1574
1575 if (Controller->AhciCapabilities & AHCI_CAP_SPM)
1576 return AHCI_MAX_PMP_DEVICES;
1577
1578 return AHCI_MAX_PORT_DEVICES;
1579}
#define AHCI_CAP_SPM
Definition: ahci.h:324
#define AHCI_MAX_PMP_DEVICES
Definition: ahci.h:12
#define AHCI_MAX_PORT_DEVICES
Definition: ahci.h:11
ULONG AhciCapabilities
Definition: pciidex.h:218

Referenced by PciIdeXQueryPciIdeInterface().

◆ AtaAhciDowngradeInterfaceSpeed()

BOOLEAN AtaAhciDowngradeInterfaceSpeed ( _In_ PCHANNEL_DATA_AHCI  ChanData)

Definition at line 1542 of file ahci_hw.c.

1544{
1545 ULONG SataSpeed, SataControl;
1546
1547 SataSpeed = AHCI_PORT_READ(ChanData->IoBase, PxSataStatus) & AHCI_PXSSTS_SPD_MASK;
1548 if (SataSpeed != AHCI_PXSSTS_SPD_SATA1)
1549 {
1550 SataControl = AHCI_PORT_READ(ChanData->IoBase, PxSataControl);
1551
1552 if ((SataControl & AHCI_PXCTL_SPD_MASK) != AHCI_PXCTL_SPD_LIMIT_NONE)
1553 {
1554 SataControl &= ~AHCI_PXCTL_SPD_MASK;
1555 SataControl |= SataSpeed - AHCI_PXCTL_SPD_LIMIT_LEVEL;
1556
1557 WARN("CH %lu: Downgrading interface speed to %08lx\n", ChanData->Channel, SataControl);
1558
1559 AHCI_PORT_WRITE(ChanData->IoBase, PxSataControl, SataControl);
1560 return TRUE;
1561 }
1562 }
1563
1564 INFO("CH %lu: Unable to downgrade interface speed %08lx\n", ChanData->Channel, SataSpeed);
1565 return FALSE;
1566}
#define AHCI_PXSSTS_SPD_SATA1
Definition: ahci.h:219
#define AHCI_PXCTL_SPD_MASK
Definition: ahci.h:233
#define AHCI_PXSSTS_SPD_MASK
Definition: ahci.h:210
@ PxSataStatus
Definition: ahci.h:107
@ PxSataControl
Definition: ahci.h:108
#define AHCI_PXCTL_SPD_LIMIT_NONE
Definition: ahci.h:240
#define AHCI_PXCTL_SPD_LIMIT_LEVEL
Definition: ahci.h:245
#define WARN(fmt,...)
Definition: precomp.h:61
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define INFO
Definition: debug.h:89

Referenced by AtaCtrlDowngradeInterfaceSpeed().

◆ AtaAhciEnableInterrupts()

VOID AtaAhciEnableInterrupts ( _In_ PVOID  ChannelContext,
_In_ BOOLEAN  Enable 
)

Definition at line 56 of file ahci_hw.c.

59{
60 PCHANNEL_DATA_AHCI ChanData = ChannelContext;
61
62 INFO("CH %lu: %sble interrupts\n", ChanData->Channel, Enable ? "Ena" : "Disa");
63
64 /* Clear port interrupts */
65 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
66 AHCI_PORT_WRITE(ChanData->IoBase, PxInterruptStatus, 0xFFFFFFFF);
67 AHCI_HBA_WRITE(ChanData->Controller->IoBase, HbaInterruptStatus, 1 << ChanData->Channel);
68
70}
@ PxInterruptEnable
Definition: ahci.h:103
@ PxSataError
Definition: ahci.h:109
@ PxInterruptStatus
Definition: ahci.h:102
FORCEINLINE VOID AHCI_HBA_WRITE(_In_ PVOID HbaIoBase, _In_ AHCI_HOST_BUS_ADAPTER_REGISTER Register, _In_ ULONG Value)
Definition: ahci.h:538
#define AHCI_PORT_INTERRUPT_MASK
Definition: ahci.h:276
@ HbaInterruptStatus
Definition: ahci.h:85
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:142

◆ AtaAhciEnterIdleState()

static BOOLEAN AtaAhciEnterIdleState ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 351 of file ahci_hw.c.

353{
354 ULONG CmdStatus;
355
356 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
357
358 /* Already in an idle state */
359 if (!(CmdStatus & (AHCI_PXCMD_ST | AHCI_PXCMD_CR | AHCI_PXCMD_FRE | AHCI_PXCMD_FR)))
360 return TRUE;
361
362 /* Stop the command list DMA engine */
364 {
365 WARN("CH %lu: Failed to stop the command list DMA engine %08lx\n",
366 ChanData->Channel,
367 AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus));
368 return FALSE;
369 }
370
372
373 /* Stop the FIS Receive DMA engine */
375 {
376 WARN("CH %lu: Failed to stop the FIS Receive DMA engine %08lx\n",
377 ChanData->Channel,
378 AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus));
379 return FALSE;
380 }
381
382 return TRUE;
383}
#define AHCI_PXCMD_FRE
Definition: ahci.h:153
#define AHCI_PXCMD_CR
Definition: ahci.h:158
#define AHCI_PXCMD_ST
Definition: ahci.h:149
#define AHCI_PXCMD_FR
Definition: ahci.h:157
static BOOLEAN AtaAhciPerformCommandListOverride(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:267
static BOOLEAN AtaAhciStopCommandListProcessAndWait(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:163
static BOOLEAN AtaAhciStopFisReceiveProcessAndWait(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:207

Referenced by AtaAhciPhyCheckConnection().

◆ AtaAhciEnumerateChannel()

ULONG AtaAhciEnumerateChannel ( _In_ PVOID  ChannelContext)

Definition at line 970 of file ahci_hw.c.

972{
973 PCHANNEL_DATA_AHCI ChanData = ChannelContext;
974 ULONG RetryCount, PortCount;
975 ATA_CONNECTION_STATUS ConnectionStatus;
976 BOOLEAN CheckForPmp = TRUE;
977
978 if (AtaAhciIsHbaHotRemoved(ChanData))
979 return 0;
980
982
983 /* COMRESET acts as a bus reset for the SATA port */
984 ChanData->PortNotification(AtaResetDetected, ChanData->PortContext, 0xFFFFFFFF);
985
986 for (RetryCount = 3; RetryCount > 0; RetryCount--)
987 {
988 ChanData->ChanInfo &= ~CHANNEL_FLAG_IS_PMP;
989
990 ConnectionStatus = AtaAhciPhyCheckConnection(ChanData);
991 if (ConnectionStatus != CONN_STATUS_DEV_UNKNOWN)
992 {
993 PortCount = 0;
994 break;
995 }
996
997 /*
998 * Check for a Port Multiplier.
999 *
1000 * If the last discovery resulted in a failure,
1001 * threat this device as a non-port multiplier device
1002 * (i.e. a SATA device that is connected to device Port 0).
1003 */
1004 if ((ChanData->Controller->AhciCapabilities & AHCI_CAP_SPM) &&
1005 (RetryCount > 1) && CheckForPmp)
1006 {
1007 INFO("CH %lu: Trying to detect PMP\n", ChanData->Channel);
1008
1009 ConnectionStatus = AtaAhciPmpDetect(ChanData, &CheckForPmp);
1010 if (ConnectionStatus == CONN_STATUS_FAILURE)
1011 continue;
1012
1013 if (ConnectionStatus == CONN_STATUS_DEV_UNKNOWN)
1014 {
1015 INFO("CH %lu: Discovered a Port Multiplier\n", ChanData->Channel);
1016
1017 ChanData->ChanInfo |= CHANNEL_FLAG_IS_PMP;
1018
1019 if (!AtaAhciPmpIdentifyPmp(ChanData, &PortCount))
1020 continue;
1021
1022 break;
1023 }
1024 }
1025 else
1026 {
1028 }
1029
1030 PortCount = 1;
1031 break;
1032 }
1033
1034 if (ConnectionStatus == CONN_STATUS_FAILURE)
1035 {
1036 /* Channel reset failed, clear active DMA commands, so we can release pending IRPs safely */
1039 }
1040 else if (PortCount == 0)
1041 {
1042 AtaAhciPhyEnterListenMode(ChanData);
1043 }
1044
1046
1047 ChanData->TotalPortCount = PortCount;
1048 return PortCount;
1049}
unsigned char BOOLEAN
Definition: actypes.h:127
static VOID AtaAhciStartCommandListProcess(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:137
static ATA_CONNECTION_STATUS AtaAhciPmpDetect(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ PBOOLEAN CheckForPmp)
Definition: ahci_hw.c:800
static BOOLEAN AtaAhciPmpIdentifyPmp(_In_ PCHANNEL_DATA_AHCI ChanData, _Out_ PULONG PortCountResult)
Definition: ahci_hw.c:734
static VOID AtaAhciPhyEnterListenMode(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:244
static BOOLEAN AtaAhciIsHbaHotRemoved(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:74
static ATA_CONNECTION_STATUS AtaAhciPhyCheckConnection(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:889
@ CONN_STATUS_FAILURE
Definition: ata_shared.h:83
@ CONN_STATUS_DEV_UNKNOWN
Definition: ata_shared.h:85
enum _ATA_CONNECTION_STATUS ATA_CONNECTION_STATUS
@ AtaResetDetected
Definition: ata_shared.h:75
#define CHANNEL_FLAG_IS_PMP
Definition: pciidex.h:272
DECLSPEC_NOINLINE_FROM_PAGED VOID AtaChanEnableInterruptsSync(_In_ PVOID ChannelContext, _In_ BOOLEAN Enable)
Definition: fdo.c:62
ULONG TotalPortCount
Definition: pciidex.h:346

◆ AtaAhciFbsControl()

static VOID AtaAhciFbsControl ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ BOOLEAN  DoEnable 
)
static

Definition at line 306 of file ahci_hw.c.

309{
310 ULONG FbsControl, NewFbsControl;
311
312 if (!(ChanData->ChanInfo & CHANNEL_FLAG_HAS_FBS))
313 return;
314
315 ChanData->LastFbsDeviceNumber = 0xFF;
316
317 FbsControl = AHCI_PORT_READ(ChanData->IoBase, PxFisSwitchingControl);
318 if (DoEnable)
319 {
320 NewFbsControl = FbsControl | AHCI_FBS_ENABLE;
321 }
322 else
323 {
324 NewFbsControl = FbsControl & ~AHCI_FBS_ENABLE;
325 ChanData->ChanInfo &= ~CHANNEL_FLAG_FBS_ENABLED;
326 }
327
328 if ((FbsControl & NewFbsControl) ^ AHCI_FBS_ENABLE)
329 {
330 AHCI_PORT_WRITE(ChanData->IoBase, PxFisSwitchingControl, NewFbsControl);
331 }
332
333 if (!DoEnable)
334 return;
335
336 /* Make sure we can read back the new value */
337 FbsControl = AHCI_PORT_READ(ChanData->IoBase, PxFisSwitchingControl);
338 if (FbsControl & AHCI_FBS_ENABLE)
339 {
340 ChanData->ChanInfo |= CHANNEL_FLAG_FBS_ENABLED;
341 INFO("CH %lu: FBS enabled\n", ChanData->Channel);
342 }
343 else
344 {
345 WARN("CH %lu: Unable to enable FIS-based switching\n", ChanData->Channel);
346 }
347}
#define AHCI_FBS_ENABLE
Definition: ahci.h:257
@ PxFisSwitchingControl
Definition: ahci.h:113
#define CHANNEL_FLAG_FBS_ENABLED
Definition: pciidex.h:274
#define CHANNEL_FLAG_HAS_FBS
Definition: pciidex.h:273

Referenced by AtaAhciIdentifyDevice(), and AtaAhciPmpDetect().

◆ AtaAhciHandleFatalError()

VOID AtaAhciHandleFatalError ( _In_ PCHANNEL_DATA_AHCI  ChanData)

Definition at line 1397 of file ahci_hw.c.

1399{
1400 ULONG CurrentCommandSlot, TaskFileData;
1401 ULONG i, CmdStatus, SlotsBitmap, FailedSlot;
1403
1404 Request = NULL;
1405 CurrentCommandSlot = AHCI_PXCMD_CCS(AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus));
1406
1407 /* Clear the ST bit. This also clears PxCI, PxSACT, and PxCMD.CCS */
1409
1410 if (AtaAhciIsHbaHotRemoved(ChanData))
1411 goto Done;
1412
1413 /* Wait for 500ms */
1414 for (i = 50000; i > 0; i--)
1415 {
1416 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
1417 if (!(CmdStatus & AHCI_PXCMD_CR))
1418 break;
1419
1421 }
1422 if (i == 0)
1423 {
1424 /* The interface is hung */
1425 ERR("CH %lu: Failed to stop the command list DMA engine %08lx\n",
1426 ChanData->Channel,
1427 CmdStatus);
1428 goto Done;
1429 }
1430
1431 TaskFileData = AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData);
1432 if (TaskFileData & (IDE_STATUS_BUSY | IDE_STATUS_DRQ))
1433 {
1434 /* Put the device to the idle state */
1435 ERR("CH %lu: Busy TFD %08lx\n", ChanData->Channel, TaskFileData);
1436 goto Done;
1437 }
1438
1439 /* Clear errors */
1440 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError,
1441 AHCI_PORT_READ(ChanData->IoBase, PxSataError));
1442
1443 /* NCQ recovery is needed */
1444 if (ChanData->ActiveQueuedSlotsBitmap != 0)
1445 {
1447
1448 /* Find some active command */
1449 NT_VERIFY(_BitScanForward(&FailedSlot, ChanData->ActiveQueuedSlotsBitmap) != 0);
1450
1451 Request = ChanData->Slots[FailedSlot];
1452 ASSERT(Request);
1453 ASSERT(Request->Slot == FailedSlot);
1455 goto Done;
1456 }
1457
1458 if (IsPowerOfTwo(ChanData->ActiveSlotsBitmap))
1459 {
1460 /* We have exactly one slot is outstanding */
1461 SlotsBitmap = ChanData->ActiveSlotsBitmap;
1462 }
1463 else if (ChanData->ActiveSlotsBitmap & (1 << CurrentCommandSlot))
1464 {
1465 SlotsBitmap = 1 << CurrentCommandSlot;
1466 }
1467 else
1468 {
1469 /* Indicates that the error bit is spurious *or* the exact slot is not known */
1470 if (ChanData->ActiveSlotsBitmap != 0)
1471 {
1472 ERR("CH %lu: Invalid slot received from the HBA %08lX --> %08lX\n",
1473 ChanData->Channel,
1474 ChanData->ActiveSlotsBitmap,
1475 1 << CurrentCommandSlot);
1476 }
1477 else
1478 {
1479 WARN("CH %lu: Spurious error interrupt %08lX\n",
1480 ChanData->Channel,
1481 AHCI_PORT_READ(ChanData->IoBase, PxInterruptStatus));
1482 }
1483 goto Done;
1484 }
1485
1487
1488 NT_VERIFY(_BitScanForward(&FailedSlot, SlotsBitmap) != 0);
1489
1490 Request = ChanData->Slots[FailedSlot];
1491 ASSERT(Request);
1492 ASSERT(Request->Slot == FailedSlot);
1493
1494 /* Save the error */
1495 Request->SrbStatus = SRB_STATUS_ERROR;
1496 Request->Output.Status = (TaskFileData & AHCI_PXTFD_STATUS_MASK);
1497 Request->Output.Error = (TaskFileData & AHCI_PXTFD_ERROR_MASK) >> AHCI_PXTFD_ERROR_SHIFT;
1498
1499 /* Save the current task file for the "ATA LBA field" (SAT-6 11.7) */
1500 if (!(Request->Device->TransportFlags & DEVICE_IS_ATAPI) ||
1502 {
1503 AtaAhciSaveTaskFile(ChanData, Request, TRUE);
1504 }
1505
1506Done:
1507 /* Request arbitration from the port worker */
1508 ChanData->PortNotification(AtaRequestFailed, ChanData->PortContext, Request);
1509}
#define AHCI_PXTFD_STATUS_MASK
Definition: ahci.h:188
#define AHCI_PXCMD_CCS(Value)
Definition: ahci.h:183
#define AHCI_PXTFD_ERROR_MASK
Definition: ahci.h:189
@ PxTaskFileData
Definition: ahci.h:105
#define AHCI_PXTFD_ERROR_SHIFT
Definition: ahci.h:191
static VOID AtaAhciStopCommandListProcess(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:122
VOID AtaAhciSaveTaskFile(_In_ PCHANNEL_DATA_AHCI ChanData, _Inout_ PATA_DEVICE_REQUEST Request, _In_ BOOLEAN ProcessErrorStatus)
Definition: ahci_hw.c:1325
#define REQUEST_FLAG_NCQ
Definition: ata_shared.h:284
#define REQUEST_FLAG_SAVE_TASK_FILE
Definition: ata_shared.h:309
#define DEVICE_IS_ATAPI
Definition: ata_shared.h:165
@ AtaRequestFailed
Definition: ata_shared.h:77
FORCEINLINE BOOLEAN IsPowerOfTwo(_In_ ULONG x)
Definition: atapi.h:604
#define IDE_STATUS_BUSY
Definition: atapi.h:132
#define IDE_STATUS_DRQ
Definition: atapi.h:128
#define ERR(fmt,...)
Definition: precomp.h:57
#define NULL
Definition: types.h:112
#define SRB_STATUS_ERROR
Definition: srb.h:344
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ASSERT(a)
Definition: mode.c:44
#define KeStallExecutionProcessor(MicroSeconds)
Definition: precomp.h:27
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask)
Definition: intrin_arm.h:57
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3304

Referenced by AtaAhciPortHandleInterrupt().

◆ AtaAhciHandlePortStateChange()

VOID AtaAhciHandlePortStateChange ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  InterruptStatus 
)

Definition at line 1512 of file ahci_hw.c.

1515{
1516 ULONG SataStatus;
1517
1518 if (InterruptStatus & AHCI_PXIRQ_DMPS)
1519 {
1520 ULONG CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
1521
1522 if (CmdStatus & AHCI_PXCMD_MPSP)
1523 {
1524 WARN("CH %lu: Mechanical presence switch has changed %08lx\n",
1525 ChanData->Channel, CmdStatus);
1526 goto Notify;
1527 }
1528 }
1529
1530 SataStatus = AHCI_PORT_READ(ChanData->IoBase, PxSataStatus) & AHCI_PXSSTS_DET_MASK;
1531 if (SataStatus == AHCI_PXSSTS_DET_PHY_OK)
1532 INFO("CH %lu: Device hot plug detected %08lx\n", ChanData->Channel, SataStatus);
1533 else
1534 INFO("CH %lu: Device removal detected %08lx\n", ChanData->Channel, SataStatus);
1535
1536Notify:
1537 /* Schedule a port reset */
1538 ChanData->PortNotification(AtaBusChangeDetected, ChanData->PortContext);
1539}
#define AHCI_PXSSTS_DET_PHY_OK
Definition: ahci.h:215
#define AHCI_PXIRQ_DMPS
Definition: ahci.h:127
#define AHCI_PXSSTS_DET_MASK
Definition: ahci.h:209
#define AHCI_PXCMD_MPSP
Definition: ahci.h:162
@ AtaBusChangeDetected
Definition: ata_shared.h:76
BOOL WINAPI SHIM_OBJ_NAME() Notify(DWORD fdwReason, PVOID ptr)

Referenced by AtaAhciPortHandleInterrupt().

◆ AtaAhciIdentifyDevice()

ATA_CONNECTION_STATUS AtaAhciIdentifyDevice ( _In_ PVOID  ChannelContext,
_In_ ULONG  DeviceNumber 
)

Definition at line 1236 of file ahci_hw.c.

1239{
1240 PCHANNEL_DATA_AHCI ChanData = ChannelContext;
1242
1243 if (ChanData->ChanInfo & CHANNEL_FLAG_IS_PMP)
1244 {
1245 ATA_CONNECTION_STATUS ConnectionStatus;
1246
1247 ConnectionStatus = AtaAhciPmpIdentifyDeviceBehindPmp(ChanData, DeviceNumber);
1248
1249 /* Enable use of FIS-based switching once the port multiplier has enumerated */
1250 if ((ChanData->ChanInfo & CHANNEL_FLAG_HAS_FBS) &&
1251 (DeviceNumber == (ChanData->TotalPortCount - 1)))
1252 {
1254 AtaAhciFbsControl(ChanData, TRUE);
1256 }
1257
1258 if (ConnectionStatus != CONN_STATUS_DEV_UNKNOWN)
1259 return ConnectionStatus;
1260 }
1261 else
1262 {
1263 ASSERT(DeviceNumber == 0);
1264 }
1265
1267 INFO("CH %lu: Received signature %08lx\n", ChanData->Channel, Signature);
1268
1270 {
1271 AtaAhciAtapiLedControl(ChanData, TRUE);
1272 return CONN_STATUS_DEV_ATAPI;
1273 }
1274
1275 AtaAhciAtapiLedControl(ChanData, FALSE);
1276 return CONN_STATUS_DEV_ATA;
1277}
#define AHCI_PXSIG_MASK
Definition: ahci.h:204
#define AHCI_PXSIG_ATAPI
Definition: ahci.h:197
@ PxSignature
Definition: ahci.h:106
static VOID AtaAhciFbsControl(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ BOOLEAN DoEnable)
Definition: ahci_hw.c:306
static VOID AtaAhciAtapiLedControl(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ BOOLEAN DoEnable)
Definition: ahci_hw.c:288
static ATA_CONNECTION_STATUS AtaAhciPmpIdentifyDeviceBehindPmp(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
Definition: ahci_hw.c:1188
@ CONN_STATUS_DEV_ATA
Definition: ata_shared.h:86
@ CONN_STATUS_DEV_ATAPI
Definition: ata_shared.h:87
_In_ PCHAR _In_ ULONG DeviceNumber
Definition: classpnp.h:1230
static const WCHAR Signature[]
Definition: parser.c:141

◆ AtaAhciIsHbaHotRemoved()

static BOOLEAN AtaAhciIsHbaHotRemoved ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 74 of file ahci_hw.c.

76{
77 PATA_CONTROLLER Controller = ChanData->Controller;
78 BOOLEAN WasRemoved;
79
80 /* Check if the HBA has been hot-removed to avoid timeouts on all ports */
81 WasRemoved = (AHCI_HBA_READ(Controller->IoBase, HbaAhciVersion) == 0xFFFFFFFF);
82 if (WasRemoved)
83 {
84 ERR("CH %lu: AHCI controller %04X:%04X is gone\n",
85 ChanData->Channel,
86 Controller->Pci.VendorID,
87 Controller->Pci.DeviceID);
88 }
89 return WasRemoved;
90}
FORCEINLINE ULONG AHCI_HBA_READ(_In_ PVOID HbaIoBase, _In_ AHCI_HOST_BUS_ADAPTER_REGISTER Register)
Definition: ahci.h:529
@ HbaAhciVersion
Definition: ahci.h:87
PVOID IoBase
Definition: pciidex.h:194
struct _ATA_CONTROLLER::@1179 Pci

Referenced by AtaAhciEnumerateChannel(), AtaAhciHandleFatalError(), AtaAhciStopCommandListProcessAndWait(), AtaAhciStopFisReceiveProcessAndWait(), and AtaAhciWaitForDeviceReady().

◆ AtaAhciPerformCommandListOverride()

static BOOLEAN AtaAhciPerformCommandListOverride ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 267 of file ahci_hw.c.

269{
270 ULONG CmdStatus;
271
272 if (!(ChanData->Controller->AhciCapabilities & AHCI_CAP_SCLO))
273 return TRUE;
274
275 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
276 CmdStatus |= AHCI_PXCMD_CLO;
277 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
278
279 return AtaAhciPollRegister(ChanData->IoBase,
282 0,
284}
#define AHCI_PXCMD_CLO
Definition: ahci.h:152
#define AHCI_CAP_SCLO
Definition: ahci.h:328
#define AHCI_DELAY_CLO_CLEAR
Definition: ahci.h:36
static BOOLEAN AtaAhciPollRegister(_In_ PVOID IoBase, _In_ AHCI_PORT_REGISTER Register, _In_ ULONG Mask, _In_ ULONG Value, _In_range_(>, 0) ULONG TimeOut)
Definition: ahci_hw.c:21

Referenced by AtaAhciEnterIdleState(), AtaAhciEnumerateChannel(), AtaAhciPmpDetect(), AtaAhciPostRequestPolled(), and AtaAhciStopDma().

◆ AtaAhciPhyCheckConnection()

static ATA_CONNECTION_STATUS AtaAhciPhyCheckConnection ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 889 of file ahci_hw.c.

891{
892 ATA_CONNECTION_STATUS ConnectionStatus;
893 ULONG RetryCount;
894
895 for (RetryCount = 0; RetryCount < 2; ++RetryCount)
896 {
897 /* Suspend DMA engine and wait for port idle */
898 if (!AtaAhciEnterIdleState(ChanData))
899 {
900 /*
901 * We can skip the ST bit clearing part while the port in a fatal error condition.
902 * Transmit a COMRESET to recover.
903 */
904 AtaAhciSendComReset(ChanData);
905
906 ConnectionStatus = CONN_STATUS_FAILURE;
907 continue;
908 }
909
911 AtaAhciSpinUp(ChanData);
912
913 /* Enable FIS reception from the device */
915
916 /* Start device detection */
917 AtaAhciSendComReset(ChanData);
918
919 if (!AtaAhciPhyCheckDevicePresence(ChanData))
920 {
921 INFO("CH %lu: Device not connected %08lx\n",
922 ChanData->Channel,
923 AHCI_PORT_READ(ChanData->IoBase, PxSataStatus));
924
925 ConnectionStatus = CONN_STATUS_NO_DEVICE;
926 break;
927 }
928
929 INFO("CH %lu: Link up %08lx\n",
930 ChanData->Channel,
931 AHCI_PORT_READ(ChanData->IoBase, PxSataStatus));
932
933 /* Determine if communication is established */
934 if (!AtaAhciPhyWaitForReady(ChanData))
935 {
936 WARN("CH %lu: Unable to establish link %08lx\n",
937 ChanData->Channel,
938 AHCI_PORT_READ(ChanData->IoBase, PxSataStatus));
939
940 ConnectionStatus = CONN_STATUS_FAILURE;
941 continue;
942 }
943
944 /* Required for a D2H FIS */
945 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
946 /* AtaChanEnableInterruptsSync(ChanData, TRUE); */
947
949 {
950 WARN("CH %lu: Wait for ready failed %08lx\n",
951 ChanData->Channel,
952 AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData));
953
954 ConnectionStatus = CONN_STATUS_FAILURE;
955 continue;
956 }
957
958 INFO("CH %lu: Device is ready %08lx\n",
959 ChanData->Channel,
960 AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData));
961
962 ConnectionStatus = CONN_STATUS_DEV_UNKNOWN;
963 break;
964 }
965
966 return ConnectionStatus;
967}
#define AHCI_DELAY_READY_DRIVE
Definition: ahci.h:32
static BOOLEAN AtaAhciEnterIdleState(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:351
static BOOLEAN AtaAhciWaitForDeviceReady(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG TimeOut)
Definition: ahci_hw.c:490
static BOOLEAN AtaAhciPhyWaitForReady(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:478
static VOID AtaAhciStartFisReceiveProcessAndWait(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:224
static VOID AtaAhciSendComReset(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:94
static VOID AtaAhciSetupDmaMemoryAddress(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:387
static BOOLEAN AtaAhciPhyCheckDevicePresence(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:448
static VOID AtaAhciSpinUp(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:411
@ CONN_STATUS_NO_DEVICE
Definition: ata_shared.h:84

Referenced by AtaAhciEnumerateChannel().

◆ AtaAhciPhyCheckDevicePresence()

static BOOLEAN AtaAhciPhyCheckDevicePresence ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 448 of file ahci_hw.c.

450{
451 ULONG i, SataStatus;
452
453 /* Do a quick check first (100 us) */
454 for (i = 0; i < 10; ++i)
455 {
456 SataStatus = AHCI_PORT_READ(ChanData->IoBase, PxSataStatus) & AHCI_PXSSTS_DET_MASK;
457 if (SataStatus != AHCI_PXSSTS_DET_NO_DEVICE)
458 return TRUE;
459
461 }
462
463 /* Retry after the time interval */
464 for (i = 0; i < AHCI_DELAY_DET_PRESENCE; ++i)
465 {
466 SataStatus = AHCI_PORT_READ(ChanData->IoBase, PxSataStatus) & AHCI_PXSSTS_DET_MASK;
467 if (SataStatus != AHCI_PXSSTS_DET_NO_DEVICE)
468 return TRUE;
469
470 AtaSleep();
471 }
472
473 return FALSE;
474}
#define AHCI_PXSSTS_DET_NO_DEVICE
Definition: ahci.h:213
#define AHCI_DELAY_DET_PRESENCE
Definition: ahci.h:30
VOID AtaSleep(VOID)
Definition: pciidex.c:100

Referenced by AtaAhciPhyCheckConnection().

◆ AtaAhciPhyEnterListenMode()

static VOID AtaAhciPhyEnterListenMode ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 244 of file ahci_hw.c.

246{
247 ULONG CmdStatus, SataControl;
248
249 if (!(ChanData->Controller->AhciCapabilities & AHCI_CAP_SSS))
250 return;
251
252 INFO("CH %lu: Enter listen mode\n", ChanData->Channel);
253
255
256 SataControl = AHCI_PORT_READ(ChanData->IoBase, PxSataControl);
257 SataControl &= ~AHCI_PXCTL_DET_MASK;
258 AHCI_PORT_WRITE(ChanData->IoBase, PxSataControl, SataControl);
259
260 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
261 CmdStatus &= ~(AHCI_PXCMD_SUD | AHCI_PXCMD_ICC_MASK);
262 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
263}
#define AHCI_PXCMD_ICC_MASK
Definition: ahci.h:171
#define AHCI_PXCMD_SUD
Definition: ahci.h:150
#define AHCI_CAP_SSS
Definition: ahci.h:331

Referenced by AtaAhciEnumerateChannel().

◆ AtaAhciPhyWaitForReady()

static BOOLEAN AtaAhciPhyWaitForReady ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 478 of file ahci_hw.c.

480{
481 return AtaAhciPollRegister(ChanData->IoBase,
486}
#define AHCI_DELAY_DET_STABLE
Definition: ahci.h:31

Referenced by AtaAhciPhyCheckConnection().

◆ AtaAhciPmpCheckSendComReset()

static BOOLEAN AtaAhciPmpCheckSendComReset ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  PortNumber 
)
static

Definition at line 1053 of file ahci_hw.c.

1056{
1057 ULONG SataControl;
1058 UCHAR SrbStatus;
1059
1060 INFO("CH %lu: Transmit a COMRESET on the interface\n", ChanData->Channel);
1061
1062 /* Clear errors */
1063 SrbStatus = AtaAhciPmpWrite(ChanData, PortNumber, ATA_SERROR, 0xFFFFFFFF);
1064 if (SrbStatus != SRB_STATUS_SUCCESS)
1065 return FALSE;
1066
1067 SataControl = AHCI_PXCTL_DET_RESET;
1068 SrbStatus = AtaAhciPmpWrite(ChanData, PortNumber, ATA_SCONTROL, SataControl);
1069 if (SrbStatus != SRB_STATUS_SUCCESS)
1070 return FALSE;
1071
1073
1074 SataControl &= ~AHCI_PXCTL_DET_MASK;
1075 SataControl |= AHCI_PXCTL_DET_IDLE;
1076 SrbStatus = AtaAhciPmpWrite(ChanData, PortNumber, ATA_SCONTROL, SataControl);
1077 if (SrbStatus != SRB_STATUS_SUCCESS)
1078 return FALSE;
1079
1080 /* Clear errors */
1081 SrbStatus = AtaAhciPmpWrite(ChanData, PortNumber, ATA_SERROR, 0xFFFFFFFF);
1082 if (SrbStatus != SRB_STATUS_SUCCESS)
1083 return FALSE;
1084
1085 return TRUE;
1086}
#define AHCI_PXCTL_DET_IDLE
Definition: ahci.h:236
#define AHCI_PXCTL_DET_RESET
Definition: ahci.h:237
@ ATA_SCONTROL
Definition: ahci.h:55
@ ATA_SERROR
Definition: ahci.h:54
static UCHAR AtaAhciPmpWrite(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ UCHAR PortNumber, _In_ USHORT Register, _In_ ULONG Value)
Definition: ahci_hw.c:679
#define SRB_STATUS_SUCCESS
Definition: srb.h:341
ULONG PortNumber
Definition: storport.c:18
unsigned char UCHAR
Definition: typedefs.h:53

Referenced by AtaPmpCheckConnection().

◆ AtaAhciPmpDetect()

static ATA_CONNECTION_STATUS AtaAhciPmpDetect ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ PBOOLEAN  CheckForPmp 
)
static

Definition at line 800 of file ahci_hw.c.

803{
804 ULONG CmdStatus, Signature;
805 UCHAR SrbStatus;
806
807 /* Indicate a PMP */
808 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
809 CmdStatus |= AHCI_PXCMD_PMA;
810 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
811
812 /* Turn off FIS-based switching prior to issuing the software reset */
813 AtaAhciFbsControl(ChanData, FALSE);
814
815 /* Start the command list DMA engine */
818
819 /* BSY and DRQ must be cleared prior to issuing the software reset */
821 {
822 WARN("CH %lu: Wait for ready failed %08lx\n",
823 ChanData->Channel,
824 AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData));
825
826 /* Transmit a COMRESET to recover */
827 AtaAhciSendComReset(ChanData);
828
829 return CONN_STATUS_FAILURE;
830 }
831
832 /*
833 * Issue a software reset.
834 *
835 * Real PMP devices come up faster than ATA/ATAPI devices,
836 * keep the timeout as small as possible.
837 */
838 SrbStatus = AtaAhciSendResetFis(ChanData, AHCI_PMP_CONTROL_PORT, TRUE, 1000);
839 if (SrbStatus != SRB_STATUS_SUCCESS)
840 {
841 INFO("CH %lu: Soft reset failed %02x\n", ChanData->Channel, SrbStatus);
842
843 /*
844 * This command may timeout if a PMP-capable port indicates device presence
845 * and the connected device is not a port multiplier.
846 * As a result, the system boot time may increase by (ActivePortCount * TimeOutMs).
847 * We skip PMP detection upon the first timeout, there is nothing more that can be done.
848 */
849 if (SrbStatus == SRB_STATUS_TIMEOUT)
850 {
851 /* Not a PMP device */
852 *CheckForPmp = FALSE;
853 INFO("CH %lu: Seems to have no PMP device\n", ChanData->Channel);
854 }
855 return CONN_STATUS_FAILURE;
856 }
857
858 /* SRST pulse width */
860
861 SrbStatus = AtaAhciSendResetFis(ChanData, AHCI_PMP_CONTROL_PORT, FALSE, 2000);
862 if (SrbStatus != SRB_STATUS_SUCCESS)
863 {
864 INFO("CH %lu: Soft reset failed %02x\n", ChanData->Channel, SrbStatus);
865
866 if (SrbStatus == SRB_STATUS_TIMEOUT)
867 {
868 /* Not a PMP device */
869 *CheckForPmp = FALSE;
870 INFO("CH %lu: Seems to have no PMP device\n", ChanData->Channel);
871 }
872 return CONN_STATUS_FAILURE;
873 }
874
875 /* SRST pulse width */
877
878 Signature = AHCI_PORT_READ(ChanData->IoBase, PxSignature);
879
880 INFO("CH %lu: Received signature %08lx\n", ChanData->Channel, Signature);
883
885}
#define AHCI_DELAY_PMP_READY_DRIVE
Definition: ahci.h:33
#define AHCI_PXCMD_PMA
Definition: ahci.h:160
#define AHCI_PXSIG_PMP
Definition: ahci.h:198
#define AHCI_PMP_CONTROL_PORT
Definition: ahci.h:18
static UCHAR AtaAhciSendResetFis(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ UCHAR PortNumber, _In_ BOOLEAN AssertSRST, _In_range_(>, 0) ULONG TimeOutMs)
Definition: ahci_hw.c:611
#define SRB_STATUS_TIMEOUT
Definition: srb.h:349

Referenced by AtaAhciEnumerateChannel().

◆ AtaAhciPmpDisableSilXmitEarlyAck()

static BOOLEAN AtaAhciPmpDisableSilXmitEarlyAck ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 711 of file ahci_hw.c.

713{
714 UCHAR SrbStatus;
715 ULONG Value;
716
717 SrbStatus = AtaAhciPmpRead(ChanData, AHCI_PMP_CONTROL_PORT, 129, &Value);
718 if (SrbStatus != SRB_STATUS_SUCCESS)
719 return FALSE;
720
721 if (Value & 1)
722 {
723 Value &= ~1;
724 SrbStatus = AtaAhciPmpWrite(ChanData, AHCI_PMP_CONTROL_PORT, 129, Value);
725 if (SrbStatus != SRB_STATUS_SUCCESS)
726 return FALSE;
727 }
728
729 return TRUE;
730}
static UCHAR AtaAhciPmpRead(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ UCHAR PortNumber, _In_ USHORT Register, _Out_ PULONG Result)
Definition: ahci_hw.c:642
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413

Referenced by AtaAhciPmpIdentifyPmp().

◆ AtaAhciPmpIdentifyDeviceBehindPmp()

static ATA_CONNECTION_STATUS AtaAhciPmpIdentifyDeviceBehindPmp ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  PortNumber 
)
static

Definition at line 1188 of file ahci_hw.c.

1191{
1192 ATA_CONNECTION_STATUS ConnectionStatus;
1193 UCHAR SrbStatus;
1194 ULONG RetryCount;
1195
1196 ASSERT(!(ChanData->ChanInfo & CHANNEL_FLAG_FBS_ENABLED));
1197
1198 ConnectionStatus = AtaPmpCheckConnection(ChanData, PortNumber);
1199 if (ConnectionStatus != CONN_STATUS_DEV_UNKNOWN)
1200 return ConnectionStatus;
1201
1202 /* Issue a soft reset */
1203 for (RetryCount = 0; RetryCount < 2; RetryCount++)
1204 {
1205 SrbStatus = AtaAhciPmpWrite(ChanData, PortNumber, ATA_SERROR, 0xFFFFFFFF);
1206 if (SrbStatus == SRB_STATUS_ERROR)
1207 continue;
1208 else if (SrbStatus != SRB_STATUS_SUCCESS)
1209 goto Failure;
1210
1211 SrbStatus = AtaAhciSendResetFis(ChanData, PortNumber, TRUE, 1000);
1212 if (SrbStatus == SRB_STATUS_ERROR)
1213 continue;
1214 else if (SrbStatus != SRB_STATUS_SUCCESS)
1215 goto Failure;
1216
1217 /* SRST pulse width */
1219
1220 SrbStatus = AtaAhciSendResetFis(ChanData, PortNumber, FALSE, 1000);
1221 if (SrbStatus == SRB_STATUS_ERROR)
1222 continue;
1223 else if (SrbStatus != SRB_STATUS_SUCCESS)
1224 goto Failure;
1225 }
1226
1228
1229Failure:
1230 WARN("CH %lu: PMP port %lu soft reset failed %02x\n",
1231 ChanData->Channel, PortNumber, SrbStatus);
1232 return CONN_STATUS_FAILURE;
1233}
static ATA_CONNECTION_STATUS AtaPmpCheckConnection(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
Definition: ahci_hw.c:1162

Referenced by AtaAhciIdentifyDevice().

◆ AtaAhciPmpIdentifyPmp()

static BOOLEAN AtaAhciPmpIdentifyPmp ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_Out_ PULONG  PortCountResult 
)
static

Definition at line 734 of file ahci_hw.c.

737{
738 ULONG ProductId, RevisionInfo, PortCount;
739 UCHAR SrbStatus;
740
741 *PortCountResult = 0;
742
743 SrbStatus = AtaAhciPmpRead(ChanData, AHCI_PMP_CONTROL_PORT, PmpProductId, &ProductId);
744 if (SrbStatus != SRB_STATUS_SUCCESS)
745 return FALSE;
746
747 SrbStatus = AtaAhciPmpRead(ChanData, AHCI_PMP_CONTROL_PORT, PmpRevisionInfo, &RevisionInfo);
748 if (SrbStatus != SRB_STATUS_SUCCESS)
749 return FALSE;
750
751 SrbStatus = AtaAhciPmpRead(ChanData, AHCI_PMP_CONTROL_PORT, PmpPortInfo, &PortCount);
752 if (SrbStatus != SRB_STATUS_SUCCESS)
753 return FALSE;
754
755 INFO("CH %lu: PMP %08lX:%08lX %lu ports\n",
756 ChanData->Channel,
757 ProductId,
758 RevisionInfo,
759 PortCount);
760
761 PortCount &= AHCI_MAX_PMP_DEVICES;
762
763 /* From FreeBSD: Hide pseudo ATA devices from the driver */
764 switch (ProductId)
765 {
766 case 0x37261095:
767 case 0x38261095:
768 {
770 return FALSE;
771
772 if (PortCount == 6)
773 PortCount = 5;
774 break;
775 }
776
777 case 0x47261095:
778 if (PortCount == 7)
779 PortCount = 5;
780 break;
781
782 case 0x57231095:
783 case 0x57331095:
784 case 0x57341095:
785 case 0x57441095:
786 if (PortCount > 0)
787 --PortCount;
788 break;
789
790 default:
791 break;
792 }
793 *PortCountResult = PortCount;
794
795 return TRUE;
796}
@ PmpProductId
Definition: ahci.h:67
@ PmpPortInfo
Definition: ahci.h:69
@ PmpRevisionInfo
Definition: ahci.h:68
static BOOLEAN AtaAhciPmpDisableSilXmitEarlyAck(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:711

Referenced by AtaAhciEnumerateChannel().

◆ AtaAhciPmpPhyCheckDevicePresence()

static ATA_CONNECTION_STATUS AtaAhciPmpPhyCheckDevicePresence ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  PortNumber 
)
static

Definition at line 1090 of file ahci_hw.c.

1093{
1094 ULONG i, SataStatus;
1095 UCHAR SrbStatus;
1096
1097 for (i = 0; i < AHCI_DELAY_PMP_DET_PRESENSE; ++i)
1098 {
1099 SrbStatus = AtaAhciPmpRead(ChanData, PortNumber, ATA_SSTATUS, &SataStatus);
1100 if (SrbStatus == SRB_STATUS_ERROR)
1101 continue;
1102 else if (SrbStatus != SRB_STATUS_SUCCESS)
1103 return CONN_STATUS_FAILURE;
1104
1105 if ((SataStatus & AHCI_PXSSTS_DET_MASK) != AHCI_PXSSTS_DET_NO_DEVICE)
1106 {
1107 INFO("CH %lu: PMP device %lu link up %08lx\n",
1108 ChanData->Channel,
1109 PortNumber,
1110 SataStatus);
1112 }
1113
1114 AtaSleep();
1115 }
1116
1117 INFO("CH %lu: PMP device %lu not connected %08lx\n",
1118 ChanData->Channel,
1119 PortNumber,
1120 SataStatus);
1121 return CONN_STATUS_NO_DEVICE;
1122}
#define AHCI_DELAY_PMP_DET_PRESENSE
Definition: ahci.h:34
@ ATA_SSTATUS
Definition: ahci.h:53

Referenced by AtaPmpCheckConnection().

◆ AtaAhciPmpPhyWaitForReady()

static ATA_CONNECTION_STATUS AtaAhciPmpPhyWaitForReady ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  PortNumber 
)
static

Definition at line 1126 of file ahci_hw.c.

1129{
1130 ULONG i, SataStatus;
1131 UCHAR SrbStatus;
1132
1133 for (i = 0; i < AHCI_DELAY_PMP_DET_PRESENSE; ++i)
1134 {
1135 SrbStatus = AtaAhciPmpRead(ChanData, PortNumber, ATA_SSTATUS, &SataStatus);
1136 if (SrbStatus == SRB_STATUS_ERROR)
1137 continue;
1138 else if (SrbStatus != SRB_STATUS_SUCCESS)
1139 return CONN_STATUS_FAILURE;
1140
1141 if ((SataStatus & AHCI_PXSSTS_DET_MASK) == AHCI_PXSSTS_DET_PHY_OK)
1142 {
1143 INFO("CH %lu: PMP device %lu link up %08lx\n",
1144 ChanData->Channel,
1145 PortNumber,
1146 SataStatus);
1148 }
1149
1150 AtaSleep();
1151 }
1152
1153 INFO("CH %lu: PMP device %lu unable to establish link %08lx\n",
1154 ChanData->Channel,
1155 PortNumber,
1156 SataStatus);
1157 return CONN_STATUS_NO_DEVICE;
1158}

Referenced by AtaPmpCheckConnection().

◆ AtaAhciPmpRead()

static UCHAR AtaAhciPmpRead ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ UCHAR  PortNumber,
_In_ USHORT  Register,
_Out_ PULONG  Result 
)
static

Definition at line 642 of file ahci_hw.c.

647{
648 PAHCI_COMMAND_TABLE CommandTable = ChanData->CommandTable[AHCI_INTERNAL_SLOT];
649 PAHCI_COMMAND_HEADER CommandHeader = &ChanData->CommandList->CommandHeader[AHCI_INTERNAL_SLOT];
650 PAHCI_FIS_HOST_TO_DEVICE H2dFis = &CommandTable->HostToDeviceFis;
651 PAHCI_FIS_DEVICE_TO_HOST D2hFis = &ChanData->ReceivedFis->DeviceToHostFis;
652 UCHAR SrbStatus;
653
654 RtlZeroMemory(H2dFis, sizeof(*H2dFis));
657 H2dFis->Control = IDE_DC_ALWAYS;
659 H2dFis->Features = (UCHAR)Register;
660 H2dFis->FeaturesEx = (UCHAR)(Register >> 8);
662
663 CommandHeader->PrdByteCount = 0;
664 CommandHeader->Control = (sizeof(*H2dFis) / sizeof(ULONG)) |
666
667 SrbStatus = AtaAhciPostRequestPolled(ChanData, 1000);
668
669 *Result = D2hFis->SectorCount |
670 (D2hFis->LbaLow << 8) |
671 (D2hFis->LbaMid << 16) |
672 (D2hFis->LbaHigh << 24);
673
674 return SrbStatus;
675}
#define IDE_COMMAND_READ_PORT_MULTIPLIER
Definition: ahci.h:48
#define UPDATE_COMMAND
Definition: ahci.h:360
#define AHCI_COMMAND_HEADER_PMP_SHIFT
Definition: ahci.h:480
#define AHCI_FIS_REGISTER_HOST_TO_DEVICE
Definition: ahci.h:39
#define AHCI_INTERNAL_SLOT
Definition: ahci.h:60
static UCHAR AtaAhciPostRequestPolled(_In_ PCHANNEL_DATA_AHCI ChanData, _In_range_(>, 0) ULONG TimeOutMs)
Definition: ahci_hw.c:535
#define IDE_DC_ALWAYS
Definition: hwidep.h:54
#define IDE_DRIVE_SELECT
Definition: hwidep.h:56
ULONG PrdByteCount
Definition: ahci.h:482
AHCI_FIS_HOST_TO_DEVICE HostToDeviceFis
Definition: ahci.h:512
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409

Referenced by AtaAhciPmpDisableSilXmitEarlyAck(), AtaAhciPmpIdentifyPmp(), AtaAhciPmpPhyCheckDevicePresence(), and AtaAhciPmpPhyWaitForReady().

◆ AtaAhciPmpWrite()

static UCHAR AtaAhciPmpWrite ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ UCHAR  PortNumber,
_In_ USHORT  Register,
_In_ ULONG  Value 
)
static

Definition at line 679 of file ahci_hw.c.

684{
685 PAHCI_COMMAND_TABLE CommandTable = ChanData->CommandTable[AHCI_INTERNAL_SLOT];
686 PAHCI_COMMAND_HEADER CommandHeader = &ChanData->CommandList->CommandHeader[AHCI_INTERNAL_SLOT];
687 PAHCI_FIS_HOST_TO_DEVICE H2dFis = &CommandTable->HostToDeviceFis;
688
689 RtlZeroMemory(H2dFis, sizeof(*H2dFis));
692 H2dFis->Control = IDE_DC_ALWAYS;
694 H2dFis->Features = (UCHAR)Register;
695 H2dFis->FeaturesEx = (UCHAR)(Register >> 8);
696 H2dFis->SectorCount = (UCHAR)Value;
697 H2dFis->LbaLow = (UCHAR)(Value >> 8);
698 H2dFis->LbaMid = (UCHAR)(Value >> 16);
699 H2dFis->LbaHigh = (UCHAR)(Value >> 24);
701
702 CommandHeader->PrdByteCount = 0;
703 CommandHeader->Control = (sizeof(*H2dFis) / sizeof(ULONG)) |
705
706 return AtaAhciPostRequestPolled(ChanData, 1000);
707}
#define IDE_COMMAND_WRITE_PORT_MULTIPLIER
Definition: ahci.h:49

Referenced by AtaAhciPmpCheckSendComReset(), AtaAhciPmpDisableSilXmitEarlyAck(), and AtaAhciPmpIdentifyDeviceBehindPmp().

◆ AtaAhciPollRegister()

static BOOLEAN AtaAhciPollRegister ( _In_ PVOID  IoBase,
_In_ AHCI_PORT_REGISTER  Register,
_In_ ULONG  Mask,
_In_ ULONG  Value,
_In_range_(>, 0) ULONG  TimeOut 
)
static

Definition at line 21 of file ahci_hw.c.

27{
28 ULONG i, Data;
29
30 ASSUME(TimeOut > 0);
31
32 /* Do a quick check first (100 us) */
33 for (i = 0; i < 10; ++i)
34 {
35 Data = AHCI_PORT_READ(IoBase, Register);
36 if ((Data & Mask) == Value)
37 return TRUE;
38
40 }
41
42 /* Retry after the time interval */
43 for (i = 0; i < TimeOut; i++)
44 {
45 Data = AHCI_PORT_READ(IoBase, Register);
46 if ((Data & Mask) == Value)
47 return TRUE;
48
49 AtaSleep();
50 }
51
52 return FALSE;
53}
#define ASSUME(cond)
Definition: atapi.h:165
unsigned int Mask
Definition: fpcontrol.c:82

Referenced by AtaAhciPerformCommandListOverride(), AtaAhciPhyWaitForReady(), AtaAhciPostRequestPolled(), AtaAhciSpinUp(), AtaAhciStartFisReceiveProcessAndWait(), AtaAhciStopCommandListProcessAndWait(), and AtaAhciStopFisReceiveProcessAndWait().

◆ AtaAhciPostRequestPolled()

static UCHAR AtaAhciPostRequestPolled ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_range_(>, 0) ULONG  TimeOutMs 
)
static

Definition at line 535 of file ahci_hw.c.

538{
539 ULONG InterruptStatus, TaskFileData;
540 UCHAR SrbStatus;
541
542 ASSERT((ChanData->ActiveSlotsBitmap == 0) && (ChanData->ActiveQueuedSlotsBitmap == 0));
543
544 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
545
546 AHCI_PORT_WRITE(ChanData->IoBase, PxCommandIssue, 1 << AHCI_INTERNAL_SLOT);
547 if (!AtaAhciPollRegister(ChanData->IoBase,
550 0,
551 TimeOutMs / PORT_TIMER_TICK_MS))
552 {
553 ERR("CH %lu: Internal request timed out\n", ChanData->Channel);
554
555 /* Clear the active DMA command */
559
560 SrbStatus = SRB_STATUS_TIMEOUT;
561 goto Done;
562 }
563
564 InterruptStatus = AHCI_PORT_READ(ChanData->IoBase, PxInterruptStatus);
565
566 /* Minimal basic recovery for port */
567 if (InterruptStatus & AHCI_PXIRQ_FATAL_ERROR)
568 {
570 {
571 ERR("CH %lu: Failed to stop the command list DMA engine\n", ChanData->Channel);
572 SrbStatus = SRB_STATUS_TIMEOUT;
573 goto Done;
574 }
575
576 TaskFileData = AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData);
577 if (TaskFileData & (IDE_STATUS_BUSY | IDE_STATUS_DRQ))
578 {
579 ERR("CH %lu: Busy TFD %08lx\n", ChanData->Channel, TaskFileData);
580 SrbStatus = SRB_STATUS_TIMEOUT;
581 goto Done;
582 }
583
584 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError,
585 AHCI_PORT_READ(ChanData->IoBase, PxSataError));
586
588
589 SrbStatus = SRB_STATUS_ERROR;
590 goto Done;
591 }
592
593 SrbStatus = SRB_STATUS_SUCCESS;
594
595Done:
596 if (SrbStatus == SRB_STATUS_SUCCESS)
597 TRACE("CH %lu: Completed internal request\n", ChanData->Channel);
598 else
599 INFO("CH %lu: Internal request failed %02x\n", ChanData->Channel, SrbStatus);
600
601 /* Clear port interrupts */
602 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
603 AHCI_PORT_WRITE(ChanData->IoBase, PxInterruptStatus, 0xFFFFFFFF);
604 AHCI_HBA_WRITE(ChanData->Controller->IoBase, HbaInterruptStatus, 1 << ChanData->Channel);
605
606 return SrbStatus;
607}
#define AHCI_PXIRQ_FATAL_ERROR
Definition: ahci.h:140
@ PxCommandIssue
Definition: ahci.h:111
#define PORT_TIMER_TICK_MS
Definition: pciidex.h:54
#define TRACE(s)
Definition: solgame.cpp:4

Referenced by AtaAhciPmpRead(), AtaAhciPmpWrite(), and AtaAhciSendResetFis().

◆ AtaAhciResetChannel()

VOID AtaAhciResetChannel ( _In_ PVOID  ChannelContext)

Definition at line 1289 of file ahci_hw.c.

1291{
1292 /* The channel reset is done unconditionally in AtaAhciEnumerateChannel() */
1293 NOTHING;
1294}
#define NOTHING
Definition: input_list.c:10

◆ AtaAhciSaveReceivedFisArea()

static VOID AtaAhciSaveReceivedFisArea ( _In_ AHCI_FIS_DEVICE_TO_HOST *__restrict  Fis,
_Inout_ ATA_DEVICE_REQUEST *__restrict  Request 
)
static

Captures and saves a dump of the AHCI task file registers, except the values in the Fis->Status and Fis->Error fields.

Definition at line 1302 of file ahci_hw.c.

1305{
1306 PATA_TASKFILE TaskFile = &Request->Output;
1307
1308 TaskFile->SectorCount = Fis->SectorCount;
1309 TaskFile->LowLba = Fis->LbaLow;
1310 TaskFile->MidLba = Fis->LbaMid;
1311 TaskFile->HighLba = Fis->LbaHigh;
1312 TaskFile->DriveSelect = Fis->Device;
1313
1314 if (Request->Flags & REQUEST_FLAG_LBA48)
1315 {
1316 TaskFile->FeatureEx = 0; // FIS byte 11 is reserved
1317 TaskFile->SectorCountEx = Fis->SectorCountEx;
1318 TaskFile->LowLbaEx = Fis->LbaLowEx;
1319 TaskFile->MidLbaEx = Fis->LbaMidEx;
1320 TaskFile->HighLbaEx = Fis->LbaHighEx;
1321 }
1322}
#define REQUEST_FLAG_LBA48
Definition: hwidep.h:167
UCHAR SectorCountEx
Definition: ata_shared.h:200
UCHAR SectorCount
Definition: hwidep.h:151
UCHAR MidLba
LBA bits 8-15.
Definition: hwidep.h:153
UCHAR LowLbaEx
LBA bits 24-31.
Definition: ata_shared.h:195
UCHAR HighLba
LBA bits 16-23.
Definition: hwidep.h:154
UCHAR FeatureEx
Definition: ata_shared.h:198
UCHAR HighLbaEx
LBA bits 40-47.
Definition: ata_shared.h:197
UCHAR DriveSelect
Definition: hwidep.h:146
UCHAR LowLba
LBA bits 0-7.
Definition: hwidep.h:152
UCHAR MidLbaEx
LBA bits 32-39.
Definition: ata_shared.h:196

Referenced by AtaAhciSaveTaskFile().

◆ AtaAhciSaveTaskFile()

VOID AtaAhciSaveTaskFile ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_Inout_ PATA_DEVICE_REQUEST  Request,
_In_ BOOLEAN  ProcessErrorStatus 
)

Definition at line 1325 of file ahci_hw.c.

1329{
1330 union
1331 {
1332 PAHCI_FIS_PIO_SETUP PioSetup;
1333 PAHCI_FIS_DEVICE_TO_HOST DeviceToHost;
1334 } Fis;
1335 PAHCI_RECEIVED_FIS ReceivedFis;
1336
1337 ReceivedFis = ChanData->ReceivedFis;
1338
1339 if (ChanData->ChanInfo & CHANNEL_FLAG_FBS_ENABLED)
1340 ReceivedFis += DEV_NUMBER(Request->Device);
1341
1343
1344 if (ProcessErrorStatus)
1345 {
1346 /*
1347 * Device to Host FIS on failed commands.
1348 * The Request->Output.Status and Request->Output.Error fields should have saved earlier.
1349 */
1350 Fis.DeviceToHost = &ReceivedFis->DeviceToHostFis;
1351 }
1352 else
1353 {
1354 /* Check for successful queued commands (see SATA 3.5 specification 11.14) */
1355 if (Request->Flags & REQUEST_FLAG_NCQ)
1356 {
1357 PAHCI_FIS_SET_DEVICE_BITS SetDeviceBitsFis;
1358
1359 /*
1360 * The SDB FIS was received and we do not have enough information
1361 * for the rest of the registers. Emulate the content of the task file registers.
1362 */
1363 RtlCopyMemory(&Request->Output, &Request->TaskFile, sizeof(Request->TaskFile));
1364
1365 SetDeviceBitsFis = &ReceivedFis->SetDeviceBitsFis;
1366 Request->Output.Status = SetDeviceBitsFis->Status;
1367 Request->Output.Error = SetDeviceBitsFis->Error;
1368 return;
1369 }
1370 /* Check for successful PIO Data-In commands (see SATA 3.5 specification 11.8) */
1371 else if (!(Request->Flags & REQUEST_FLAG_DMA) && (Request->Flags & REQUEST_FLAG_DATA_IN))
1372 {
1373 /* In this case we have received a PIO Setup FIS */
1374 Fis.PioSetup = &ReceivedFis->PioSetupFis;
1375
1376 Request->Output.Status = Fis.PioSetup->EStatus;
1377 Request->Output.Error = Fis.PioSetup->Error;
1378 }
1379 else
1380 {
1381 ULONG TaskFileData;
1382
1383 /* Otherwise, we have received a Device to Host FIS */
1384 Fis.DeviceToHost = &ReceivedFis->DeviceToHostFis;
1385
1386 TaskFileData = AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData);
1387 Request->Output.Status = (TaskFileData & AHCI_PXTFD_STATUS_MASK);
1388 Request->Output.Error =
1390 }
1391 }
1392
1393 AtaAhciSaveReceivedFisArea(Fis.DeviceToHost, Request);
1394}
static VOID AtaAhciSaveReceivedFisArea(_In_ AHCI_FIS_DEVICE_TO_HOST *__restrict Fis, _Inout_ ATA_DEVICE_REQUEST *__restrict Request)
Captures and saves a dump of the AHCI task file registers, except the values in the Fis->Status and F...
Definition: ahci_hw.c:1302
#define REQUEST_FLAG_DATA_IN
Definition: ata_shared.h:287
#define REQUEST_FLAG_DMA
Definition: ata_shared.h:278
#define REQUEST_FLAG_HAS_TASK_FILE
Definition: ata_shared.h:312
#define DEV_NUMBER(Device)
Definition: pciidex.h:56
AHCI_FIS_DEVICE_TO_HOST DeviceToHostFis
Definition: ahci.h:454
AHCI_FIS_SET_DEVICE_BITS SetDeviceBitsFis
Definition: ahci.h:457
AHCI_FIS_PIO_SETUP PioSetupFis
Definition: ahci.h:451
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263

Referenced by AtaAhciHandleFatalError(), and AtaAhciPortCompleteCommands().

◆ AtaAhciSendComReset()

static VOID AtaAhciSendComReset ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 94 of file ahci_hw.c.

96{
97 ULONG SataControl;
98
99 INFO("CH %lu: Transmit a COMRESET on the interface\n", ChanData->Channel);
100
101 /* Clear errors */
102 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
103
104 SataControl = AHCI_PORT_READ(ChanData->IoBase, PxSataControl);
105 SataControl &= ~AHCI_PXCTL_DET_MASK;
106 SataControl |= AHCI_PXCTL_DET_RESET;
107 AHCI_PORT_WRITE(ChanData->IoBase, PxSataControl, SataControl);
108
110
111 SataControl = AHCI_PORT_READ(ChanData->IoBase, PxSataControl);
112 SataControl &= ~AHCI_PXCTL_DET_MASK;
113 SataControl |= AHCI_PXCTL_DET_IDLE;
114 AHCI_PORT_WRITE(ChanData->IoBase, PxSataControl, SataControl);
115
116 /* Clear errors */
117 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
118}

Referenced by AtaAhciPhyCheckConnection(), and AtaAhciPmpDetect().

◆ AtaAhciSendResetFis()

static UCHAR AtaAhciSendResetFis ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ UCHAR  PortNumber,
_In_ BOOLEAN  AssertSRST,
_In_range_(>, 0) ULONG  TimeOutMs 
)
static

Definition at line 611 of file ahci_hw.c.

616{
617 PAHCI_COMMAND_TABLE CommandTable = ChanData->CommandTable[AHCI_INTERNAL_SLOT];
618 PAHCI_COMMAND_HEADER CommandHeader = &ChanData->CommandList->CommandHeader[AHCI_INTERNAL_SLOT];
619 PAHCI_FIS_HOST_TO_DEVICE H2dFis = &CommandTable->HostToDeviceFis;
620
621 RtlZeroMemory(H2dFis, sizeof(*H2dFis));
623 H2dFis->Flags = PortNumber;
624 H2dFis->Control = IDE_DC_ALWAYS;
625
626 CommandHeader->PrdByteCount = 0;
627 CommandHeader->Control = (sizeof(*H2dFis) / sizeof(ULONG)) |
629
630 if (AssertSRST)
631 {
633 CommandHeader->Control |= AHCI_COMMAND_HEADER_RESET |
635 }
636
637 return AtaAhciPostRequestPolled(ChanData, TimeOutMs);
638}
#define AHCI_COMMAND_HEADER_CLEAR_BUSY_UPON_OK
Definition: ahci.h:475
#define AHCI_COMMAND_HEADER_RESET
Definition: ahci.h:473
#define IDE_DC_RESET_CONTROLLER
Definition: atapi.h:146

Referenced by AtaAhciPmpDetect(), and AtaAhciPmpIdentifyDeviceBehindPmp().

◆ AtaAhciSetupDmaMemoryAddress()

static VOID AtaAhciSetupDmaMemoryAddress ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 387 of file ahci_hw.c.

389{
390 /* Physical address of the allocated command list */
391 AHCI_PORT_WRITE(ChanData->IoBase, PxCommandListBaseLow, (ULONG)ChanData->Mem.CommandListPhys);
392 if (ChanData->Controller->AhciCapabilities & AHCI_CAP_S64A)
393 {
394 AHCI_PORT_WRITE(ChanData->IoBase,
396 (ULONG)(ChanData->Mem.CommandListPhys >> 32));
397 }
398
399 /* Physical address of the allocated FIS receive area */
400 AHCI_PORT_WRITE(ChanData->IoBase, PxFisBaseLow, (ULONG)ChanData->Mem.ReceivedFisPhys);
401 if (ChanData->Controller->AhciCapabilities & AHCI_CAP_S64A)
402 {
403 AHCI_PORT_WRITE(ChanData->IoBase,
405 (ULONG)(ChanData->Mem.ReceivedFisPhys >> 32));
406 }
407}
#define AHCI_CAP_S64A
Definition: ahci.h:335
@ PxCommandListBaseHigh
Definition: ahci.h:99
@ PxFisBaseHigh
Definition: ahci.h:101
@ PxFisBaseLow
Definition: ahci.h:100
@ PxCommandListBaseLow
Definition: ahci.h:98

Referenced by AtaAhciPhyCheckConnection().

◆ AtaAhciSpinUp()

static VOID AtaAhciSpinUp ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 411 of file ahci_hw.c.

413{
414 ULONG CmdStatus;
415
416 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
417
418 /* Clear the PMA bit once the DMA engine has been stopped */
419 CmdStatus &= ~AHCI_PXCMD_PMA;
420
421 /* Move to the active interface state for the DET value be accurate */
422 CmdStatus &= ~AHCI_PXCMD_ICC_MASK;
423 CmdStatus |= AHCI_PXCMD_ICC_ACTIVE;
424
425 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
426
427 AtaAhciPollRegister(ChanData->IoBase,
432
433 /* Spin-up and power up the device */
434 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
435 if (ChanData->Controller->AhciCapabilities & AHCI_CAP_SSS)
436 {
437 CmdStatus |= AHCI_PXCMD_SUD;
438 }
439 if (CmdStatus & AHCI_PXCMD_CPD)
440 {
441 CmdStatus |= AHCI_PXCMD_POD;
442 }
443 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
444}
#define AHCI_DELAY_INTERFACE_CHANGE
Definition: ahci.h:37
#define AHCI_PXCMD_ICC_IDLE
Definition: ahci.h:173
#define AHCI_PXCMD_CPD
Definition: ahci.h:163
#define AHCI_PXCMD_POD
Definition: ahci.h:151
#define AHCI_PXCMD_ICC_ACTIVE
Definition: ahci.h:174

Referenced by AtaAhciPhyCheckConnection().

◆ AtaAhciStartCommandListProcess()

static VOID AtaAhciStartCommandListProcess ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 137 of file ahci_hw.c.

139{
140 ULONG i, CmdStatus;
141
142 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
143 CmdStatus |= AHCI_PXCMD_ST;
144 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
145
146 /*
147 * We are supposed to wait for the AHCI_PXCMD_CR bit to be set
148 * before interacting with the port again,
149 * but on some AHCI controllers this bit never becomes set.
150 */
151 for (i = 0; i < 10; ++i)
152 {
153 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
154 if (CmdStatus & AHCI_PXCMD_CR)
155 break;
156
158 }
159}

Referenced by AtaAhciEnumerateChannel(), AtaAhciHandleFatalError(), AtaAhciIdentifyDevice(), AtaAhciPmpDetect(), and AtaAhciPostRequestPolled().

◆ AtaAhciStartFisReceiveProcess()

static VOID AtaAhciStartFisReceiveProcess ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 195 of file ahci_hw.c.

197{
198 ULONG CmdStatus;
199
200 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
201 CmdStatus |= AHCI_PXCMD_FRE;
202 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
203}

Referenced by AtaAhciStartFisReceiveProcessAndWait().

◆ AtaAhciStartFisReceiveProcessAndWait()

static VOID AtaAhciStartFisReceiveProcessAndWait ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 224 of file ahci_hw.c.

226{
228
229 if (!AtaAhciPollRegister(ChanData->IoBase,
234 {
235 /* Ignore timeouts, on some AHCI controllers the FR bit never becomes set */
236 WARN("CH %lx: Failed to start the FIS Receive DMA engine %08lx\n",
237 ChanData->Channel,
238 AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus));
239 }
240}
#define AHCI_DELAY_FR_START_STOP
Definition: ahci.h:29
static VOID AtaAhciStartFisReceiveProcess(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:195

Referenced by AtaAhciPhyCheckConnection().

◆ AtaAhciStopCommandListProcess()

static VOID AtaAhciStopCommandListProcess ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 122 of file ahci_hw.c.

124{
125 ULONG CmdStatus;
126
127 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
128 if (CmdStatus & AHCI_PXCMD_ST)
129 {
130 CmdStatus &= ~AHCI_PXCMD_ST;
131 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
132 }
133}

Referenced by AtaAhciHandleFatalError(), and AtaAhciStopCommandListProcessAndWait().

◆ AtaAhciStopCommandListProcessAndWait()

static BOOLEAN AtaAhciStopCommandListProcessAndWait ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 163 of file ahci_hw.c.

165{
167
168 if (AtaAhciIsHbaHotRemoved(ChanData))
169 return FALSE;
170
171 return AtaAhciPollRegister(ChanData->IoBase,
174 0,
176}
#define AHCI_DELAY_CR_START_STOP
Definition: ahci.h:28

Referenced by AtaAhciEnterIdleState(), AtaAhciEnumerateChannel(), AtaAhciIdentifyDevice(), AtaAhciPhyEnterListenMode(), AtaAhciPostRequestPolled(), and AtaAhciStopDma().

◆ AtaAhciStopDma()

VOID AtaAhciStopDma ( _In_ PCHANNEL_DATA_AHCI  ChanData)

Definition at line 1280 of file ahci_hw.c.

Referenced by AtaAhciAttachChannel().

◆ AtaAhciStopFisReceiveProcess()

static VOID AtaAhciStopFisReceiveProcess ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 180 of file ahci_hw.c.

182{
183 ULONG CmdStatus;
184
185 CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
186 if (CmdStatus & AHCI_PXCMD_FRE)
187 {
188 CmdStatus &= ~AHCI_PXCMD_FRE;
189 AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
190 }
191}

Referenced by AtaAhciStopFisReceiveProcessAndWait().

◆ AtaAhciStopFisReceiveProcessAndWait()

static BOOLEAN AtaAhciStopFisReceiveProcessAndWait ( _In_ PCHANNEL_DATA_AHCI  ChanData)
static

Definition at line 207 of file ahci_hw.c.

209{
211
212 if (AtaAhciIsHbaHotRemoved(ChanData))
213 return FALSE;
214
215 return AtaAhciPollRegister(ChanData->IoBase,
218 0,
220}
static VOID AtaAhciStopFisReceiveProcess(_In_ PCHANNEL_DATA_AHCI ChanData)
Definition: ahci_hw.c:180

Referenced by AtaAhciEnterIdleState(), and AtaAhciStopDma().

◆ AtaAhciWaitForDeviceReady()

static BOOLEAN AtaAhciWaitForDeviceReady ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  TimeOut 
)
static

Definition at line 490 of file ahci_hw.c.

493{
494 ULONG i, TaskFileData;
495
496 /* Do a quick check first (100 us) */
497 for (i = 0; i < 10; ++i)
498 {
499 TaskFileData = AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData);
500 if (!(TaskFileData & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)))
501 return TRUE;
502
504 }
505
506 /* Retry after the time interval */
507 for (i = 0; i < TimeOut; ++i)
508 {
509 TaskFileData = AHCI_PORT_READ(ChanData->IoBase, PxTaskFileData);
510 if (!(TaskFileData & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)))
511 return TRUE;
512
513 /* Keep clearing the port errors after every 1 second interval */
514 if (((i % AHCI_DELAY_1_SECOND) == 0) && (i != 0))
515 {
516 if (AtaAhciIsHbaHotRemoved(ChanData))
517 return FALSE;
518
519 WARN("CH %lu: Device is busy %08lx, trying to recover %lu\n",
520 ChanData->Channel,
521 TaskFileData,
522 i);
523
524 AHCI_PORT_WRITE(ChanData->IoBase, PxSataError, 0xFFFFFFFF);
525 }
526
527 AtaSleep();
528 }
529
530 return FALSE;
531}
#define AHCI_DELAY_1_SECOND
Definition: ahci.h:27

Referenced by AtaAhciPhyCheckConnection(), and AtaAhciPmpDetect().

◆ AtaPmpCheckConnection()

static ATA_CONNECTION_STATUS AtaPmpCheckConnection ( _In_ PCHANNEL_DATA_AHCI  ChanData,
_In_ ULONG  PortNumber 
)
static

Definition at line 1162 of file ahci_hw.c.

1165{
1166 ATA_CONNECTION_STATUS ConnectionStatus;
1167
1168 INFO("CH %lu: Reset PMP port %lu\n", ChanData->Channel, PortNumber);
1169
1170 ChanData->PortNotification(AtaResetDetected, ChanData->PortContext, 1 << PortNumber);
1171
1173 return CONN_STATUS_FAILURE;
1174
1175 ConnectionStatus = AtaAhciPmpPhyCheckDevicePresence(ChanData, PortNumber);
1176 if (ConnectionStatus != CONN_STATUS_DEV_UNKNOWN)
1177 return ConnectionStatus;
1178
1179 ConnectionStatus = AtaAhciPmpPhyWaitForReady(ChanData, PortNumber);
1180 if (ConnectionStatus != CONN_STATUS_DEV_UNKNOWN)
1181 return ConnectionStatus;
1182
1184}
static ATA_CONNECTION_STATUS AtaAhciPmpPhyCheckDevicePresence(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
Definition: ahci_hw.c:1090
static BOOLEAN AtaAhciPmpCheckSendComReset(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
Definition: ahci_hw.c:1053
static ATA_CONNECTION_STATUS AtaAhciPmpPhyWaitForReady(_In_ PCHANNEL_DATA_AHCI ChanData, _In_ ULONG PortNumber)
Definition: ahci_hw.c:1126

Referenced by AtaAhciPmpIdentifyDeviceBehindPmp().