From 93ea02836069e43243b03cce8d8a59e6df180dd0 Mon Sep 17 00:00:00 2001 From: Aman Priyadarshi Date: Tue, 19 Jul 2016 16:50:59 +0000 Subject: [PATCH] Implemented Dpc Routine, managed Srb functions and some code fixes! svn path=/branches/GSoC_2016/AHCI/; revision=71969 --- drivers/storage/storahci/storahci.c | 479 ++++++++++++++++++++-------- drivers/storage/storahci/storahci.h | 148 ++++++--- 2 files changed, 440 insertions(+), 187 deletions(-) diff --git a/drivers/storage/storahci/storahci.c b/drivers/storage/storahci/storahci.c index 5f81b4ab02a..5cfd7e0295a 100644 --- a/drivers/storage/storahci/storahci.c +++ b/drivers/storage/storahci/storahci.c @@ -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; + } + + // should I replace this to single line? + // by directly setting ie.Status? - StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IE, 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) - { - Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb); - } - else + NT_ASSERT(cdb != NULL); + + switch(cdb->CDB10.OperationCode) { - 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() /** diff --git a/drivers/storage/storahci/storahci.h b/drivers/storage/storahci/storahci.h index 2e736789d6e..c8e14345a72 100644 --- a/drivers/storage/storahci/storahci.h +++ b/drivers/storage/storahci/storahci.h @@ -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); +// 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_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); \ No newline at end of file +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); -- 2.17.1