From 5b776020aeb4f6270336c6110db872d9cec3c67b Mon Sep 17 00:00:00 2001 From: Aman Priyadarshi Date: Thu, 16 Jun 2016 17:02:55 +0000 Subject: [PATCH] - Fixed CMakeLists issues reported by hbelusca - Fixed ROS name issue reported by hbelusca - Handled non fatal device error interrupts - AhciProcessIO Implemented - code clean svn path=/branches/GSoC_2016/AHCI/; revision=71647 --- drivers/storage/CMakeLists.txt | 1 + drivers/storage/storahci/CMakeLists.txt | 21 +- drivers/storage/storahci/storahci.c | 408 ++++++++++++++++++------ drivers/storage/storahci/storahci.h | 51 +++ drivers/storage/storahci/storahci.inf | 2 +- 5 files changed, 363 insertions(+), 120 deletions(-) diff --git a/drivers/storage/CMakeLists.txt b/drivers/storage/CMakeLists.txt index ff51e59f461..610df522d26 100644 --- a/drivers/storage/CMakeLists.txt +++ b/drivers/storage/CMakeLists.txt @@ -6,3 +6,4 @@ add_subdirectory(floppy) add_subdirectory(ide) add_subdirectory(port) add_subdirectory(scsiport) +add_subdirectory(storahci) diff --git a/drivers/storage/storahci/CMakeLists.txt b/drivers/storage/storahci/CMakeLists.txt index 0f09d56ef09..039ed8d0c4e 100644 --- a/drivers/storage/storahci/CMakeLists.txt +++ b/drivers/storage/storahci/CMakeLists.txt @@ -1,27 +1,10 @@ - -set_cpp() - -include_directories( - BEFORE ${CMAKE_CURRENT_SOURCE_DIR} - inc) - -#add_definitions(-DDEBUG) +add_definitions(-DDEBUG) list(APPEND SOURCE - storahci.cpp - ros_glue/ros_glue.cpp - stdafx.h) + storahci.c) add_library(storahci SHARED ${SOURCE} storahci.rc) -if(NOT MSVC) - add_target_compile_flags(storahci "-Wno-narrowing") - if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang") - add_target_compile_flags(storahci "-Wno-unused-but-set-variable") - endif() -endif() - -add_pch(storahci stdafx.h SOURCE) set_module_type(storahci kernelmodedriver) add_importlibs(storahci storport ntoskrnl hal) add_cd_file(TARGET storahci DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/storage/storahci/storahci.c b/drivers/storage/storahci/storahci.c index 473e88cd483..fb2e6fa5914 100644 --- a/drivers/storage/storahci/storahci.c +++ b/drivers/storage/storahci/storahci.c @@ -216,19 +216,80 @@ AhciHwInitialize ( * * @param PortExtension * - * @return - * return TRUE Indicates the interrupt was handled correctly - * return FALSE Indicates something went wrong */ -BOOLEAN +VOID AhciInterruptHandler ( __in PAHCI_PORT_EXTENSION PortExtension ) { + ULONG IS; + AHCI_INTERRUPT_STATUS PxIS; + AHCI_INTERRUPT_STATUS PxISMasked; + PAHCI_ADAPTER_EXTENSION AdapterExtension; + DebugPrint("AhciInterruptHandler()\n"); DebugPrint("\tPort Number: %d\n", PortExtension->PortNumber); - return FALSE; + AdapterExtension = PortExtension->AdapterExtension; + NT_ASSERT(IsPortValid(AdapterExtension, PortExtension->PortNumber)); + + // 5.5.3 + // 1. Software determines the cause of the interrupt by reading the PxIS register. + // It is possible for multiple bits to be set + // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt. + // 3. Software clears the interrupt bit in IS.IPS corresponding to the port. + // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to + // the list of commands previously issued by software that are still outstanding. + // If executing native queued commands, software reads the PxSACT register and compares the current + // value to the list of commands previously issued by software. + // Software completes with success any outstanding command whose corresponding bit has been cleared in + // the respective register. PxCI and PxSACT are volatile registers; software should only use their values + // to determine commands that have completed, not to determine which commands have previously been issued. + // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2). + PxISMasked.Status = 0; + PxIS.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IS); + + // 6.2.2 + // Fatal Error + // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES + if (PxIS.HBFS || PxIS.HBDS || PxIS.IFS || PxIS.TFES) + { + // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process + // any native command queuing commands. To recover, the port must be restarted + // To detect an error that requires software recovery actions to be performed, + // software should check whether any of the following status bits are set on an interrupt: + // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set, + // software should perform the appropriate error recovery actions based on whether + // non-queued commands were being issued or native command queuing commands were being issued. + + DebugPrint("\tFata Error: %x\n", PxIS.Status); + } + + // Normal Command Completion + // 3.3.5 + // A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory. + PxISMasked.DHRS = PxIS.DHRS; + // A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory. + PxISMasked.PSS = PxIS.PSS; + // A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory. + PxISMasked.DSS = PxIS.DSS; + // A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/ + PxISMasked.SDBS = PxIS.SDBS; + // A PRD with the ‘I’ bit set has transferred all of its data. + PxISMasked.DPS = PxIS.DPS; + + if (PxISMasked.Status != 0) + { + StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IS, PxISMasked.Status); + } + + // 10.7.1.1 + // Clear port interrupt + // It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software. + IS = (1 << PortExtension->PortNumber); + StorPortWriteRegisterUlong(AdapterExtension, AdapterExtension->IS, IS); + + return; }// -- AhciInterruptHandler(); /** @@ -276,6 +337,8 @@ AhciHwInterrupt( if ((portPending & (0x1 << nextPort)) == 0) continue; + NT_ASSERT(IsPortValid(AdapterExtension, nextPort)); + if ((nextPort == adapterExtension->LastInterruptPort) || (adapterExtension->PortExtension[nextPort].IsActive == FALSE)) { @@ -284,7 +347,11 @@ AhciHwInterrupt( // we can assign this interrupt to this port adapterExtension->LastInterruptPort = nextPort; - return AhciInterruptHandler(&adapterExtension->PortExtension[nextPort]); + AhciInterruptHandler(&adapterExtension->PortExtension[nextPort]); + + // interrupt belongs to this device + // should always return TRUE + return TRUE; } DebugPrint("\tSomething went wrong"); @@ -341,7 +408,7 @@ AhciHwStartIo ( { Srb->SrbStatus = SRB_STATUS_SUCCESS; adapterExtension->StateFlags.Removed = 1; - DebugPrint("\tadapter removed\n"); + DebugPrint("\tAdapter removed\n"); } else if (pnpRequest->PnPAction == StorStopDevice) { @@ -417,6 +484,7 @@ AhciHwResetBus ( __in ULONG PathId ) { + STOR_LOCK_HANDLE lockhandle; PAHCI_ADAPTER_EXTENSION adapterExtension; DebugPrint("AhciHwResetBus()\n"); @@ -425,7 +493,15 @@ AhciHwResetBus ( if (IsPortValid(AdapterExtension, PathId)) { - // TODO: Reset Port + AhciZeroMemory(&lockhandle, sizeof(lockhandle)); + + // Acquire Lock + StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle); + + // TODO: Perform port reset + + // Release lock + StorPortReleaseSpinLock(AdapterExtension, &lockhandle); } return FALSE; @@ -665,6 +741,182 @@ DriverEntry ( return status; }// -- DriverEntry(); +/** + * @name AhciProcessSrb + * @not_implemented + * + * Prepare Srb for IO processing + * + * @param PortExtension + * @param Srb + * + */ +VOID +AhciProcessSrb ( + __in PAHCI_PORT_EXTENSION PortExtension, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + DebugPrint("AhciProcessSrb()\n"); + + NT_ASSERT(Srb->PathId == PortExtension->PortNumber); + + return; +}// -- AhciProcessSrb(); + +/** + * @name AhciActivatePort + * @not_implemented + * + * Program Port and populate command list + * + * @param PortExtension + * + */ +VOID +AhciActivatePort ( + __in PAHCI_PORT_EXTENSION PortExtension + ) +{ + DebugPrint("AhciActivatePort()\n"); + + return; +}// -- AhciActivatePort(); + +/** + * @name AhciProcessIO + * @implemented + * + * Acquire Exclusive lock to port, populate pending commands to command List + * program controller's port to process new commands in command list. + * + * @param AdapterExtension + * @param PathId + * @param Srb + * + */ +VOID +AhciProcessIO ( + __in PAHCI_ADAPTER_EXTENSION AdapterExtension, + __in UCHAR PathId, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + STOR_LOCK_HANDLE lockhandle; + PSCSI_REQUEST_BLOCK tmpSrb; + PAHCI_PORT_EXTENSION PortExtension; + ULONG commandSlotMask, occupiedSlots, slotIndex; + + DebugPrint("AhciProcessIO()\n"); + DebugPrint("\tPathId: %d\n", PathId); + + PortExtension = &AdapterExtension->PortExtension[PathId]; + + NT_ASSERT(PathId < MAXIMUM_AHCI_PORT_COUNT); + + // 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); + + occupiedSlots = PortExtension->OccupiedSlots; // Busy command slots for given port + commandSlotMask = (1 << AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)) - 1; // available slots mask + + commandSlotMask = (commandSlotMask & ~occupiedSlots); + if(commandSlotMask != 0) + { + // iterate over HBA port slots + for (slotIndex = 0; slotIndex <= AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); slotIndex++) + { + // find first free slot + if ((commandSlotMask & (1 << slotIndex)) != 0) + { + tmpSrb = RemoveQueue(&PortExtension->SrbQueue); + if (tmpSrb != NULL) + { + NT_ASSERT(Srb->PathId == PathId); + AhciProcessSrb(PortExtension, tmpSrb); + } + else + { + break; + } + } + else + { + break; + } + } + } + + // program HBA port + AhciActivatePort(PortExtension); + + // Release Lock + StorPortReleaseSpinLock(AdapterExtension, &lockhandle); + + return; +}// -- AhciProcessIO(); + +/** + * @name DeviceInquiryRequest + * @implemented + * + * Tells wheather given port is implemented or not + * + * @param AdapterExtension + * @param Srb + * @param Cdb + * + * @return + * return STOR status for DeviceInquiryRequest + * + * @remark + * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf + */ +ULONG +DeviceInquiryRequest ( + __in PAHCI_ADAPTER_EXTENSION AdapterExtension, + __in PSCSI_REQUEST_BLOCK Srb, + __in PCDB Cdb + ) +{ + PVOID DataBuffer; + ULONG DataBufferLength; + + DebugPrint("DeviceInquiryRequest()\n"); + + // 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) + { + DebugPrint("\tEVPD Inquired\n"); + } + else + { + DebugPrint("\tVPD Inquired\n"); + + DataBuffer = Srb->DataBuffer; + DataBufferLength = Srb->DataTransferLength; + + if (DataBuffer == NULL) + { + return SRB_STATUS_INVALID_REQUEST; + } + + AhciZeroMemory(DataBuffer, DataBufferLength); + } + + AhciProcessIO(AdapterExtension, Srb->PathId, Srb); + return SRB_STATUS_SUCCESS; +}// -- DeviceInquiryRequest(); + /** * @name AhciAdapterReset * @implemented @@ -744,6 +996,8 @@ AhciZeroMemory ( { Buffer[i] = 0; } + + return; }// -- AhciZeroMemory(); /** @@ -776,111 +1030,65 @@ IsPortValid ( }// -- IsPortValid() /** - * @name AhciProcessIO - * @not_implemented - * - * Acquire Exclusive lock to port, populate pending commands to command List - * program controller's port to process new commands in command list. - * - * @param AdapterExtension - * @param pathId - * @param Srb - * - */ -VOID -AhciProcessIO ( - __in PAHCI_ADAPTER_EXTENSION AdapterExtension, - __in UCHAR pathId - ) -{ - STOR_LOCK_HANDLE lockhandle; - PAHCI_PORT_EXTENSION PortExtension; - ULONG commandSlotMask, occupiedSlots, slotIndex; - - DebugPrint("AhciProcessIO()\n"); - DebugPrint("\tPathId: %d\n", pathId); - - PortExtension = &AdapterExtension->PortExtension[pathId]; - - NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT); - - if (PortExtension->IsActive == FALSE) - return; // we should wait for device to get active - - AhciZeroMemory(&lockhandle, sizeof(lockhandle)); - - // Acquire Lock - StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle); - - occupiedSlots = PortExtension->OccupiedSlots; // Busy command slots for given port - commandSlotMask = (1 << AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)) - 1; // available slots mask - - commandSlotMask = (commandSlotMask & ~occupiedSlots); - if(commandSlotMask != 0) - { - for (slotIndex = 0; slotIndex <= AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); slotIndex++) - { - // find first free slot - if ((commandSlotMask & (1 << slotIndex)) != 0) - { - // TODO: remove from queue and process it - } - } - } - - // Release Lock - StorPortReleaseSpinLock(AdapterExtension, &lockhandle); -}// -- AhciProcessIO(); - -/** - * @name DeviceInquiryRequest + * @name AddQueue * @implemented * - * Tells wheather given port is implemented or not + * Add Srb to Queue * - * @param AdapterExtension + * @param Queue * @param Srb - * @param Cdb * * @return - * return STOR status for DeviceInquiryRequest + * return TRUE if Srb is successfully added to Queue * - * @remark - * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf */ -ULONG -DeviceInquiryRequest ( - __in PAHCI_ADAPTER_EXTENSION AdapterExtension, - __in PSCSI_REQUEST_BLOCK Srb, - __in PCDB Cdb +__inline +BOOLEAN +AddQueue ( + __inout PAHCI_QUEUE Queue, + __in PVOID Srb ) { - PVOID DataBuffer; - ULONG DataBufferLength; + NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE); + NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE); - DebugPrint("DeviceInquiryRequest()\n"); + if (Queue->Head == ((Queue->Tail + 1) % MAXIMUM_QUEUE_BUFFER_SIZE)) + return FALSE; - // 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) - { - DebugPrint("\tEVPD Inquired\n"); - } - else - { - DebugPrint("\tVPD Inquired\n"); + Queue->Buffer[Queue->Head++] = Srb; + Queue->Head %= MAXIMUM_QUEUE_BUFFER_SIZE; - DataBuffer = Srb->DataBuffer; - DataBufferLength = Srb->DataTransferLength; + return TRUE; +}// -- AddQueue(); - if (DataBuffer == NULL) - { - return SRB_STATUS_INVALID_REQUEST; - } +/** + * @name RemoveQueue + * @implemented + * + * Remove and return Srb from Queue + * + * @param Queue + * + * @return + * return Srb + * + */ +__inline +PVOID +RemoveQueue ( + __inout PAHCI_QUEUE Queue + ) +{ + PVOID Srb; - AhciZeroMemory(DataBuffer, DataBufferLength); - } + NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE); + NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE); - AhciProcessIO(AdapterExtension, Srb->PathId, Srb); - return SRB_STATUS_SUCCESS; -}// -- DeviceInquiryRequest(); + if (Queue->Head == Queue->Tail) + return NULL; + + Srb = Queue->Buffer[Queue->Tail++]; + Queue->Tail %= MAXIMUM_QUEUE_BUFFER_SIZE; + + return Srb; +}// -- RemoveQueue(); diff --git a/drivers/storage/storahci/storahci.h b/drivers/storage/storahci/storahci.h index 07a2749a916..41ddb43cf3a 100644 --- a/drivers/storage/storahci/storahci.h +++ b/drivers/storage/storahci/storahci.h @@ -11,6 +11,7 @@ #define DEBUG 1 #define MAXIMUM_AHCI_PORT_COUNT 12 +#define MAXIMUM_QUEUE_BUFFER_SIZE 255 #define MAXIMUM_TRANSFER_LENGTH (128*1024) // 128 KB // section 3.1.2 @@ -32,6 +33,35 @@ // ---- Support Structures --- // ////////////////////////////////////////////////////////////// +// section 3.3.5 +typedef union _AHCI_INTERRUPT_STATUS +{ + struct + { + ULONG DHRS:1; //Device to Host Register FIS Interrupt + ULONG PSS :1; //PIO Setup FIS Interrupt + ULONG DSS :1; //DMA Setup FIS Interrupt + ULONG SDBS :1; //Set Device Bits Interrupt + ULONG UFS :1; //Unknown FIS Interrupt + ULONG DPS :1; //Descriptor Processed + ULONG PCS :1; //Port Connect Change Status + ULONG DMPS :1; //Device Mechanical Presence Status (DMPS) + ULONG Reserved :14; + ULONG PRCS :1; //PhyRdy Change Status + ULONG IPMS :1; //Incorrect Port Multiplier Status + ULONG OFS :1; //Overflow Status + ULONG Reserved2 :1; + ULONG INFS :1; //Interface Non-fatal Error Status + ULONG IFS :1; //Interface Fatal Error Status + ULONG HBDS :1; //Host Bus Data Error Status + ULONG HBFS :1; //Host Bus Fatal Error Status + ULONG TFES :1; //Task File Error Status + ULONG CPDS :1; //Cold Port Detect Status + }; + + ULONG Status; +} AHCI_INTERRUPT_STATUS; + typedef struct _AHCI_FIS_DMA_SETUP { ULONG ULONG0_1; // FIS_TYPE_DMA_SETUP @@ -123,6 +153,13 @@ typedef struct _AHCI_SET_DEVICE_BITS_FIS UCHAR Reserved5[4]; } AHCI_SET_DEVICE_BITS_FIS; +typedef struct _AHCI_QUEUE +{ + PVOID Buffer[MAXIMUM_QUEUE_BUFFER_SIZE]; // because Storahci hold Srb queue of 255 size + ULONG Head; + ULONG Tail; +} AHCI_QUEUE, *PAHCI_QUEUE; + ////////////////////////////////////////////////////////////// // --------------------------- // ////////////////////////////////////////////////////////////// @@ -202,6 +239,7 @@ typedef struct _AHCI_PORT_EXTENSION ULONG OccupiedSlots; // slots to which we have already assigned task BOOLEAN IsActive; PAHCI_PORT Port; // AHCI Port Infomation + AHCI_QUEUE SrbQueue; PAHCI_RECEIVED_FIS ReceivedFIS; PAHCI_COMMAND_HEADER CommandList; STOR_DEVICE_POWER_STATE DevicePowerState; // Device Power State @@ -274,3 +312,16 @@ DeviceInquiryRequest ( __in PSCSI_REQUEST_BLOCK Srb, __in PCDB Cdb ); + +__inline +BOOLEAN +AddQueue ( + __inout PAHCI_QUEUE Queue, + __in PVOID Srb + ); + +__inline +PVOID +RemoveQueue ( + __inout PAHCI_QUEUE Queue + ); diff --git a/drivers/storage/storahci/storahci.inf b/drivers/storage/storahci/storahci.inf index b0e3c421d3f..f291c2b9462 100644 --- a/drivers/storage/storahci/storahci.inf +++ b/drivers/storage/storahci/storahci.inf @@ -65,7 +65,7 @@ HKR,,EventMessageFile,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\IoLogMsg.dll" HKR,,TypesSupported,%REG_DWORD%,7 [Strings] -ROS = "ROS" +ROS = "ReactOS" DeviceDesc = "AHCI SATA Driver" SATA_AHCI.DeviceDesc = "Standard SATA AHCI Controller"