Implemented Dpc Routine, managed Srb functions and some code fixes!

svn path=/branches/GSoC_2016/AHCI/; revision=71969
This commit is contained in:
Aman Priyadarshi 2016-07-19 16:50:59 +00:00
parent b86b9221d4
commit 93ea028360
2 changed files with 440 additions and 187 deletions

View file

@ -132,6 +132,7 @@ AhciAllocateResourceForAdapter (
PCHAR nonCachedExtension, tmp;
ULONG index, NCS, AlignedNCS;
ULONG portCount, portImplemented, nonCachedExtensionSize;
PAHCI_PORT_EXTENSION PortExtension;
DebugPrint("AhciAllocateResourceForAdapter()\n");
@ -173,18 +174,21 @@ AhciAllocateResourceForAdapter (
for (index = 0; index < portCount; index++)
{
AdapterExtension->PortExtension[index].IsActive = FALSE;
PortExtension = &AdapterExtension->PortExtension[index];
PortExtension->DeviceParams.IsActive = FALSE;
if ((AdapterExtension->PortImplemented & (1 << index)) != 0)
{
AdapterExtension->PortExtension[index].PortNumber = index;
AdapterExtension->PortExtension[index].IsActive = TRUE;
AdapterExtension->PortExtension[index].AdapterExtension = AdapterExtension;
AdapterExtension->PortExtension[index].CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension;
PortExtension->PortNumber = index;
PortExtension->DeviceParams.IsActive = TRUE;
PortExtension->AdapterExtension = AdapterExtension;
PortExtension->CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension;
tmp = (PCHAR)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
AdapterExtension->PortExtension[index].ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp;
AdapterExtension->PortExtension[index].IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS));
PortExtension->ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp;
PortExtension->IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS));
PortExtension->MaxPortQueueDepth = NCS;
nonCachedExtension += nonCachedExtensionSize;
}
}
@ -272,13 +276,6 @@ AhciStartPort (
ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS);
switch (ssts.DET)
{
case 0x0:
case 0x1:
case 0x2:
default:
// unhandled case
DebugPrint("\tDET == %x Unsupported\n", ssts.DET);
return FALSE;
case 0x3:
{
NT_ASSERT(cmd.ST == 0);
@ -299,6 +296,7 @@ AhciStartPort (
{
// failed to start FIS DMA engine
// it can crash the driver later
// so better to turn this port off
return FALSE;
}
@ -325,30 +323,51 @@ AhciStartPort (
// set IE
ie.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IE);
/* Device to Host Register FIS Interrupt Enable */
ie.DHRE = 1;
/* PIO Setup FIS Interrupt Enable */
ie.PSE = 1;
/* DMA Setup FIS Interrupt Enable */
ie.DSE = 1;
/* Set Device Bits FIS Interrupt Enable */
ie.SDBE = 1;
/* Unknown FIS Interrupt Enable */
ie.UFE = 0;
/* Descriptor Processed Interrupt Enable */
ie.DPE = 0;
/* Port Change Interrupt Enable */
ie.PCE = 1;
/* Device Mechanical Presence Enable */
ie.DMPE = 0;
/* PhyRdy Change Interrupt Enable */
ie.PRCE = 1;
/* Incorrect Port Multiplier Enable */
ie.IPME = 0;
/* Overflow Enable */
ie.OFE = 1;
/* Interface Non-fatal Error Enable */
ie.INFE = 1;
/* Interface Fatal Error Enable */
ie.IFE = 1;
/* Host Bus Data Error Enable */
ie.HBDE = 1;
/* Host Bus Fatal Error Enable */
ie.HBFE = 1;
/* Task File Error Enable */
ie.TFEE = 1;
cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
ie.CPDE = cmd.CPD;
/* Cold Presence Detect Enable */
if (cmd.CPD) // does it support CPD?
{
// disable it for now
ie.CPDE = 0;
}
StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IE, ie.Status);
// should I replace this to single line?
// by directly setting ie.Status?
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IE, ie.Status);
cmd.ST = 1;
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
@ -362,15 +381,107 @@ AhciStartPort (
return TRUE;
}
case 0x4:
// no device found
default:
// unhandled case
DebugPrint("\tDET == %x Unsupported\n", ssts.DET);
return FALSE;
}
DebugPrint("\tInvalid DET value: %x\n", ssts.DET);
return FALSE;
}// -- AhciStartPort();
/**
* @name AhciCommandCompletionDpcRoutine
* @implemented
*
* Handles Completed Commands
*
* @param Dpc
* @param AdapterExtension
* @param SystemArgument1
* @param SystemArgument2
*/
VOID
AhciCommandCompletionDpcRoutine (
__in PSTOR_DPC Dpc,
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in PAHCI_PORT_EXTENSION PortExtension,
__in PVOID SystemArgument2
)
{
PSCSI_REQUEST_BLOCK Srb;
STOR_LOCK_HANDLE lockhandle;
PAHCI_SRB_EXTENSION SrbExtension;
PAHCI_COMPLETION_ROUTINE CompletionRoutine;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument2);
DebugPrint("AhciCommandCompletionDpcRoutine()\n");
AhciZeroMemory(&lockhandle, sizeof(lockhandle));
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
Srb = RemoveQueue(&PortExtension->CompletionQueue);
NT_ASSERT(Srb != NULL);
if (Srb->SrbStatus == SRB_STATUS_PENDING)
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
}
SrbExtension = GetSrbExtension(Srb);
CompletionRoutine = SrbExtension->CompletionRoutine;
if (CompletionRoutine != NULL)
{
// now it's completion routine responsibility to set SrbStatus
CompletionRoutine(PortExtension, Srb);
}
else
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
StorPortNotification(RequestComplete, AdapterExtension, Srb);
}
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
return;
}// -- AhciCommandCompletionDpcRoutine();
/**
* @name AhciHwPassiveInitialize
* @implemented
*
* initializes the HBA and finds all devices that are of interest to the miniport driver. (at PASSIVE LEVEL)
*
* @param adapterExtension
*
* @return
* return TRUE if intialization was successful
*/
BOOLEAN
AhciHwPassiveInitialize (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension
)
{
ULONG index;
PAHCI_PORT_EXTENSION PortExtension;
DebugPrint("AhciHwPassiveInitialize()\n");
for (index = 0; index < AdapterExtension->PortCount; index++)
{
if ((AdapterExtension->PortImplemented & (0x1 << index)) != 0)
{
PortExtension = &AdapterExtension->PortExtension[index];
PortExtension->DeviceParams.IsActive = AhciStartPort(PortExtension);
StorPortInitializeDpc(AdapterExtension, &PortExtension->CommandCompletion, AhciCommandCompletionDpcRoutine);
}
}
return TRUE;
}// -- AhciHwPassiveInitialize();
/**
* @name AhciHwInitialize
* @implemented
@ -384,39 +495,30 @@ AhciStartPort (
*/
BOOLEAN
AhciHwInitialize (
__in PVOID AdapterExtension
__in PAHCI_ADAPTER_EXTENSION AdapterExtension
)
{
ULONG ghc, index;
PAHCI_PORT_EXTENSION PortExtension;
PAHCI_ADAPTER_EXTENSION adapterExtension;
AHCI_GHC ghc;
MESSAGE_INTERRUPT_INFORMATION messageInfo;
DebugPrint("AhciHwInitialize()\n");
adapterExtension = AdapterExtension;
adapterExtension->StateFlags.MessagePerPort = FALSE;
AdapterExtension->StateFlags.MessagePerPort = FALSE;
// First check what type of interrupt/synchronization device is using
ghc = StorPortReadRegisterUlong(adapterExtension, &adapterExtension->ABAR_Address->GHC);
ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &AdapterExtension->ABAR_Address->GHC);
// When set to 1 by hardware, indicates that the HBA requested more than one MSI vector
// but has reverted to using the first vector only. When this bit is cleared to 0,
// the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
// software has allocated the number of messages requested
if ((ghc & AHCI_Global_HBA_CONTROL_MRSM) == 0)
if (ghc.MRSM == 0)
{
adapterExtension->StateFlags.MessagePerPort = TRUE;
AdapterExtension->StateFlags.MessagePerPort = TRUE;
DebugPrint("\tMultiple MSI based message not supported\n");
}
for (index = 0; index < adapterExtension->PortCount; index++)
{
if ((adapterExtension->PortImplemented & (0x1 << index)) != 0)
{
PortExtension = &adapterExtension->PortExtension[index];
PortExtension->IsActive = AhciStartPort(PortExtension);
}
}
StorPortEnablePassiveInitialization(AdapterExtension, AhciHwPassiveInitialize);
return TRUE;
}// -- AhciHwInitialize();
@ -438,9 +540,7 @@ AhciCompleteIssuedSrb (
{
ULONG NCS, i;
PSCSI_REQUEST_BLOCK Srb;
PAHCI_SRB_EXTENSION SrbExtension;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
PAHCI_COMPLETION_ROUTINE CompletionRoutine;
DebugPrint("AhciCompleteIssuedSrb()\n");
@ -458,24 +558,8 @@ AhciCompleteIssuedSrb (
Srb = PortExtension->Slot[i];
NT_ASSERT(Srb != NULL);
if (Srb->SrbStatus == SRB_STATUS_PENDING)
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
}
SrbExtension = GetSrbExtension(Srb);
CompletionRoutine = SrbExtension->CompletionRoutine;
if (CompletionRoutine != NULL)
{
// now it's completion routine responsibility to set SrbStatus
CompletionRoutine(AdapterExtension, PortExtension, Srb);
}
else
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
StorPortNotification(RequestComplete, AdapterExtension, Srb);
}
AddQueue(&PortExtension->CompletionQueue, Srb);
StorPortIssueDpc(AdapterExtension, &PortExtension->CommandCompletion, PortExtension, Srb);
}
}
@ -589,23 +673,21 @@ AhciInterruptHandler (
* return FALSE Indicates the interrupt was not ours.
*/
BOOLEAN
AhciHwInterrupt(
AhciHwInterrupt (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension
)
{
ULONG portPending, nextPort, i, portCount;
DebugPrint("AhciHwInterrupt()\n");
if (AdapterExtension->StateFlags.Removed)
{
return FALSE;
}
portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS);
// we process interrupt for implemented ports only
portCount = AdapterExtension->PortCount;
DebugPrint("\tPortPending: %d\n", portPending);
portPending = portPending & AdapterExtension->PortImplemented;
if (portPending == 0)
@ -616,18 +698,12 @@ AhciHwInterrupt(
for (i = 1; i <= portCount; i++)
{
nextPort = (AdapterExtension->LastInterruptPort + i) % portCount;
if ((portPending & (0x1 << nextPort)) == 0)
continue;
NT_ASSERT(IsPortValid(AdapterExtension, nextPort));
if (nextPort == AdapterExtension->LastInterruptPort)
{
return FALSE;
}
if (AdapterExtension->PortExtension[nextPort].IsActive == FALSE)
if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE)
{
continue;
}
@ -636,6 +712,8 @@ AhciHwInterrupt(
AdapterExtension->LastInterruptPort = nextPort;
AhciInterruptHandler(&AdapterExtension->PortExtension[nextPort]);
portPending &= ~(1 << nextPort);
// interrupt belongs to this device
// should always return TRUE
return TRUE;
@ -673,6 +751,8 @@ AhciHwStartIo (
function = Srb->Function;
adapterExtension = AdapterExtension;
DebugPrint("\tFunction: %x\n", function);
if (!IsPortValid(adapterExtension, pathId))
{
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
@ -714,6 +794,7 @@ AhciHwStartIo (
if (function == SRB_FUNCTION_EXECUTE_SCSI)
{
DebugPrint("\tSRB_FUNCTION_EXECUTE_SCSI\n");
// https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
// On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
// routine does the following:
@ -732,13 +813,22 @@ AhciHwStartIo (
if (Srb->CdbLength > 0)
{
PCDB cdb = (PCDB)&Srb->Cdb;
if (cdb->CDB10.OperationCode == SCSIOP_INQUIRY)
NT_ASSERT(cdb != NULL);
switch(cdb->CDB10.OperationCode)
{
Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb);
}
else
{
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
case SCSIOP_INQUIRY:
Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb, TRUE);
break;
case SCSIOP_REPORT_LUNS:
Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb, FALSE);
break;
default:
{
DebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
}
break;
}
}
else
@ -751,7 +841,7 @@ AhciHwStartIo (
}
DebugPrint("\tUnknown function code recieved: %x\n", function);
Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}// -- AhciHwStartIo();
@ -839,9 +929,10 @@ AhciHwFindAdapter (
__in PBOOLEAN Reserved3
)
{
ULONG ghc, index, pci_cfg_len;
UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
AHCI_GHC ghc;
ULONG index, pci_cfg_len;
PACCESS_RANGE accessRange;
UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
PAHCI_MEMORY_REGISTERS abar;
PPCI_COMMON_CONFIG pciConfigData;
@ -919,9 +1010,9 @@ AhciHwFindAdapter (
// 10.1.2
// 1. Indicate that system software is AHCI aware by setting GHC.AE to 1.
// 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
ghc = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
// AE := Highest Significant bit of GHC
if ((ghc & AHCI_Global_HBA_CONTROL_AE) != 0)// Hmm, controller was already in power state
if (ghc.AE != 0)// Hmm, controller was already in power state
{
// reset controller to have it in known state
DebugPrint("\tAE Already set, Reset()\n");
@ -932,9 +1023,10 @@ AhciHwFindAdapter (
}
}
ghc = AHCI_Global_HBA_CONTROL_AE;// only AE=1
ghc.Status = 0;
ghc.AE = 1;// only AE=1
// tell the controller that we know about AHCI
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
adapterExtension->IS = &abar->IS;
adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
@ -954,6 +1046,11 @@ AhciHwFindAdapter (
ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
ConfigInfo->ScatterGather = TRUE;
// Turn IE -- Interrupt Enabled
ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
ghc.IE = 1;
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
// allocate necessary resource for each port
if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo))
{
@ -967,11 +1064,6 @@ AhciHwFindAdapter (
AhciPortInitialize(&adapterExtension->PortExtension[index]);
}
// Turn IE -- Interrupt Enabled
ghc = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
ghc |= AHCI_Global_HBA_CONTROL_IE;
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
return SP_RETURN_FOUND;
}// -- AhciHwFindAdapter();
@ -1044,8 +1136,10 @@ DriverEntry (
* @param PortExtension
* @param Srb
*
* @return
* Number of CFIS fields used in DWORD
*/
VOID
ULONG
AhciATA_CFIS (
__in PAHCI_PORT_EXTENSION PortExtension,
__in PAHCI_SRB_EXTENSION SrbExtension
@ -1059,12 +1153,10 @@ AhciATA_CFIS (
cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
NT_ASSERT(sizeof(cmdTable->CFIS) == 64);
AhciZeroMemory(&cmdTable->CFIS, sizeof(cmdTable->CFIS));
cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = 0x27; // FIS Type
cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C
cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = FIS_TYPE_REG_H2D; // FIS Type
cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C
cmdTable->CFIS[AHCI_ATA_CFIS_CommandReg] = SrbExtension->CommandReg;
cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesLow] = SrbExtension->FeaturesLow;
@ -1079,7 +1171,7 @@ AhciATA_CFIS (
cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountLow] = SrbExtension->SectorCountLow;
cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountHigh] = SrbExtension->SectorCountHigh;
return;
return 5;
}// -- AhciATA_CFIS();
/**
@ -1091,8 +1183,10 @@ AhciATA_CFIS (
* @param PortExtension
* @param Srb
*
* @return
* Number of CFIS fields used in DWORD
*/
VOID
ULONG
AhciATAPI_CFIS (
__in PAHCI_PORT_EXTENSION PortExtension,
__in PAHCI_SRB_EXTENSION SrbExtension
@ -1103,7 +1197,7 @@ AhciATAPI_CFIS (
DebugPrint("AhciATAPI_CFIS()\n");
return;
return 2;
}// -- AhciATAPI_CFIS();
/**
@ -1147,6 +1241,11 @@ AhciBuild_PRDT (
{
cmdTable->PRDT[index].DBAU = sgl->List[index].PhysicalAddress.HighPart;
}
// Data Byte Count (DBC): A 0 based value that Indicates the length, in bytes, of the data block.
// A maximum of length of 4MB may exist for any entry. Bit 0 of this field must always be 1 to
// indicate an even byte count. A value of 1 indicates 2 bytes, 3 indicates 4 bytes, etc.
cmdTable->PRDT[index].DBC = sgl->List[index].Length - 1;
}
return sgl->NumberOfElements;
@ -1170,7 +1269,7 @@ AhciProcessSrb (
__in ULONG SlotIndex
)
{
ULONG prdtlen, sig, length;
ULONG prdtlen, sig, length, cfl;
PAHCI_SRB_EXTENSION SrbExtension;
PAHCI_COMMAND_HEADER CommandHeader;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
@ -1193,10 +1292,12 @@ AhciProcessSrb (
sig = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SIG);
if (sig == 0x101)
{
DebugPrint("\tATA Device Found!\n");
SrbExtension->CommandReg = IDE_COMMAND_IDENTIFY;
}
else
{
DebugPrint("\tATAPI Device Found!\n");
SrbExtension->CommandReg = IDE_COMMAND_ATAPI_IDENTIFY;
}
}
@ -1207,13 +1308,14 @@ AhciProcessSrb (
// program the CFIS in the CommandTable
CommandHeader = &PortExtension->CommandList[SlotIndex];
cfl = 0;
if (IsAtaCommand(SrbExtension->AtaFunction))
{
AhciATA_CFIS(PortExtension, SrbExtension);
cfl = AhciATA_CFIS(PortExtension, SrbExtension);
}
else if (IsAtapiCommand(SrbExtension->AtaFunction))
{
AhciATAPI_CFIS(PortExtension, SrbExtension);
cfl = AhciATAPI_CFIS(PortExtension, SrbExtension);
}
prdtlen = 0;
@ -1225,7 +1327,8 @@ AhciProcessSrb (
// Program the command header
CommandHeader->DI.PRDTL = prdtlen; // number of entries in PRD table
CommandHeader->DI.CFL = 5;
CommandHeader->DI.CFL = cfl;
CommandHeader->DI.A = (SrbExtension->AtaFunction & ATA_FUNCTION_ATAPI_COMMAND) ? 1 : 0;
CommandHeader->DI.W = (SrbExtension->Flags & ATA_FLAGS_DATA_OUT) ? 1 : 0;
CommandHeader->DI.P = 0; // ATA Specifications says so
CommandHeader->DI.PMP = 0; // Port Multiplier
@ -1243,21 +1346,21 @@ AhciProcessSrb (
CommandHeader->Reserved[3] = 0;
// set CommandHeader CTBA
// I am really not sure if SrbExtension is 128 byte aligned or not
// Command FIS will not work if it is not so.
CommandTablePhysicalAddress = StorPortGetPhysicalAddress(AdapterExtension,
NULL,
SrbExtension,
&length);
NT_ASSERT(length != 0);
// command table alignment
NT_ASSERT((CommandTablePhysicalAddress.LowPart % 128) == 0);
CommandHeader->CTBA0 = CommandTablePhysicalAddress.LowPart;
CommandHeader->CTBA = CommandTablePhysicalAddress.LowPart;
if (IsAdapterCAPS64(AdapterExtension->CAP))
{
CommandHeader->CTBA_U0 = CommandTablePhysicalAddress.HighPart;
CommandHeader->CTBA_U = CommandTablePhysicalAddress.HighPart;
}
// mark this slot
@ -1281,6 +1384,7 @@ AhciActivatePort (
)
{
AHCI_PORT_CMD cmd;
ULONG sact, ci;
ULONG QueueSlots, slotToActivate, tmp;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
@ -1290,7 +1394,9 @@ AhciActivatePort (
QueueSlots = PortExtension->QueueSlots;
if (QueueSlots == 0)
{
return;
}
// section 3.3.14
// Bits in this field shall only be set to 1 by software when PxCMD.ST is set to 1
@ -1301,6 +1407,9 @@ AhciActivatePort (
return;
}
sact = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SACT);
ci = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CI);
// get the lowest set bit
tmp = QueueSlots & (QueueSlots - 1);
@ -1316,8 +1425,6 @@ AhciActivatePort (
// to validate in completeIssuedCommand
PortExtension->CommandIssuedSlots |= slotToActivate;
DebugPrint("\tslotToActivate: %d\n", slotToActivate);
// tell the HBA to issue this Command Slot to the given port
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CI, slotToActivate);
@ -1355,17 +1462,21 @@ AhciProcessIO (
NT_ASSERT(PathId < AdapterExtension->PortCount);
// add Srb to queue
AddQueue(&PortExtension->SrbQueue, Srb);
if (PortExtension->IsActive == FALSE)
return; // we should wait for device to get active
AhciZeroMemory(&lockhandle, sizeof(lockhandle));
// Acquire Lock
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
// add Srb to queue
AddQueue(&PortExtension->SrbQueue, Srb);
if (PortExtension->DeviceParams.IsActive == FALSE)
{
// Release Lock
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
return; // we should wait for device to get active
}
occupiedSlots = (PortExtension->QueueSlots | PortExtension->CommandIssuedSlots); // Busy command slots for given port
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
commandSlotMask = (1 << NCS) - 1; // available slots mask
@ -1419,46 +1530,107 @@ AhciProcessIO (
*/
VOID
InquiryCompletion (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in PAHCI_PORT_EXTENSION PortExtension,
__in PSCSI_REQUEST_BLOCK Srb
)
{
ULONG SrbStatus;
PCDB cdb;
PLUN_LIST LunList;
PAHCI_SRB_EXTENSION SrbExtension;
PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
ULONG SrbStatus, LunCount, DataBufferLength;
DebugPrint("InquiryCompletion()\n");
NT_ASSERT(PortExtension != NULL);
NT_ASSERT(Srb != NULL);
cdb = (PCDB)&Srb->Cdb;
SrbStatus = Srb->SrbStatus;
SrbExtension = GetSrbExtension(Srb);
if (SrbStatus == SRB_STATUS_SUCCESS)
{
IdentifyDeviceData = PortExtension->IdentifyDeviceData;
if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
{
DebugPrint("Device: ATA\n");
AdapterExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
if (IdentifyDeviceData->GeneralConfiguration.RemovableMedia)
{
PortExtension->DeviceParams.RemovableDevice = 1;
}
if (IdentifyDeviceData->CommandSetSupport.BigLba && IdentifyDeviceData->CommandSetActive.BigLba)
{
PortExtension->DeviceParams.Lba48BitMode = 1;
}
PortExtension->DeviceParams.AccessType = DIRECT_ACCESS_DEVICE;
// TODO: Add other device params
}
else
{
DebugPrint("Device: ATAPI\n");
AdapterExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
}
// TODO: Set Device Paramters
}
else if (SrbStatus == SRB_STATUS_NO_DEVICE)
{
DebugPrint("Device: No Device\n");
AdapterExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
}
else
{
return;
}
if ((cdb != NULL) && (cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS))
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->ScsiStatus = SCSISTAT_GOOD;
SrbExtension->AtaFunction = 0;
DataBufferLength = Srb->DataTransferLength;
LunList = (PLUN_LIST)Srb->DataBuffer;
if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_NODEVICE)
{
LunCount = 0;
}
else
{
LunCount = 1;
}
if (DataBufferLength < sizeof(LUN_LIST))
{
DebugPrint("\tSRB_STATUS_DATA_OVERRUN\n");
Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
}
else
{
LunList->LunListLength[0] = 0;
LunList->LunListLength[1] = 0;
LunList->LunListLength[2] = 0;
LunList->LunListLength[3] = 8;
// followed by 8 entries
LunList->Lun[0][0] = 0;
LunList->Lun[0][1] = 0;
LunList->Lun[0][2] = 0;
LunList->Lun[0][3] = 0;
LunList->Lun[0][4] = 0;
LunList->Lun[0][5] = 0;
LunList->Lun[0][6] = 0;
LunList->Lun[0][7] = 0;
}
}
return;
}// -- InquiryCompletion();
@ -1482,13 +1654,15 @@ UCHAR
DeviceInquiryRequest (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in PSCSI_REQUEST_BLOCK Srb,
__in PCDB Cdb
__in PCDB Cdb,
__in BOOLEAN HasProductDataRequest
)
{
PVOID DataBuffer;
ULONG DataBufferLength;
PAHCI_PORT_EXTENSION PortExtension;
PAHCI_SRB_EXTENSION SrbExtension;
PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
ULONG DataBufferLength, RequiredDataBufferLength;
DebugPrint("DeviceInquiryRequest()\n");
@ -1497,10 +1671,14 @@ DeviceInquiryRequest (
SrbExtension = GetSrbExtension(Srb);
PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
// 3.6.1
// If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
if (Srb->Lun != 0)
{
return SRB_STATUS_SELECTION_TIMEOUT;
}
else if ((HasProductDataRequest == FALSE) || (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0))
{
// 3.6.1
// If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
DebugPrint("\tEVPD Inquired\n");
NT_ASSERT(SrbExtension != NULL);
@ -1514,7 +1692,7 @@ DeviceInquiryRequest (
SrbExtension->LBA0 = 0;
SrbExtension->LBA1 = 0;
SrbExtension->LBA2 = 0;
SrbExtension->Device = 0;
SrbExtension->Device = 0xA0;
SrbExtension->LBA3 = 0;
SrbExtension->LBA4 = 0;
SrbExtension->LBA5 = 0;
@ -1526,8 +1704,11 @@ DeviceInquiryRequest (
SrbExtension->Sgl.List[0].PhysicalAddress.LowPart = PortExtension->IdentifyDeviceDataPhysicalAddress.LowPart;
SrbExtension->Sgl.List[0].PhysicalAddress.HighPart = PortExtension->IdentifyDeviceDataPhysicalAddress.HighPart;
SrbExtension->Sgl.List[0].Length = sizeof(IDENTIFY_DEVICE_DATA);
AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
return SRB_STATUS_PENDING;
}
else
else if (HasProductDataRequest == TRUE)
{
DebugPrint("\tVPD Inquired\n");
@ -1541,12 +1722,37 @@ DeviceInquiryRequest (
AhciZeroMemory(DataBuffer, DataBufferLength);
// not supported
return SRB_STATUS_BAD_FUNCTION;
switch(Cdb->CDB6INQUIRY3.PageCode)
{
case VPD_SUPPORTED_PAGES:
{
DebugPrint("\tVPD_SUPPORTED_PAGES\n");
RequiredDataBufferLength = sizeof(VPD_SUPPORTED_PAGES_PAGE);
if (DataBufferLength < RequiredDataBufferLength)
{
DebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength, RequiredDataBufferLength);
return SRB_STATUS_INVALID_REQUEST;
}
else
{
VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer;
VpdOutputBuffer->DeviceType = PortExtension->DeviceParams.DeviceType;
VpdOutputBuffer->DeviceTypeQualifier = 0;
VpdOutputBuffer->PageCode = VPD_SUPPORTED_PAGES;
VpdOutputBuffer->PageLength = 1;
VpdOutputBuffer->SupportedPageList[0] = VPD_SUPPORTED_PAGES;
return SRB_STATUS_SUCCESS;
}
}
break;
default:
DebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode);
break;
}
}
AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
return SRB_STATUS_PENDING;
return SRB_STATUS_INVALID_REQUEST;
}// -- DeviceInquiryRequest();
/**
@ -1573,7 +1779,8 @@ AhciAdapterReset (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension
)
{
ULONG ghc, ticks, ghcStatus;
ULONG ticks;
AHCI_GHC ghc;
PAHCI_MEMORY_REGISTERS abar = NULL;
DebugPrint("AhciAdapterReset()\n");
@ -1585,13 +1792,13 @@ AhciAdapterReset (
}
// HR -- Very first bit (lowest significant)
ghc = AHCI_Global_HBA_CONTROL_HR;
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc);
ghc.HR = 1;
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status);
for (ticks = 0; ticks < 50; ++ticks)
{
ghcStatus = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
if ((ghcStatus & AHCI_Global_HBA_CONTROL_HR) == 0)
ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
if (ghc.HR == 0)
{
break;
}
@ -1658,7 +1865,7 @@ IsPortValid (
return FALSE;
}
return AdapterExtension->PortExtension[pathId].IsActive;
return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive;
}// -- IsPortValid()
/**

View file

@ -25,12 +25,17 @@
#define AHCI_DEVICE_TYPE_NODEVICE 3
// section 3.1.2
#define AHCI_Global_HBA_CONTROL_HR (1 << 0)
#define AHCI_Global_HBA_CONTROL_IE (1 << 1)
#define AHCI_Global_HBA_CONTROL_MRSM (1 << 2)
#define AHCI_Global_HBA_CONTROL_AE (1 << 31)
#define AHCI_Global_HBA_CAP_S64A (1 << 31)
// FIS Types : http://wiki.osdev.org/AHCI
#define FIS_TYPE_REG_H2D 0x27 // Register FIS - host to device
#define FIS_TYPE_REG_D2H 0x34 // Register FIS - device to host
#define FIS_TYPE_DMA_ACT 0x39 // DMA activate FIS - device to host
#define FIS_TYPE_DMA_SETUP 0x41 // DMA setup FIS - bidirectional
#define FIS_TYPE_BIST 0x58 // BIST activate FIS - bidirectional
#define FIS_TYPE_PIO_SETUP 0x5F // PIO setup FIS - device to host
#define FIS_TYPE_DEV_BITS 0xA1 // Set device bits FIS - device to host
#define AHCI_ATA_CFIS_FisType 0
#define AHCI_ATA_CFIS_PMPort_C 1
#define AHCI_ATA_CFIS_CommandReg 2
@ -73,7 +78,6 @@
typedef
VOID
(*PAHCI_COMPLETION_ROUTINE) (
__in PVOID AdapterExtension,
__in PVOID PortExtension,
__in PVOID Srb
);
@ -225,7 +229,7 @@ typedef union _AHCI_COMMAND_HEADER_DESCRIPTION
ULONG R : 1; // Reset
ULONG B : 1; // BIST
ULONG C : 1; //Clear Busy upon R_OK
ULONG DW0_Reserved : 1;
ULONG RSV : 1;
ULONG PMP : 4; //Port Multiplier Port
ULONG PRDTL : 16; //Physical Region Descriptor Table Length
@ -234,6 +238,20 @@ typedef union _AHCI_COMMAND_HEADER_DESCRIPTION
ULONG Status;
} AHCI_COMMAND_HEADER_DESCRIPTION;
typedef union _AHCI_GHC
{
struct
{
ULONG HR : 1;
ULONG IE : 1;
ULONG MRSM : 1;
ULONG RSV0 : 28;
ULONG AE : 1;
};
ULONG Status;
} AHCI_GHC;
// section 3.3.7
typedef union _AHCI_PORT_CMD
{
@ -340,10 +358,10 @@ typedef struct _AHCI_COMMAND_TABLE
typedef struct _AHCI_COMMAND_HEADER
{
AHCI_COMMAND_HEADER_DESCRIPTION DI; // DW 0
ULONG PRDBC; // DW 1
ULONG CTBA0; // DW 2
ULONG CTBA_U0; // DW 3
ULONG Reserved[4]; // DW 4-7
ULONG PRDBC; // DW 1
ULONG CTBA; // DW 2
ULONG CTBA_U; // DW 3
ULONG Reserved[4]; // DW 4-7
} AHCI_COMMAND_HEADER, *PAHCI_COMMAND_HEADER;
// Received FIS
@ -384,7 +402,7 @@ typedef struct _AHCI_PORT
ULONG Vendor[4]; // 0x70 ~ 0x7F, vendor specific
} AHCI_PORT, *PAHCI_PORT;
typedef struct _AHCI_INTERRUPT_ENABLE
typedef union _AHCI_INTERRUPT_ENABLE
{
struct
{
@ -408,6 +426,7 @@ typedef struct _AHCI_INTERRUPT_ENABLE
ULONG TFEE :1;
ULONG CPDE :1;
};
ULONG Status;
} AHCI_INTERRUPT_ENABLE;
@ -436,9 +455,21 @@ typedef struct _AHCI_PORT_EXTENSION
ULONG PortNumber;
ULONG QueueSlots; // slots which we have already assigned task (Slot)
ULONG CommandIssuedSlots; // slots which has been programmed
BOOLEAN IsActive;
ULONG MaxPortQueueDepth;
struct
{
UCHAR RemovableDevice;
UCHAR Lba48BitMode;
UCHAR AccessType;
UCHAR DeviceType;
UCHAR IsActive;
} DeviceParams;
STOR_DPC CommandCompletion;
PAHCI_PORT Port; // AHCI Port Infomation
AHCI_QUEUE SrbQueue; // pending Srbs
AHCI_QUEUE CompletionQueue;
PSCSI_REQUEST_BLOCK Slot[MAXIMUM_AHCI_PORT_NCS]; // Srbs which has been alloted a port
PAHCI_RECEIVED_FIS ReceivedFIS;
PAHCI_COMMAND_HEADER CommandList;
@ -470,11 +501,6 @@ typedef struct _AHCI_ADAPTER_EXTENSION
PVOID NonCachedExtension; // holds virtual address to noncached buffer allocated for Port Extension
struct
{
UCHAR DeviceType;
} DeviceParams;
struct
{
// Message per port or shared port?
@ -546,7 +572,8 @@ UCHAR
DeviceInquiryRequest (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in PSCSI_REQUEST_BLOCK Srb,
__in PCDB Cdb
__in PCDB Cdb,
__in BOOLEAN HasProductDataRequest
);
__inline
@ -572,37 +599,56 @@ GetSrbExtension(
// Assertions //
//////////////////////////////////////////////////////////////
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CAP) == 0x00);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, GHC) == 0x04);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, IS) == 0x08);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, PI) == 0x0C);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, VS) == 0x10);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CCC_CTL) == 0x14);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CCC_PTS) == 0x18);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, EM_LOC) == 0x1C);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, EM_CTL) == 0x20);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CAP2) == 0x24);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, BOHC) == 0x28);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, Reserved) == 0x2C);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, VendorSpecific) == 0xA0);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, PortList) == 0x100);
// I assert every silly mistake I can do while coding
// because god never help me debugging the code
// but these asserts do :')
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CLB) == 0x00);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CLBU) == 0x04);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, FB) == 0x08);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, FBU) == 0x0C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, IS) == 0x10);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, IE) == 0x14);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CMD) == 0x18);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, RSV0) == 0x1C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, TFD) == 0x20);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SIG) == 0x24);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SSTS) == 0x28);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SCTL) == 0x2C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SERR) == 0x30);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SACT) == 0x34);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CI) == 0x38);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SNTF) == 0x3C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, FBS) == 0x40);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, RSV1) == 0x44);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, Vendor) == 0x70);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CAP) == 0x00);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, GHC) == 0x04);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, IS) == 0x08);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, PI) == 0x0C);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, VS) == 0x10);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CCC_CTL) == 0x14);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CCC_PTS) == 0x18);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, EM_LOC) == 0x1C);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, EM_CTL) == 0x20);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, CAP2) == 0x24);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, BOHC) == 0x28);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, Reserved) == 0x2C);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, VendorSpecific) == 0xA0);
C_ASSERT(FIELD_OFFSET(AHCI_MEMORY_REGISTERS, PortList) == 0x100);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CLB) == 0x00);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CLBU) == 0x04);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, FB) == 0x08);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, FBU) == 0x0C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, IS) == 0x10);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, IE) == 0x14);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CMD) == 0x18);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, RSV0) == 0x1C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, TFD) == 0x20);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SIG) == 0x24);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SSTS) == 0x28);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SCTL) == 0x2C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SERR) == 0x30);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SACT) == 0x34);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, CI) == 0x38);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, SNTF) == 0x3C);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, FBS) == 0x40);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, RSV1) == 0x44);
C_ASSERT(FIELD_OFFSET(AHCI_PORT, Vendor) == 0x70);
C_ASSERT((sizeof(AHCI_COMMAND_TABLE) % 128) == 0);
C_ASSERT(sizeof(AHCI_GHC) == sizeof(ULONG));
C_ASSERT(sizeof(AHCI_PORT_CMD) == sizeof(ULONG));
C_ASSERT(sizeof(AHCI_TASK_FILE_DATA) == sizeof(ULONG));
C_ASSERT(sizeof(AHCI_INTERRUPT_ENABLE) == sizeof(ULONG));
C_ASSERT(sizeof(AHCI_SERIAL_ATA_STATUS) == sizeof(ULONG));
C_ASSERT(sizeof(AHCI_SERIAL_ATA_CONTROL) == sizeof(ULONG));
C_ASSERT(sizeof(AHCI_COMMAND_HEADER_DESCRIPTION) == sizeof(ULONG));
C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE, CFIS) == 0x00);
C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE, ACMD) == 0x40);
C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE, RSV0) == 0x50);
C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE, PRDT) == 0x80);