[STORAHCI] Merge Storport Miniport driver by Aman Priyadarshi in GSoC.
authorAmine Khaldi <amine.khaldi@reactos.org>
Fri, 27 Jan 2017 10:11:30 +0000 (10:11 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Fri, 27 Jan 2017 10:11:30 +0000 (10:11 +0000)
svn path=/trunk/; revision=73604

reactos/drivers/storage/CMakeLists.txt
reactos/drivers/storage/storahci/CMakeLists.txt [new file with mode: 0644]
reactos/drivers/storage/storahci/Notes.txt [new file with mode: 0644]
reactos/drivers/storage/storahci/makefile [new file with mode: 0644]
reactos/drivers/storage/storahci/sources [new file with mode: 0644]
reactos/drivers/storage/storahci/storahci.c [new file with mode: 0644]
reactos/drivers/storage/storahci/storahci.h [new file with mode: 0644]
reactos/drivers/storage/storahci/storahci.inf [new file with mode: 0644]
reactos/drivers/storage/storahci/storahci.rc [new file with mode: 0644]

index ff51e59..44cd868 100644 (file)
@@ -6,3 +6,4 @@ add_subdirectory(floppy)
 add_subdirectory(ide)
 add_subdirectory(port)
 add_subdirectory(scsiport)
+#add_subdirectory(storahci)
diff --git a/reactos/drivers/storage/storahci/CMakeLists.txt b/reactos/drivers/storage/storahci/CMakeLists.txt
new file mode 100644 (file)
index 0000000..039ed8d
--- /dev/null
@@ -0,0 +1,11 @@
+add_definitions(-DDEBUG)
+
+list(APPEND SOURCE
+    storahci.c)
+
+add_library(storahci SHARED ${SOURCE} storahci.rc)
+
+set_module_type(storahci kernelmodedriver)
+add_importlibs(storahci storport ntoskrnl hal)
+add_cd_file(TARGET storahci DESTINATION reactos/system32/drivers NO_CAB FOR all)
+add_registry_inf(storahci.inf)
diff --git a/reactos/drivers/storage/storahci/Notes.txt b/reactos/drivers/storage/storahci/Notes.txt
new file mode 100644 (file)
index 0000000..cac4353
--- /dev/null
@@ -0,0 +1,168 @@
+AhciPortInitialize
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AhciAllocateResourceForAdapter
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AhciHwInitialize
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AhciInterruptHandler
+    Flags
+        NOT_IMPLEMENTED
+        TESTED
+    Comment
+        Fatal Error not supported
+        Error Recovery not supported
+        Complete Request Routine
+
+AhciHwInterrupt
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AhciHwStartIo
+    Flags
+        IMPLEMENTED
+        TESTED
+    Comment
+        Adapter based IO request not supported
+        Need to implement more srb functions
+
+AhciHwResetBus
+    Flags
+        NOT_IMPLEMENTED
+    Comment
+        Adapter master bus reset not implemented
+
+AhciHwFindAdapter
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+DriverEntry
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AhciATA_CFIS
+    Flags
+        IMPLEMENTED
+    Comment
+        Need to implement NCQ
+
+AhciATAPI_CFIS
+    Flags
+        NOT_IMPLEMENTED
+    Comment
+        Need to configure command table according to Srb function
+
+AhciBuild_PRDT
+    Flags
+        IMPLEMENTED
+    Comment
+        NONE
+
+AhciProcessSrb
+    Flags
+        IMPLEMENTED
+    Comment
+        Only ATA/ATAPI type CFIS supported
+        Also I am not sure about FIS alignment in SrbExtension.
+
+AhciActivatePort
+    Flags
+        IMPLEMENTED
+    Comment
+        NCQ not supported
+
+AhciProcessIO
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+DeviceInquiryRequest
+    Flags
+        IMPLEMENTED
+        TESTED
+    Comment
+        EVPD is not sending Data buffer for IDENTIFY command.
+        Need to implement VPD
+
+AhciAdapterReset
+    Flags
+        NOT_IMPLEMENTED
+    Comment
+        NONE
+
+AhciZeroMemory
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+IsPortValid
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AddQueue
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+RemoveQueue
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+        TESTED
+    Comment
+        NONE
+
+AhciCompleteIssuedSrb
+    Flags
+        IMPLEMENTED
+        FULLY_SUPPORTED
+    Comment
+        NONE
+
+InquiryCompletion
+    Flags
+        NOT_IMPLEMENTED
+    Comment
+        NONE
\ No newline at end of file
diff --git a/reactos/drivers/storage/storahci/makefile b/reactos/drivers/storage/storahci/makefile
new file mode 100644 (file)
index 0000000..756c299
--- /dev/null
@@ -0,0 +1,2 @@
+MINIMUM_NT_TARGET_VERSION=0x502
+!INCLUDE $(NTMAKEENV)\makefile.def
\ No newline at end of file
diff --git a/reactos/drivers/storage/storahci/sources b/reactos/drivers/storage/storahci/sources
new file mode 100644 (file)
index 0000000..a1772ae
--- /dev/null
@@ -0,0 +1,10 @@
+TARGETNAME = storahci
+TARGETTYPE = MINIPORT
+
+MSC_WARNING_LEVEL=/W4
+TARGETLIBS=$(DDK_LIB_PATH)\storport.lib
+
+INCLUDES   = %BUILD%\inc
+LIBS       = %BUILD%\lib
+SOURCES    = storahci.c \
+                        storahci.rc
diff --git a/reactos/drivers/storage/storahci/storahci.c b/reactos/drivers/storage/storahci/storahci.c
new file mode 100644 (file)
index 0000000..97138a6
--- /dev/null
@@ -0,0 +1,2570 @@
+/*
+ * PROJECT:        ReactOS Kernel
+ * LICENSE:        GNU GPLv2 only as published by the Free Software Foundation
+ * PURPOSE:        To Implement AHCI Miniport driver targeting storport NT 5.2
+ * PROGRAMMERS:    Aman Priyadarshi (aman.eureka@gmail.com)
+ */
+
+#include "storahci.h"
+
+/**
+ * @name AhciPortInitialize
+ * @implemented
+ *
+ * Initialize port by setting up PxCLB & PxFB Registers
+ *
+ * @param PortExtension
+ *
+ * @return
+ * Return true if intialization was successful
+ */
+BOOLEAN
+AhciPortInitialize (
+    __in PAHCI_PORT_EXTENSION PortExtension
+    )
+{
+    AHCI_PORT_CMD cmd;
+    PAHCI_MEMORY_REGISTERS abar;
+    ULONG mappedLength, portNumber, ticks;
+    PAHCI_ADAPTER_EXTENSION adapterExtension;
+    STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical;
+
+    AhciDebugPrint("AhciPortInitialize()\n");
+
+    adapterExtension = PortExtension->AdapterExtension;
+    abar = adapterExtension->ABAR_Address;
+    portNumber = PortExtension->PortNumber;
+
+    NT_ASSERT(abar != NULL);
+    NT_ASSERT(portNumber < adapterExtension->PortCount);
+
+    PortExtension->Port = &abar->PortList[portNumber];
+
+    commandListPhysical = StorPortGetPhysicalAddress(adapterExtension,
+                                                     NULL,
+                                                     PortExtension->CommandList,
+                                                     &mappedLength);
+
+    if ((mappedLength == 0) || ((commandListPhysical.LowPart % 1024) != 0))
+    {
+        AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
+        return FALSE;
+    }
+
+    receivedFISPhysical = StorPortGetPhysicalAddress(adapterExtension,
+                                                     NULL,
+                                                     PortExtension->ReceivedFIS,
+                                                     &mappedLength);
+
+    if ((mappedLength == 0) || ((receivedFISPhysical.LowPart % 256) != 0))
+    {
+        AhciDebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength);
+        return FALSE;
+    }
+
+    // Ensure that the controller is not in the running state by reading and examining each
+    // implemented port’s PxCMD register. If PxCMD.ST, PxCMD.CR, PxCMD.FRE and
+    // PxCMD.FR are all cleared, the port is in an idle state. Otherwise, the port is not idle and
+    // should be placed in the idle state prior to manipulating HBA and port specific registers.
+    // System software places a port into the idle state by clearing PxCMD.ST and waiting for
+    // PxCMD.CR to return ‘0’ when read. Software should wait at least 500 milliseconds for
+    // this to occur. If PxCMD.FRE is set to ‘1’, software should clear it to ‘0’ and wait at least
+    // 500 milliseconds for PxCMD.FR to return ‘0’ when read. If PxCMD.CR or PxCMD.FR do
+    // not clear to ‘0’ correctly, then software may attempt a port reset or a full HBA reset to recove
+
+    // TODO: Check if port is in idle state or not, if not then restart port
+    cmd.Status = StorPortReadRegisterUlong(adapterExtension, &PortExtension->Port->CMD);
+    if ((cmd.FR != 0) || (cmd.CR != 0) || (cmd.FRE != 0) || (cmd.ST != 0))
+    {
+        cmd.ST = 0;
+        cmd.FRE = 0;
+
+        ticks = 3;
+        do
+        {
+            StorPortStallExecution(50000);
+            cmd.Status = StorPortReadRegisterUlong(adapterExtension, &PortExtension->Port->CMD);
+            if (ticks == 0)
+            {
+                AhciDebugPrint("\tAttempt to reset port failed: %x\n", cmd);
+                return FALSE;
+            }
+            ticks--;
+        }
+        while(cmd.CR != 0 || cmd.FR != 0);
+    }
+
+    // 10.1.2 For each implemented port, system software shall allocate memory for and program:
+    //  PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
+    //  PxFB and PxFBU (if CAP.S64A is set to ‘1’)
+    // Note: Assuming 32bit support only
+    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLB, commandListPhysical.LowPart);
+    if (IsAdapterCAPS64(adapterExtension->CAP))
+    {
+        StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLBU, commandListPhysical.HighPart);
+    }
+
+    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FB, receivedFISPhysical.LowPart);
+    if (IsAdapterCAPS64(adapterExtension->CAP))
+    {
+        StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FBU, receivedFISPhysical.HighPart);
+    }
+
+    PortExtension->IdentifyDeviceDataPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension,
+                                                                                  NULL,
+                                                                                  PortExtension->IdentifyDeviceData,
+                                                                                  &mappedLength);
+
+    // set device power state flag to D0
+    PortExtension->DevicePowerState = StorPowerDeviceD0;
+
+    // clear pending interrupts
+    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->SERR, (ULONG)~0);
+    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->IS, (ULONG)~0);
+    StorPortWriteRegisterUlong(adapterExtension, adapterExtension->IS, (1 << PortExtension->PortNumber));
+
+    return TRUE;
+}// -- AhciPortInitialize();
+
+/**
+ * @name AhciAllocateResourceForAdapter
+ * @implemented
+ *
+ * Allocate memory from poll for required pointers
+ *
+ * @param AdapterExtension
+ * @param ConfigInfo
+ *
+ * @return
+ * return TRUE if allocation was successful
+ */
+BOOLEAN
+AhciAllocateResourceForAdapter (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
+    )
+{
+    PCHAR nonCachedExtension, tmp;
+    ULONG index, NCS, AlignedNCS;
+    ULONG portCount, portImplemented, nonCachedExtensionSize;
+    PAHCI_PORT_EXTENSION PortExtension;
+
+    AhciDebugPrint("AhciAllocateResourceForAdapter()\n");
+
+    NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
+    AlignedNCS = ROUND_UP(NCS, 8);
+
+    // get port count -- Number of set bits in `AdapterExtension->PortImplemented`
+    portCount = 0;
+    portImplemented = AdapterExtension->PortImplemented;
+
+    NT_ASSERT(portImplemented != 0);
+    for (index = MAXIMUM_AHCI_PORT_COUNT - 1; index > 0; index--)
+        if ((portImplemented & (1 << index)) != 0)
+            break;
+
+    portCount = index + 1;
+    AhciDebugPrint("\tPort Count: %d\n", portCount);
+
+    AdapterExtension->PortCount = portCount;
+    nonCachedExtensionSize =    sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
+                                sizeof(AHCI_RECEIVED_FIS) +
+                                sizeof(IDENTIFY_DEVICE_DATA);
+
+    // align nonCachedExtensionSize to 1024
+    nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024);
+
+    AdapterExtension->NonCachedExtension = StorPortGetUncachedExtension(AdapterExtension,
+                                                                        ConfigInfo,
+                                                                        nonCachedExtensionSize * portCount);
+
+    if (AdapterExtension->NonCachedExtension == NULL)
+    {
+        AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
+        return FALSE;
+    }
+
+    nonCachedExtension = AdapterExtension->NonCachedExtension;
+    AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount);
+
+    for (index = 0; index < portCount; index++)
+    {
+        PortExtension = &AdapterExtension->PortExtension[index];
+
+        PortExtension->DeviceParams.IsActive = FALSE;
+        if ((AdapterExtension->PortImplemented & (1 << index)) != 0)
+        {
+            PortExtension->PortNumber = index;
+            PortExtension->DeviceParams.IsActive = TRUE;
+            PortExtension->AdapterExtension = AdapterExtension;
+            PortExtension->CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension;
+
+            tmp = (PCHAR)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
+
+            PortExtension->ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp;
+            PortExtension->IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS));
+            PortExtension->MaxPortQueueDepth = NCS;
+            nonCachedExtension += nonCachedExtensionSize;
+        }
+    }
+
+    return TRUE;
+}// -- AhciAllocateResourceForAdapter();
+
+/**
+ * @name AhciStartPort
+ * @implemented
+ *
+ * Try to start the port device
+ *
+ * @param AdapterExtension
+ * @param PortExtension
+ *
+ */
+BOOLEAN
+AhciStartPort (
+    __in PAHCI_PORT_EXTENSION PortExtension
+    )
+{
+    ULONG index;
+    AHCI_PORT_CMD cmd;
+    AHCI_TASK_FILE_DATA tfd;
+    AHCI_INTERRUPT_ENABLE ie;
+    AHCI_SERIAL_ATA_STATUS ssts;
+    AHCI_SERIAL_ATA_CONTROL sctl;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    AhciDebugPrint("AhciStartPort()\n");
+
+    AdapterExtension = PortExtension->AdapterExtension;
+    cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
+
+    if ((cmd.FR == 1) && (cmd.CR == 1) && (cmd.FRE == 1) && (cmd.ST == 1))
+    {
+        // Already Running
+        return TRUE;
+    }
+
+    cmd.SUD = 1;
+    StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
+
+    if (((cmd.FR == 1) && (cmd.FRE == 0)) ||
+        ((cmd.CR == 1) && (cmd.ST == 0)))
+    {
+        AhciDebugPrint("\tCOMRESET\n");
+        // perform COMRESET
+        // section 10.4.2
+
+        // Software causes a port reset (COMRESET) by writing 1h to the PxSCTL.DET field to invoke a
+        // COMRESET on the interface and start a re-establishment of Phy layer communications. Software shall
+        // wait at least 1 millisecond before clearing PxSCTL.DET to 0h; this ensures that at least one COMRESET
+        // signal is sent over the interface. After clearing PxSCTL.DET to 0h, software should wait for
+        // communication to be re-established as indicated by PxSSTS.DET being set to 3h. Then software should
+        // write all 1s to the PxSERR register to clear any bits that were set as part of the port reset.
+
+        sctl.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL);
+        sctl.DET = 1;
+        StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL, sctl.Status);
+
+        StorPortStallExecution(1000);
+
+        sctl.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL);
+        sctl.DET = 0;
+        StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SCTL, sctl.Status);
+
+        // Poll DET to verify if a device is attached to the port
+        index = 0;
+        do
+        {
+            StorPortStallExecution(1000);
+            ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS);
+
+            index++;
+            if (ssts.DET != 0)
+            {
+                break;
+            }
+        }
+        while(index < 30);
+    }
+
+    ssts.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SSTS);
+    switch (ssts.DET)
+    {
+        case 0x3:
+            {
+                NT_ASSERT(cmd.ST == 0);
+
+                // make sure FIS Recieve is enabled (cmd.FRE)
+                index = 0;
+                do
+                {
+                    StorPortStallExecution(10000);
+                    cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
+                    cmd.FRE = 1;
+                    StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
+                    index++;
+                }
+                while((cmd.FR != 1) && (index < 3));
+
+                if (cmd.FR != 1)
+                {
+                    // failed to start FIS DMA engine
+                    // it can crash the driver later
+                    // so better to turn this port off
+                    return FALSE;
+                }
+
+                // start port channel
+                // set cmd.ST
+
+                NT_ASSERT(cmd.FRE == 1);
+                NT_ASSERT(cmd.CR == 0);
+
+                // why assert? well If we face such condition on DET = 0x3
+                // then we don't have port in idle state and hence before executing this part of code
+                // we must have restarted it.
+                tfd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->TFD);
+
+                if ((tfd.STS.BSY) || (tfd.STS.DRQ))
+                {
+                    AhciDebugPrint("\tUnhandled Case BSY-DRQ\n");
+                }
+
+                // clear pending interrupts
+                StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->SERR, (ULONG)~0);
+                StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IS, (ULONG)~0);
+                StorPortWriteRegisterUlong(AdapterExtension, AdapterExtension->IS, (1 << PortExtension->PortNumber));
+
+                // 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);
+                /* 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?
+
+                StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IE, ie.Status);
+
+                cmd.ST = 1;
+                StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
+                cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
+
+                if (cmd.ST != 1)
+                {
+                    AhciDebugPrint("\tFailed to start Port\n");
+                    return FALSE;
+                }
+
+                return TRUE;
+            }
+        default:
+            // unhandled case
+            AhciDebugPrint("\tDET == %x Unsupported\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;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    STOR_LOCK_HANDLE lockhandle = {0};
+    PAHCI_COMPLETION_ROUTINE CompletionRoutine;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(SystemArgument2);
+
+    AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n");
+
+    StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
+    Srb = RemoveQueue(&PortExtension->CompletionQueue);
+    StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
+
+    NT_ASSERT(Srb != NULL);
+
+    if (Srb->SrbStatus == SRB_STATUS_PENDING)
+    {
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;
+    }
+    else
+    {
+        return;
+    }
+
+    SrbExtension = GetSrbExtension(Srb);
+
+    CompletionRoutine = SrbExtension->CompletionRoutine;
+    NT_ASSERT(CompletionRoutine != NULL);
+
+    // now it's completion routine responsibility to set SrbStatus
+    CompletionRoutine(PortExtension, Srb);
+
+    StorPortNotification(RequestComplete, AdapterExtension, Srb);
+
+    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;
+
+    AhciDebugPrint("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
+ *
+ * initializes the HBA and finds all devices that are of interest to the miniport driver.
+ *
+ * @param adapterExtension
+ *
+ * @return
+ * return TRUE if intialization was successful
+ */
+BOOLEAN
+AhciHwInitialize (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+    )
+{
+    AHCI_GHC ghc;
+
+    AhciDebugPrint("AhciHwInitialize()\n");
+
+    AdapterExtension->StateFlags.MessagePerPort = FALSE;
+
+    // First check what type of interrupt/synchronization device is using
+    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.MRSM == 0)
+    {
+        AdapterExtension->StateFlags.MessagePerPort = TRUE;
+        AhciDebugPrint("\tMultiple MSI based message not supported\n");
+    }
+
+    StorPortEnablePassiveInitialization(AdapterExtension, AhciHwPassiveInitialize);
+
+    return TRUE;
+}// -- AhciHwInitialize();
+
+/**
+ * @name AhciCompleteIssuedSrb
+ * @implemented
+ *
+ * Complete issued Srbs
+ *
+ * @param PortExtension
+ *
+ */
+VOID
+AhciCompleteIssuedSrb (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in ULONG CommandsToComplete
+    )
+{
+    ULONG NCS, i;
+    PSCSI_REQUEST_BLOCK Srb;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    AhciDebugPrint("AhciCompleteIssuedSrb()\n");
+
+    NT_ASSERT(CommandsToComplete != 0);
+
+    AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete);
+
+    AdapterExtension = PortExtension->AdapterExtension;
+    NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
+
+    for (i = 0; i < NCS; i++)
+    {
+        if (((1 << i) & CommandsToComplete) != 0)
+        {
+            Srb = PortExtension->Slot[i];
+
+            if (Srb == NULL)
+            {
+                continue;
+            }
+
+            SrbExtension = GetSrbExtension(Srb);
+            NT_ASSERT(SrbExtension != NULL);
+
+            if (SrbExtension->CompletionRoutine != NULL)
+            {
+                AddQueue(&PortExtension->CompletionQueue, Srb);
+                StorPortIssueDpc(AdapterExtension, &PortExtension->CommandCompletion, PortExtension, Srb);
+            }
+            else
+            {
+                NT_ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
+                Srb->SrbStatus = SRB_STATUS_SUCCESS;
+                StorPortNotification(RequestComplete, AdapterExtension, Srb);
+            }
+        }
+    }
+
+    return;
+}// -- AhciCompleteIssuedSrb();
+
+/**
+ * @name AhciInterruptHandler
+ * @not_implemented
+ *
+ * Interrupt Handler for PortExtension
+ *
+ * @param PortExtension
+ *
+ */
+VOID
+AhciInterruptHandler (
+    __in PAHCI_PORT_EXTENSION PortExtension
+    )
+{
+    ULONG is, ci, sact, outstanding;
+    AHCI_INTERRUPT_STATUS PxIS;
+    AHCI_INTERRUPT_STATUS PxISMasked;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    AhciDebugPrint("AhciInterruptHandler()\n");
+    AhciDebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
+
+    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.
+
+        AhciDebugPrint("\tFatal 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);
+
+    ci = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CI);
+    sact = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SACT);
+
+    outstanding = ci | sact; // NOTE: Including both non-NCQ and NCQ based commands
+    if ((PortExtension->CommandIssuedSlots & (~outstanding)) != 0)
+    {
+        AhciCompleteIssuedSrb(PortExtension, (PortExtension->CommandIssuedSlots & (~outstanding)));
+        PortExtension->CommandIssuedSlots &= outstanding;
+    }
+
+    return;
+}// -- AhciInterruptHandler();
+
+/**
+ * @name AhciHwInterrupt
+ * @implemented
+ *
+ * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
+ *
+ * @param AdapterExtension
+ *
+ * @return
+ * return TRUE Indicates that an interrupt was pending on adapter.
+ * return FALSE Indicates the interrupt was not ours.
+ */
+BOOLEAN
+AhciHwInterrupt (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+    )
+{
+    ULONG portPending, nextPort, i, portCount;
+
+    if (AdapterExtension->StateFlags.Removed)
+    {
+        return FALSE;
+    }
+
+    portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS);
+
+    // we process interrupt for implemented ports only
+    portCount = AdapterExtension->PortCount;
+    portPending = portPending & AdapterExtension->PortImplemented;
+
+    if (portPending == 0)
+    {
+        return FALSE;
+    }
+
+    for (i = 1; i <= portCount; i++)
+    {
+        nextPort = (AdapterExtension->LastInterruptPort + i) % portCount;
+        if ((portPending & (0x1 << nextPort)) == 0)
+            continue;
+
+        NT_ASSERT(IsPortValid(AdapterExtension, nextPort));
+
+        if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE)
+        {
+            continue;
+        }
+
+        // we can assign this interrupt to this port
+        AdapterExtension->LastInterruptPort = nextPort;
+        AhciInterruptHandler(&AdapterExtension->PortExtension[nextPort]);
+
+        portPending &= ~(1 << nextPort);
+
+        // interrupt belongs to this device
+        // should always return TRUE
+        return TRUE;
+    }
+
+    AhciDebugPrint("\tSomething went wrong");
+    return FALSE;
+}// -- AhciHwInterrupt();
+
+/**
+ * @name AhciHwStartIo
+ * @not_implemented
+ *
+ * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
+ *
+ * @param adapterExtension
+ * @param Srb
+ *
+ * @return
+ * return TRUE if the request was accepted
+ * return FALSE if the request must be submitted later
+ */
+BOOLEAN
+AhciHwStartIo (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb
+    )
+{
+    AhciDebugPrint("AhciHwStartIo()\n");
+
+    if (!IsPortValid(AdapterExtension, Srb->PathId))
+    {
+        Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+        StorPortNotification(RequestComplete, AdapterExtension, Srb);
+        return TRUE;
+    }
+
+    switch(Srb->Function)
+    {
+        case SRB_FUNCTION_PNP:
+            {
+                // https://msdn.microsoft.com/windows/hardware/drivers/storage/handling-srb-function-pnp
+                // If the function member of an SRB is set to SRB_FUNCTION_PNP,
+                // the SRB is a structure of type SCSI_PNP_REQUEST_BLOCK.
+
+                PSCSI_PNP_REQUEST_BLOCK pnpRequest;
+                pnpRequest = (PSCSI_PNP_REQUEST_BLOCK)Srb;
+                if ((pnpRequest->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST) != 0)
+                {
+                    switch(pnpRequest->PnPAction)
+                    {
+                        case StorRemoveDevice:
+                        case StorSurpriseRemoval:
+                            {
+                                Srb->SrbStatus = SRB_STATUS_SUCCESS;
+                                AdapterExtension->StateFlags.Removed = 1;
+                                AhciDebugPrint("\tAdapter removed\n");
+                            }
+                            break;
+                        case StorStopDevice:
+                            {
+                                Srb->SrbStatus = SRB_STATUS_SUCCESS;
+                                AhciDebugPrint("\tRequested to Stop the adapter\n");
+                            }
+                            break;
+                        default:
+                            Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+                            break;
+                    }
+                }
+                else
+                {
+                    Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+                }
+            }
+            break;
+        case SRB_FUNCTION_EXECUTE_SCSI:
+            {
+                // 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:
+                //
+                // - Gets and/or sets up whatever context the miniport driver maintains in its device,
+                //   logical unit, and/or SRB extensions
+                //   For example, a miniport driver might set up a logical unit extension with pointers
+                //   to the SRB itself and the SRB DataBuffer pointer, the SRB DataTransferLength value,
+                //   and a driver-defined value (or CDB SCSIOP_XXX value) indicating the operation to be
+                //   carried out on the HBA.
+                //
+                // - Calls an internal routine to program the HBA, as partially directed by the SrbFlags,
+                //   for the requested operation
+                //   For a device I/O operation, such an internal routine generally selects the target device
+                //   and sends the CDB over the bus to the target logical unit.
+                PCDB cdb = (PCDB)&Srb->Cdb;
+                if (Srb->CdbLength == 0)
+                {
+                    AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
+                    Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
+                    break;
+                }
+
+                NT_ASSERT(cdb != NULL);
+
+                switch(cdb->CDB10.OperationCode)
+                {
+                    case SCSIOP_INQUIRY:
+                        Srb->SrbStatus = DeviceInquiryRequest(AdapterExtension, Srb, cdb);
+                        break;
+                    case SCSIOP_REPORT_LUNS:
+                        Srb->SrbStatus = DeviceReportLuns(AdapterExtension, Srb, cdb);
+                        break;
+                    case SCSIOP_READ_CAPACITY:
+                        Srb->SrbStatus = DeviceRequestCapacity(AdapterExtension, Srb, cdb);
+                        break;
+                    case SCSIOP_TEST_UNIT_READY:
+                        Srb->SrbStatus = DeviceRequestComplete(AdapterExtension, Srb, cdb);
+                        break;
+                    case SCSIOP_MODE_SENSE:
+                        Srb->SrbStatus = DeviceRequestSense(AdapterExtension, Srb, cdb);
+                        break;
+                    case SCSIOP_READ:
+                    case SCSIOP_WRITE:
+                        Srb->SrbStatus = DeviceRequestReadWrite(AdapterExtension, Srb, cdb);
+                        break;
+                    default:
+                        AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
+                        Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+                        break;
+                }
+            }
+            break;
+        default:
+            AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb->Function);
+            Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+            break;
+    }
+
+    if (Srb->SrbStatus != SRB_STATUS_PENDING)
+    {
+        StorPortNotification(RequestComplete, AdapterExtension, Srb);
+    }
+    else
+    {
+        AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
+    }
+    return TRUE;
+}// -- AhciHwStartIo();
+
+/**
+ * @name AhciHwResetBus
+ * @not_implemented
+ *
+ * The HwStorResetBus routine is called by the port driver to clear error conditions.
+ *
+ * @param adapterExtension
+ * @param PathId
+ *
+ * @return
+ * return TRUE if bus was successfully reset
+ */
+BOOLEAN
+AhciHwResetBus (
+    __in PVOID AdapterExtension,
+    __in ULONG PathId
+    )
+{
+    STOR_LOCK_HANDLE lockhandle = {0};
+    PAHCI_ADAPTER_EXTENSION adapterExtension;
+
+    AhciDebugPrint("AhciHwResetBus()\n");
+
+    adapterExtension = AdapterExtension;
+
+    if (IsPortValid(AdapterExtension, PathId))
+    {
+        // Acquire Lock
+        StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
+
+        // TODO: Perform port reset
+
+        // Release lock
+        StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
+    }
+
+    return FALSE;
+}// -- AhciHwResetBus();
+
+/**
+ * @name AhciHwFindAdapter
+ * @implemented
+ *
+ * The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
+ * HBA is supported and, if it is, to return configuration information about that adapter.
+ *
+ *  10.1 Platform Communication
+ *  http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
+
+ * @param DeviceExtension
+ * @param HwContext
+ * @param BusInformation
+ * @param ArgumentString
+ * @param ConfigInfo
+ * @param Reserved3
+ *
+ * @return
+ *      SP_RETURN_FOUND
+ *          Indicates that a supported HBA was found and that the HBA-relevant configuration information was successfully determined and set in the PORT_CONFIGURATION_INFORMATION structure.
+ *
+ *      SP_RETURN_ERROR
+ *          Indicates that an HBA was found but there was an error obtaining the configuration information. If possible, such an error should be logged with StorPortLogError.
+ *
+ *      SP_RETURN_BAD_CONFIG
+ *          Indicates that the supplied configuration information was invalid for the adapter.
+ *
+ *      SP_RETURN_NOT_FOUND
+ *          Indicates that no supported HBA was found for the supplied configuration information.
+ *
+ * @remarks Called by Storport.
+ */
+ULONG
+AhciHwFindAdapter (
+    __in PVOID AdapterExtension,
+    __in PVOID HwContext,
+    __in PVOID BusInformation,
+    __in PVOID ArgumentString,
+    __inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+    __in PBOOLEAN Reserved3
+    )
+{
+    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;
+    PAHCI_ADAPTER_EXTENSION adapterExtension;
+
+    AhciDebugPrint("AhciHwFindAdapter()\n");
+
+    UNREFERENCED_PARAMETER(HwContext);
+    UNREFERENCED_PARAMETER(BusInformation);
+    UNREFERENCED_PARAMETER(ArgumentString);
+    UNREFERENCED_PARAMETER(Reserved3);
+
+    adapterExtension = AdapterExtension;
+    adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
+    adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
+
+    // get PCI configuration header
+    pci_cfg_len = StorPortGetBusData(
+                        adapterExtension,
+                        PCIConfiguration,
+                        adapterExtension->SystemIoBusNumber,
+                        adapterExtension->SlotNumber,
+                        pci_cfg_buf,
+                        sizeof(PCI_COMMON_CONFIG));
+
+    if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG))
+    {
+        AhciDebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG), pci_cfg_len);
+        return SP_RETURN_ERROR;//Not a valid device at the given bus number
+    }
+
+    pciConfigData = (PPCI_COMMON_CONFIG)pci_cfg_buf;
+    adapterExtension->VendorID = pciConfigData->VendorID;
+    adapterExtension->DeviceID = pciConfigData->DeviceID;
+    adapterExtension->RevisionID = pciConfigData->RevisionID;
+    // The last PCI base address register (BAR[5], header offset 0x24) points to the AHCI base memory, it’s called ABAR (AHCI Base Memory Register).
+    adapterExtension->AhciBaseAddress = pciConfigData->u.type0.BaseAddresses[5] & (0xFFFFFFF0);
+
+    AhciDebugPrint("\tVendorID:%d  DeviceID:%d  RevisionID:%d\n", adapterExtension->VendorID,
+                                                              adapterExtension->DeviceID,
+                                                              adapterExtension->RevisionID);
+
+    // 2.1.11
+    abar = NULL;
+    if (ConfigInfo->NumberOfAccessRanges > 0)
+    {
+        accessRange = *(ConfigInfo->AccessRanges);
+        for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
+        {
+            if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
+            {
+                abar = StorPortGetDeviceBase(adapterExtension,
+                                             ConfigInfo->AdapterInterfaceType,
+                                             ConfigInfo->SystemIoBusNumber,
+                                             accessRange[index].RangeStart,
+                                             accessRange[index].RangeLength,
+                                             !accessRange[index].RangeInMemory);
+                break;
+            }
+        }
+    }
+
+    if (abar == NULL)
+    {
+        AhciDebugPrint("\tabar == NULL\n");
+        return SP_RETURN_ERROR; // corrupted information supplied
+    }
+
+    adapterExtension->ABAR_Address = abar;
+    adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
+    adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
+    adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
+    adapterExtension->LastInterruptPort = (ULONG)-1;
+
+    // 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.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
+    // AE := Highest Significant bit of GHC
+    if (ghc.AE != 0)// Hmm, controller was already in power state
+    {
+        // reset controller to have it in known state
+        AhciDebugPrint("\tAE Already set, Reset()\n");
+        if (!AhciAdapterReset(adapterExtension))
+        {
+            AhciDebugPrint("\tReset Failed!\n");
+            return SP_RETURN_ERROR;// reset failed
+        }
+    }
+
+    ghc.Status = 0;
+    ghc.AE = 1;// only AE=1
+    // tell the controller that we know about AHCI
+    StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
+
+    adapterExtension->IS = &abar->IS;
+    adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
+
+    if (adapterExtension->PortImplemented == 0)
+    {
+        AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n");
+        return SP_RETURN_ERROR;
+    }
+
+    ConfigInfo->Master = TRUE;
+    ConfigInfo->AlignmentMask = 0x3;
+    ConfigInfo->ScatterGather = TRUE;
+    ConfigInfo->DmaWidth = Width32Bits;
+    ConfigInfo->WmiDataProvider = FALSE;
+    ConfigInfo->Dma32BitAddresses = TRUE;
+
+    if (IsAdapterCAPS64(adapterExtension->CAP))
+    {
+        ConfigInfo->Dma64BitAddresses = TRUE;
+    }
+
+    ConfigInfo->MaximumNumberOfTargets = 1;
+    ConfigInfo->ResetTargetSupported = TRUE;
+    ConfigInfo->NumberOfPhysicalBreaks = 0x21;
+    ConfigInfo->MaximumNumberOfLogicalUnits = 1;
+    ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT;
+    ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
+    ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
+
+    // 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))
+    {
+        NT_ASSERT(FALSE);
+        return SP_RETURN_ERROR;
+    }
+
+    for (index = 0; index < adapterExtension->PortCount; index++)
+    {
+        if ((adapterExtension->PortImplemented & (0x1 << index)) != 0)
+            AhciPortInitialize(&adapterExtension->PortExtension[index]);
+    }
+
+    return SP_RETURN_FOUND;
+}// -- AhciHwFindAdapter();
+
+/**
+ * @name DriverEntry
+ * @implemented
+ *
+ * Initial Entrypoint for storahci miniport driver
+ *
+ * @param DriverObject
+ * @param RegistryPath
+ *
+ * @return
+ * NT_STATUS in case of driver loaded successfully.
+ */
+ULONG
+DriverEntry (
+    __in PVOID DriverObject,
+    __in PVOID RegistryPath
+    )
+{
+    ULONG status;
+    // initialize the hardware data structure
+    HW_INITIALIZATION_DATA hwInitializationData = {0};
+
+    // set size of hardware initialization structure
+    hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
+
+    // identity required miniport entry point routines
+    hwInitializationData.HwStartIo = AhciHwStartIo;
+    hwInitializationData.HwResetBus = AhciHwResetBus;
+    hwInitializationData.HwInterrupt = AhciHwInterrupt;
+    hwInitializationData.HwInitialize = AhciHwInitialize;
+    hwInitializationData.HwFindAdapter = AhciHwFindAdapter;
+
+    // adapter specific information
+    hwInitializationData.TaggedQueuing = TRUE;
+    hwInitializationData.AutoRequestSense = TRUE;
+    hwInitializationData.MultipleRequestPerLu = TRUE;
+    hwInitializationData.NeedPhysicalAddresses = TRUE;
+
+    hwInitializationData.NumberOfAccessRanges = 6;
+    hwInitializationData.AdapterInterfaceType = PCIBus;
+    hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
+
+    // set required extension sizes
+    hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
+    hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
+
+    // register our hw init data
+    status = StorPortInitialize(DriverObject,
+                                RegistryPath,
+                                &hwInitializationData,
+                                NULL);
+
+    NT_ASSERT(status == STATUS_SUCCESS);
+    return status;
+}// -- DriverEntry();
+
+/**
+ * @name AhciATA_CFIS
+ * @implemented
+ *
+ * create ATA CFIS from Srb
+ *
+ * @param PortExtension
+ * @param Srb
+ *
+ * @return
+ * Number of CFIS fields used in DWORD
+ */
+ULONG
+AhciATA_CFIS (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PAHCI_SRB_EXTENSION SrbExtension
+    )
+{
+    PAHCI_COMMAND_TABLE cmdTable;
+
+    UNREFERENCED_PARAMETER(PortExtension);
+
+    AhciDebugPrint("AhciATA_CFIS()\n");
+
+    cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
+
+    AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS));
+
+    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;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA0] = SrbExtension->LBA0;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA1] = SrbExtension->LBA1;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA2] = SrbExtension->LBA2;
+    cmdTable->CFIS[AHCI_ATA_CFIS_Device] = SrbExtension->Device;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA3] = SrbExtension->LBA3;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA4] = SrbExtension->LBA4;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA5] = SrbExtension->LBA5;
+    cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesHigh] = SrbExtension->FeaturesHigh;
+    cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountLow] = SrbExtension->SectorCountLow;
+    cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountHigh] = SrbExtension->SectorCountHigh;
+
+    return 5;
+}// -- AhciATA_CFIS();
+
+/**
+ * @name AhciATAPI_CFIS
+ * @not_implemented
+ *
+ * create ATAPI CFIS from Srb
+ *
+ * @param PortExtension
+ * @param Srb
+ *
+ * @return
+ * Number of CFIS fields used in DWORD
+ */
+ULONG
+AhciATAPI_CFIS (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PAHCI_SRB_EXTENSION SrbExtension
+    )
+{
+    PAHCI_COMMAND_TABLE cmdTable;
+    UNREFERENCED_PARAMETER(PortExtension);
+
+    AhciDebugPrint("AhciATAPI_CFIS()\n");
+
+    cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
+
+    NT_ASSERT(SrbExtension->CommandReg == IDE_COMMAND_ATAPI_PACKET);
+
+    AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS));
+
+    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;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA0] = SrbExtension->LBA0;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA1] = SrbExtension->LBA1;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA2] = SrbExtension->LBA2;
+    cmdTable->CFIS[AHCI_ATA_CFIS_Device] = SrbExtension->Device;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA3] = SrbExtension->LBA3;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA4] = SrbExtension->LBA4;
+    cmdTable->CFIS[AHCI_ATA_CFIS_LBA5] = SrbExtension->LBA5;
+    cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesHigh] = SrbExtension->FeaturesHigh;
+    cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountLow] = SrbExtension->SectorCountLow;
+    cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountHigh] = SrbExtension->SectorCountHigh;
+
+    return 5;
+}// -- AhciATAPI_CFIS();
+
+/**
+ * @name AhciBuild_PRDT
+ * @implemented
+ *
+ * Build PRDT for data transfer
+ *
+ * @param PortExtension
+ * @param Srb
+ *
+ * @return
+ * Return number of entries in PRDT.
+ */
+ULONG
+AhciBuild_PRDT (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PAHCI_SRB_EXTENSION SrbExtension
+    )
+{
+    ULONG index;
+    PAHCI_COMMAND_TABLE cmdTable;
+    PLOCAL_SCATTER_GATHER_LIST sgl;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    AhciDebugPrint("AhciBuild_PRDT()\n");
+
+    sgl = SrbExtension->pSgl;
+    cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
+    AdapterExtension = PortExtension->AdapterExtension;
+
+    NT_ASSERT(sgl != NULL);
+    NT_ASSERT(sgl->NumberOfElements < MAXIMUM_AHCI_PRDT_ENTRIES);
+
+    for (index = 0; index < sgl->NumberOfElements; index++)
+    {
+        NT_ASSERT(sgl->List[index].Length <= MAXIMUM_TRANSFER_LENGTH);
+
+        cmdTable->PRDT[index].DBA = sgl->List[index].PhysicalAddress.LowPart;
+        if (IsAdapterCAPS64(AdapterExtension->CAP))
+        {
+            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;
+}// -- AhciBuild_PRDT();
+
+/**
+ * @name AhciProcessSrb
+ * @implemented
+ *
+ * Prepare Srb for IO processing
+ *
+ * @param PortExtension
+ * @param Srb
+ * @param SlotIndex
+ *
+ */
+VOID
+AhciProcessSrb (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in ULONG SlotIndex
+    )
+{
+    ULONG prdtlen, sig, length, cfl;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_COMMAND_HEADER CommandHeader;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+    STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress;
+
+    AhciDebugPrint("AhciProcessSrb()\n");
+
+    NT_ASSERT(Srb->PathId == PortExtension->PortNumber);
+
+    SrbExtension = GetSrbExtension(Srb);
+    AdapterExtension = PortExtension->AdapterExtension;
+
+    NT_ASSERT(SrbExtension != NULL);
+    NT_ASSERT(SrbExtension->AtaFunction != 0);
+
+    if ((SrbExtension->AtaFunction == ATA_FUNCTION_ATA_IDENTIFY) &&
+        (SrbExtension->CommandReg == IDE_COMMAND_NOT_VALID))
+    {
+        // Here we are safe to check SIG register
+        sig = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SIG);
+        if (sig == 0x101)
+        {
+            AhciDebugPrint("\tATA Device Found!\n");
+            SrbExtension->CommandReg = IDE_COMMAND_IDENTIFY;
+        }
+        else
+        {
+            AhciDebugPrint("\tATAPI Device Found!\n");
+            SrbExtension->CommandReg = IDE_COMMAND_ATAPI_IDENTIFY;
+        }
+    }
+
+    NT_ASSERT(SlotIndex < AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
+    SrbExtension->SlotIndex = SlotIndex;
+
+    // program the CFIS in the CommandTable
+    CommandHeader = &PortExtension->CommandList[SlotIndex];
+
+    cfl = 0;
+    if (IsAtapiCommand(SrbExtension->AtaFunction))
+    {
+        cfl = AhciATAPI_CFIS(PortExtension, SrbExtension);
+    }
+    else if (IsAtaCommand(SrbExtension->AtaFunction))
+    {
+        cfl = AhciATA_CFIS(PortExtension, SrbExtension);
+    }
+    else
+    {
+        NT_ASSERT(FALSE);
+    }
+
+    prdtlen = 0;
+    if (IsDataTransferNeeded(SrbExtension))
+    {
+        prdtlen = AhciBuild_PRDT(PortExtension, SrbExtension);
+        NT_ASSERT(prdtlen != -1);
+    }
+
+    // Program the command header
+    CommandHeader->DI.PRDTL = prdtlen; // number of entries in PRD table
+    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
+
+    // Reset -- Manual Configuation
+    CommandHeader->DI.R = 0;
+    CommandHeader->DI.B = 0;
+    CommandHeader->DI.C = 0;
+
+    CommandHeader->PRDBC = 0;
+
+    CommandHeader->Reserved[0] = 0;
+    CommandHeader->Reserved[1] = 0;
+    CommandHeader->Reserved[2] = 0;
+    CommandHeader->Reserved[3] = 0;
+
+    // set CommandHeader CTBA
+    CommandTablePhysicalAddress = StorPortGetPhysicalAddress(AdapterExtension,
+                                                             NULL,
+                                                             SrbExtension,
+                                                             &length);
+
+    NT_ASSERT(length != 0);
+
+    // command table alignment
+    NT_ASSERT((CommandTablePhysicalAddress.LowPart % 128) == 0);
+
+    CommandHeader->CTBA = CommandTablePhysicalAddress.LowPart;
+
+    if (IsAdapterCAPS64(AdapterExtension->CAP))
+    {
+        CommandHeader->CTBA_U = CommandTablePhysicalAddress.HighPart;
+    }
+
+    // mark this slot
+    PortExtension->Slot[SlotIndex] = Srb;
+    PortExtension->QueueSlots |= 1 << SlotIndex;
+    return;
+}// -- AhciProcessSrb();
+
+/**
+ * @name AhciActivatePort
+ * @implemented
+ *
+ * Program Port and populate command list
+ *
+ * @param PortExtension
+ *
+ */
+VOID
+AhciActivatePort (
+    __in PAHCI_PORT_EXTENSION PortExtension
+    )
+{
+    AHCI_PORT_CMD cmd;
+    ULONG QueueSlots, slotToActivate, tmp;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    AhciDebugPrint("AhciActivatePort()\n");
+
+    AdapterExtension = PortExtension->AdapterExtension;
+    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’
+    cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
+
+    if (cmd.ST == 0) // PxCMD.ST == 0
+    {
+        return;
+    }
+
+    // get the lowest set bit
+    tmp = QueueSlots & (QueueSlots - 1);
+
+    if (tmp == 0)
+        slotToActivate = QueueSlots;
+    else
+        slotToActivate = (QueueSlots & (~tmp));
+
+    // mark that bit off in QueueSlots
+    // so we can know we it is really needed to activate port or not
+    PortExtension->QueueSlots &= ~slotToActivate;
+    // mark this CommandIssuedSlots
+    // to validate in completeIssuedCommand
+    PortExtension->CommandIssuedSlots |= slotToActivate;
+
+    // tell the HBA to issue this Command Slot to the given port
+    StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CI, slotToActivate);
+
+    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
+    )
+{
+    PSCSI_REQUEST_BLOCK tmpSrb;
+    STOR_LOCK_HANDLE lockhandle = {0};
+    PAHCI_PORT_EXTENSION PortExtension;
+    ULONG commandSlotMask, occupiedSlots, slotIndex, NCS;
+
+    AhciDebugPrint("AhciProcessIO()\n");
+    AhciDebugPrint("\tPathId: %d\n", PathId);
+
+    PortExtension = &AdapterExtension->PortExtension[PathId];
+
+    NT_ASSERT(PathId < AdapterExtension->PortCount);
+
+    // 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
+
+    commandSlotMask = (commandSlotMask & ~occupiedSlots);
+    if(commandSlotMask != 0)
+    {
+        // iterate over HBA port slots
+        for (slotIndex = 0; slotIndex < NCS; slotIndex++)
+        {
+            // find first free slot
+            if ((commandSlotMask & (1 << slotIndex)) != 0)
+            {
+                tmpSrb = RemoveQueue(&PortExtension->SrbQueue);
+                if (tmpSrb != NULL)
+                {
+                    NT_ASSERT(tmpSrb->PathId == PathId);
+                    AhciProcessSrb(PortExtension, tmpSrb, slotIndex);
+                }
+                else
+                {
+                    break;
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+
+    // program HBA port
+    AhciActivatePort(PortExtension);
+
+    // Release Lock
+    StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
+
+    return;
+}// -- AhciProcessIO();
+
+/**
+ * @name AtapiInquiryCompletion
+ * @implemented
+ *
+ * AtapiInquiryCompletion routine should be called after device signals
+ * for device inquiry request is completed (through interrupt) -- ATAPI Device only
+ *
+ * @param PortExtension
+ * @param Srb
+ *
+ */
+VOID
+AtapiInquiryCompletion (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PSCSI_REQUEST_BLOCK Srb
+    )
+{
+    BOOLEAN status;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    AhciDebugPrint("AtapiInquiryCompletion()\n");
+
+    NT_ASSERT(Srb != NULL);
+    NT_ASSERT(PortExtension != NULL);
+
+    AdapterExtension = PortExtension->AdapterExtension;
+
+    // send queue depth
+    status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
+                                         Srb->PathId,
+                                         Srb->TargetId,
+                                         Srb->Lun,
+                                         AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
+
+    NT_ASSERT(status == TRUE);
+    return;
+}// -- AtapiInquiryCompletion();
+
+/**
+ * @name InquiryCompletion
+ * @implemented
+ *
+ * InquiryCompletion routine should be called after device signals
+ * for device inquiry request is completed (through interrupt)
+ *
+ * @param PortExtension
+ * @param Srb
+ *
+ */
+VOID
+InquiryCompletion (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PSCSI_REQUEST_BLOCK Srb
+    )
+{
+    PCDB cdb;
+    BOOLEAN status;
+    PINQUIRYDATA InquiryData;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+    PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
+
+    AhciDebugPrint("InquiryCompletion()\n");
+
+    NT_ASSERT(Srb != NULL);
+    NT_ASSERT(PortExtension != NULL);
+
+    cdb = (PCDB)&Srb->Cdb;
+    InquiryData = Srb->DataBuffer;
+    SrbExtension = GetSrbExtension(Srb);
+    AdapterExtension = PortExtension->AdapterExtension;
+    IdentifyDeviceData = PortExtension->IdentifyDeviceData;
+
+    if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
+    {
+        if (Srb->SrbStatus == SRB_STATUS_NO_DEVICE)
+        {
+            PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
+        }
+        return;
+    }
+
+    NT_ASSERT(InquiryData != NULL);
+    NT_ASSERT(Srb->SrbStatus == SRB_STATUS_SUCCESS);
+
+    // Device specific data
+    PortExtension->DeviceParams.MaxLba.QuadPart = 0;
+
+    if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
+    {
+        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;
+
+        /* Device max address lba */
+        if (PortExtension->DeviceParams.Lba48BitMode)
+        {
+            PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->Max48BitLBA[0];
+            PortExtension->DeviceParams.MaxLba.HighPart = IdentifyDeviceData->Max48BitLBA[1];
+        }
+        else
+        {
+            PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->UserAddressableSectors;
+        }
+
+        /* Bytes Per Logical Sector */
+        if (IdentifyDeviceData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words)
+        {
+            AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n");
+            NT_ASSERT(FALSE);
+        }
+
+        PortExtension->DeviceParams.BytesPerLogicalSector = DEVICE_ATA_BLOCK_SIZE;
+
+        /* Bytes Per Physical Sector */
+        if (IdentifyDeviceData->PhysicalLogicalSectorSize.MultipleLogicalSectorsPerPhysicalSector)
+        {
+            AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n");
+            NT_ASSERT(FALSE);
+        }
+
+        PortExtension->DeviceParams.BytesPerPhysicalSector = DEVICE_ATA_BLOCK_SIZE;
+
+        // last byte should be NULL
+        StorPortCopyMemory(PortExtension->DeviceParams.VendorId, IdentifyDeviceData->ModelNumber, sizeof(PortExtension->DeviceParams.VendorId) - 1);
+        StorPortCopyMemory(PortExtension->DeviceParams.RevisionID, IdentifyDeviceData->FirmwareRevision, sizeof(PortExtension->DeviceParams.RevisionID) - 1);
+        StorPortCopyMemory(PortExtension->DeviceParams.SerialNumber, IdentifyDeviceData->SerialNumber, sizeof(PortExtension->DeviceParams.SerialNumber) - 1);
+
+        PortExtension->DeviceParams.VendorId[sizeof(PortExtension->DeviceParams.VendorId) - 1] = '\0';
+        PortExtension->DeviceParams.RevisionID[sizeof(PortExtension->DeviceParams.RevisionID) - 1] = '\0';
+        PortExtension->DeviceParams.SerialNumber[sizeof(PortExtension->DeviceParams.SerialNumber) - 1] = '\0';
+
+        // TODO: Add other device params
+        AhciDebugPrint("\tATA Device\n");
+    }
+    else
+    {
+        AhciDebugPrint("\tATAPI Device\n");
+        PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
+        PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
+    }
+
+    // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
+    if (Srb->DataTransferLength < INQUIRYDATABUFFERSIZE)
+    {
+        AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n");
+        NT_ASSERT(FALSE);
+    }
+
+    // update data transfer length
+    Srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+    // prepare data to send
+    InquiryData->Versions = 2;
+    InquiryData->Wide32Bit = 1;
+    InquiryData->CommandQueue = 0; // NCQ not supported
+    InquiryData->ResponseDataFormat = 0x2;
+    InquiryData->DeviceTypeModifier = 0;
+    InquiryData->DeviceTypeQualifier = DEVICE_CONNECTED;
+    InquiryData->AdditionalLength = INQUIRYDATABUFFERSIZE - 5;
+    InquiryData->DeviceType = PortExtension->DeviceParams.AccessType;
+    InquiryData->RemovableMedia = PortExtension->DeviceParams.RemovableDevice;
+
+    // Fill VendorID, Product Revision Level and other string fields
+    StorPortCopyMemory(InquiryData->VendorId, PortExtension->DeviceParams.VendorId, sizeof(InquiryData->VendorId) - 1);
+    StorPortCopyMemory(InquiryData->ProductId, PortExtension->DeviceParams.RevisionID, sizeof(PortExtension->DeviceParams.RevisionID));
+    StorPortCopyMemory(InquiryData->ProductRevisionLevel, PortExtension->DeviceParams.SerialNumber, sizeof(InquiryData->ProductRevisionLevel) - 1);
+
+    InquiryData->VendorId[sizeof(InquiryData->VendorId) - 1] = '\0';
+    InquiryData->ProductId[sizeof(InquiryData->ProductId) - 1] = '\0';
+    InquiryData->ProductRevisionLevel[sizeof(InquiryData->ProductRevisionLevel) - 1] = '\0';
+
+    // send queue depth
+    status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
+                                         Srb->PathId,
+                                         Srb->TargetId,
+                                         Srb->Lun,
+                                         AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
+
+    NT_ASSERT(status == TRUE);
+    return;
+}// -- InquiryCompletion();
+
+ /**
+ * @name AhciATAPICommand
+ * @implemented
+ *
+ * Handles ATAPI Requests commands
+ *
+ * @param AdapterExtension
+ * @param Srb
+ * @param Cdb
+ *
+ * @return
+ * return STOR status for AhciATAPICommand
+ */
+UCHAR
+AhciATAPICommand (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    ULONG SrbFlags, DataBufferLength;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_PORT_EXTENSION PortExtension;
+
+    AhciDebugPrint("AhciATAPICommand()\n");
+
+    SrbFlags = Srb->SrbFlags;
+    SrbExtension = GetSrbExtension(Srb);
+    DataBufferLength = Srb->DataTransferLength;
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    NT_ASSERT(PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI);
+
+    NT_ASSERT(SrbExtension != NULL);
+
+    SrbExtension->AtaFunction = ATA_FUNCTION_ATAPI_COMMAND;
+    SrbExtension->Flags = 0;
+
+    if (SrbFlags & SRB_FLAGS_DATA_IN)
+    {
+        SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
+    }
+
+    if (SrbFlags & SRB_FLAGS_DATA_OUT)
+    {
+        SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
+    }
+
+    SrbExtension->FeaturesLow = 0;
+
+    SrbExtension->CompletionRoutine = NULL;
+
+    NT_ASSERT(Cdb != NULL);
+    switch(Cdb->CDB10.OperationCode)
+    {
+        case SCSIOP_INQUIRY:
+            SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
+            SrbExtension->CompletionRoutine = AtapiInquiryCompletion;
+            break;
+        case SCSIOP_READ:
+            SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
+            SrbExtension->FeaturesLow = 0x5;
+            break;
+        case SCSIOP_WRITE:
+            SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
+            SrbExtension->FeaturesLow = 0x1;
+            break;
+    }
+
+    SrbExtension->CommandReg = IDE_COMMAND_ATAPI_PACKET;
+
+    SrbExtension->LBA0 = 0;
+    SrbExtension->LBA1 = (UCHAR)(DataBufferLength >> 0);
+    SrbExtension->LBA2 = (UCHAR)(DataBufferLength >> 8);
+    SrbExtension->Device = 0;
+    SrbExtension->LBA3 = 0;
+    SrbExtension->LBA4 = 0;
+    SrbExtension->LBA5 = 0;
+    SrbExtension->FeaturesHigh = 0;
+    SrbExtension->SectorCountLow = 0;
+    SrbExtension->SectorCountHigh = 0;
+
+    if ((SrbExtension->Flags & ATA_FLAGS_DATA_IN) || (SrbExtension->Flags & ATA_FLAGS_DATA_OUT))
+    {
+        SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb);
+    }
+
+    return SRB_STATUS_PENDING;
+}// -- AhciATAPICommand();
+
+/**
+ * @name DeviceRequestSense
+ * @implemented
+ *
+ * Handle SCSIOP_MODE_SENSE OperationCode
+ *
+ * @param AdapterExtension
+ * @param Srb
+ * @param Cdb
+ *
+ * @return
+ * return STOR status for DeviceRequestSense
+ */
+UCHAR
+DeviceRequestSense (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    PMODE_PARAMETER_HEADER ModeHeader;
+    PAHCI_PORT_EXTENSION PortExtension;
+
+    AhciDebugPrint("DeviceRequestSense()\n");
+
+    NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
+    NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_MODE_SENSE);
+
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
+    {
+        return AhciATAPICommand(AdapterExtension, Srb, Cdb);
+    }
+
+    ModeHeader = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
+
+    NT_ASSERT(ModeHeader != NULL);
+
+    AhciZeroMemory((PCHAR)ModeHeader, Srb->DataTransferLength);
+
+    ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER);
+    ModeHeader->MediumType = 0;
+    ModeHeader->DeviceSpecificParameter = 0;
+    ModeHeader->BlockDescriptorLength = 0;
+
+    if (Cdb->MODE_SENSE.PageCode == MODE_SENSE_CURRENT_VALUES)
+    {
+        ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
+        ModeHeader->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
+    }
+
+    return SRB_STATUS_SUCCESS;
+}// -- DeviceRequestSense();
+
+/**
+ * @name DeviceRequestReadWrite
+ * @implemented
+ *
+ * Handle SCSIOP_READ SCSIOP_WRITE OperationCode
+ *
+ * @param AdapterExtension
+ * @param Srb
+ * @param Cdb
+ *
+ * @return
+ * return STOR status for DeviceRequestReadWrite
+ */
+UCHAR
+DeviceRequestReadWrite (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    BOOLEAN IsReading;
+    ULONG64 StartOffset;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_PORT_EXTENSION PortExtension;
+    ULONG DataTransferLength, BytesPerSector, SectorCount;
+
+    AhciDebugPrint("DeviceRequestReadWrite()\n");
+
+    NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
+    NT_ASSERT((Cdb->CDB10.OperationCode == SCSIOP_READ) || (Cdb->CDB10.OperationCode == SCSIOP_WRITE));
+
+    SrbExtension = GetSrbExtension(Srb);
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
+    {
+        return AhciATAPICommand(AdapterExtension, Srb, Cdb);
+    }
+
+    DataTransferLength = Srb->DataTransferLength;
+    BytesPerSector = PortExtension->DeviceParams.BytesPerLogicalSector;
+
+    NT_ASSERT(BytesPerSector > 0);
+
+    //ROUND_UP(DataTransferLength, BytesPerSector);
+
+    SectorCount = DataTransferLength / BytesPerSector;
+
+    Srb->DataTransferLength = SectorCount * BytesPerSector;
+
+    StartOffset = AhciGetLba(Cdb, Srb->CdbLength);
+    IsReading = (Cdb->CDB10.OperationCode == SCSIOP_READ);
+
+    NT_ASSERT(SectorCount > 0);
+
+    SrbExtension->AtaFunction = ATA_FUNCTION_ATA_READ;
+    SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
+    SrbExtension->CompletionRoutine = NULL;
+
+    if (IsReading)
+    {
+        SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
+        SrbExtension->CommandReg = IDE_COMMAND_READ_DMA;
+    }
+    else
+    {
+        SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
+        SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA;
+    }
+
+    SrbExtension->FeaturesLow = 0;
+    SrbExtension->LBA0 = (StartOffset >> 0) & 0xFF;
+    SrbExtension->LBA1 = (StartOffset >> 8) & 0xFF;
+    SrbExtension->LBA2 = (StartOffset >> 16) & 0xFF;
+
+    SrbExtension->Device = (0xA0 | IDE_LBA_MODE);
+
+    if (PortExtension->DeviceParams.Lba48BitMode)
+    {
+        SrbExtension->Flags |= ATA_FLAGS_48BIT_COMMAND;
+
+        if (IsReading)
+        {
+            SrbExtension->CommandReg = IDE_COMMAND_READ_DMA_EXT;
+        }
+        else
+        {
+            SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA_EXT;
+        }
+
+        SrbExtension->LBA3 = (StartOffset >> 24) & 0xFF;
+        SrbExtension->LBA4 = (StartOffset >> 32) & 0xFF;
+        SrbExtension->LBA5 = (StartOffset >> 40) & 0xFF;
+    }
+    else
+    {
+        NT_ASSERT(FALSE);
+    }
+
+    SrbExtension->FeaturesHigh = 0;
+    SrbExtension->SectorCountLow = (SectorCount >> 0) & 0xFF;
+    SrbExtension->SectorCountHigh = (SectorCount >> 8) & 0xFF;
+
+    NT_ASSERT(SectorCount < 0x100);
+
+    SrbExtension->pSgl = (PLOCAL_SCATTER_GATHER_LIST)StorPortGetScatterGatherList(AdapterExtension, Srb);
+
+    return SRB_STATUS_PENDING;
+}// -- DeviceRequestReadWrite();
+
+/**
+ * @name DeviceRequestCapacity
+ * @implemented
+ *
+ * Handle SCSIOP_READ_CAPACITY OperationCode
+ *
+ * @param AdapterExtension
+ * @param Srb
+ * @param Cdb
+ *
+ * @return
+ * return STOR status for DeviceRequestCapacity
+ */
+UCHAR
+DeviceRequestCapacity (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    ULONG MaxLba, BytesPerLogicalSector;
+    PREAD_CAPACITY_DATA ReadCapacity;
+    PAHCI_PORT_EXTENSION PortExtension;
+
+    AhciDebugPrint("DeviceRequestCapacity()\n");
+
+    UNREFERENCED_PARAMETER(AdapterExtension);
+    UNREFERENCED_PARAMETER(Cdb);
+
+    NT_ASSERT(Srb->DataBuffer != NULL);
+    NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
+
+
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
+    {
+        return AhciATAPICommand(AdapterExtension, Srb, Cdb);
+    }
+
+    if (Cdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY)
+    {
+        ReadCapacity = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
+
+        BytesPerLogicalSector = PortExtension->DeviceParams.BytesPerLogicalSector;
+        MaxLba = (ULONG)PortExtension->DeviceParams.MaxLba.QuadPart - 1;
+
+        // I trust you windows :D
+        NT_ASSERT(Srb->DataTransferLength >= sizeof(READ_CAPACITY_DATA));
+
+        // I trust you user :D
+        NT_ASSERT(PortExtension->DeviceParams.MaxLba.QuadPart < (ULONG)-1);
+
+        // Actually I don't trust anyone :p
+        Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
+
+        REVERSE_BYTES(&ReadCapacity->BytesPerBlock, &BytesPerLogicalSector);
+        REVERSE_BYTES(&ReadCapacity->LogicalBlockAddress, &MaxLba);
+    }
+    else
+    {
+        AhciDebugPrint("\tSCSIOP_READ_CAPACITY16 not supported\n");
+        NT_ASSERT(FALSE);
+    }
+
+    return SRB_STATUS_SUCCESS;
+}// -- DeviceRequestCapacity();
+
+/**
+ * @name DeviceRequestComplete
+ * @implemented
+ *
+ * Handle UnHandled Requests
+ *
+ * @param AdapterExtension
+ * @param Srb
+ * @param Cdb
+ *
+ * @return
+ * return STOR status for DeviceRequestComplete
+ */
+UCHAR
+DeviceRequestComplete (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    AhciDebugPrint("DeviceRequestComplete()\n");
+
+    UNREFERENCED_PARAMETER(AdapterExtension);
+    UNREFERENCED_PARAMETER(Cdb);
+
+    Srb->ScsiStatus = SCSISTAT_GOOD;
+
+    return SRB_STATUS_SUCCESS;
+}// -- DeviceRequestComplete();
+
+/**
+ * @name DeviceReportLuns
+ * @implemented
+ *
+ * Handle SCSIOP_REPORT_LUNS OperationCode
+ *
+ * @param AdapterExtension
+ * @param Srb
+ * @param Cdb
+ *
+ * @return
+ * return STOR status for DeviceReportLuns
+ */
+UCHAR
+DeviceReportLuns (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    PLUN_LIST LunList;
+    PAHCI_PORT_EXTENSION PortExtension;
+
+    AhciDebugPrint("DeviceReportLuns()\n");
+
+    UNREFERENCED_PARAMETER(Cdb);
+
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    NT_ASSERT(Srb->DataTransferLength >= sizeof(LUN_LIST));
+    NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS);
+
+    if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
+    {
+        return AhciATAPICommand(AdapterExtension, Srb, Cdb);
+    }
+
+    LunList = (PLUN_LIST)Srb->DataBuffer;
+
+    NT_ASSERT(LunList != NULL);
+
+    AhciZeroMemory((PCHAR)LunList, sizeof(LUN_LIST));
+
+    LunList->LunListLength[3] = 8;
+
+    Srb->ScsiStatus = SCSISTAT_GOOD;
+    Srb->DataTransferLength = sizeof(LUN_LIST);
+
+    return SRB_STATUS_SUCCESS;
+}// -- DeviceReportLuns();
+
+/**
+ * @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
+ */
+UCHAR
+DeviceInquiryRequest (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    )
+{
+    PVOID DataBuffer;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_PORT_EXTENSION PortExtension;
+    PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
+    ULONG DataBufferLength, RequiredDataBufferLength;
+
+    AhciDebugPrint("DeviceInquiryRequest()\n");
+
+    NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_INQUIRY);
+    NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
+
+    SrbExtension = GetSrbExtension(Srb);
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
+    {
+        return AhciATAPICommand(AdapterExtension, Srb, Cdb);
+    }
+
+    if (Srb->Lun != 0)
+    {
+        return SRB_STATUS_SELECTION_TIMEOUT;
+    }
+    else if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
+    {
+        // 3.6.1
+        // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
+        AhciDebugPrint("\tEVPD Inquired\n");
+        NT_ASSERT(SrbExtension != NULL);
+
+        SrbExtension->AtaFunction = ATA_FUNCTION_ATA_IDENTIFY;
+        SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
+        SrbExtension->CompletionRoutine = InquiryCompletion;
+        SrbExtension->CommandReg = IDE_COMMAND_NOT_VALID;
+
+        // TODO: Should use AhciZeroMemory
+        SrbExtension->FeaturesLow = 0;
+        SrbExtension->LBA0 = 0;
+        SrbExtension->LBA1 = 0;
+        SrbExtension->LBA2 = 0;
+        SrbExtension->Device = 0xA0;
+        SrbExtension->LBA3 = 0;
+        SrbExtension->LBA4 = 0;
+        SrbExtension->LBA5 = 0;
+        SrbExtension->FeaturesHigh = 0;
+        SrbExtension->SectorCountLow = 0;
+        SrbExtension->SectorCountHigh = 0;
+
+        SrbExtension->Sgl.NumberOfElements = 1;
+        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);
+
+        SrbExtension->pSgl = &SrbExtension->Sgl;
+        return SRB_STATUS_PENDING;
+    }
+    else
+    {
+        AhciDebugPrint("\tVPD Inquired\n");
+
+        DataBuffer = Srb->DataBuffer;
+        DataBufferLength = Srb->DataTransferLength;
+        RequiredDataBufferLength = DataBufferLength; // make the compiler happy :p
+
+        if (DataBuffer == NULL)
+        {
+            return SRB_STATUS_INVALID_REQUEST;
+        }
+
+        AhciZeroMemory(DataBuffer, DataBufferLength);
+
+        switch(Cdb->CDB6INQUIRY3.PageCode)
+        {
+            case VPD_SUPPORTED_PAGES:
+                {
+                    AhciDebugPrint("\tVPD_SUPPORTED_PAGES\n");
+                    RequiredDataBufferLength = sizeof(VPD_SUPPORTED_PAGES_PAGE) + 1;
+
+                    if (DataBufferLength < RequiredDataBufferLength)
+                    {
+                        AhciDebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength, RequiredDataBufferLength);
+                        return SRB_STATUS_INVALID_REQUEST;
+                    }
+
+                    VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer;
+
+                    VpdOutputBuffer->DeviceType = PortExtension->DeviceParams.AccessType;
+                    VpdOutputBuffer->DeviceTypeQualifier = 0;
+                    VpdOutputBuffer->PageCode = VPD_SUPPORTED_PAGES;
+                    VpdOutputBuffer->PageLength = 1;
+                    VpdOutputBuffer->SupportedPageList[0] = VPD_SUPPORTED_PAGES;
+                    //VpdOutputBuffer->SupportedPageList[1] = VPD_SERIAL_NUMBER;
+                    //VpdOutputBuffer->SupportedPageList[2] = VPD_DEVICE_IDENTIFIERS;
+
+                    NT_ASSERT(VpdOutputBuffer->DeviceType == DIRECT_ACCESS_DEVICE);
+                }
+                break;
+            case VPD_SERIAL_NUMBER:
+                {
+                    AhciDebugPrint("\tVPD_SERIAL_NUMBER\n");
+                }
+                break;
+            case VPD_DEVICE_IDENTIFIERS:
+                {
+                    AhciDebugPrint("\tVPD_DEVICE_IDENTIFIERS\n");
+                }
+                break;
+            default:
+                AhciDebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode);
+                return SRB_STATUS_INVALID_REQUEST;
+        }
+
+        Srb->DataTransferLength = RequiredDataBufferLength;
+        return SRB_STATUS_SUCCESS;
+    }
+}// -- DeviceInquiryRequest();
+
+/**
+ * @name AhciAdapterReset
+ * @implemented
+ *
+ * 10.4.3 HBA Reset
+ * If the HBA becomes unusable for multiple ports, and a software reset or port reset does not correct the
+ * problem, software may reset the entire HBA by setting GHC.HR to ‘1’. When software sets the GHC.HR
+ * bit to ‘1’, the HBA shall perform an internal reset action. The bit shall be cleared to ‘0’ by the HBA when
+ * the reset is complete. A software write of ‘0’ to GHC.HR shall have no effect. To perform the HBA reset,
+ * software sets GHC.HR to ‘1’ and may poll until this bit is read to be ‘0’, at which point software knows that
+ * the HBA reset has completed.
+ * If the HBA has not cleared GHC.HR to ‘0’ within 1 second of software setting GHC.HR to ‘1’, the HBA is in
+ * a hung or locked state.
+ *
+ * @param AdapterExtension
+ *
+ * @return
+ * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
+ */
+BOOLEAN
+AhciAdapterReset (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+    )
+{
+    ULONG ticks;
+    AHCI_GHC ghc;
+    PAHCI_MEMORY_REGISTERS abar = NULL;
+
+    AhciDebugPrint("AhciAdapterReset()\n");
+
+    abar = AdapterExtension->ABAR_Address;
+    if (abar == NULL) // basic sanity
+    {
+        return FALSE;
+    }
+
+    // HR -- Very first bit (lowest significant)
+    ghc.HR = 1;
+    StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status);
+
+    for (ticks = 0; ticks < 50; ++ticks)
+    {
+        ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
+        if (ghc.HR == 0)
+        {
+            break;
+        }
+        StorPortStallExecution(20000);
+    }
+
+    if (ticks == 50)// 1 second
+    {
+        AhciDebugPrint("\tDevice Timeout\n");
+        return FALSE;
+    }
+
+    return TRUE;
+}// -- AhciAdapterReset();
+
+/**
+ * @name AhciZeroMemory
+ * @implemented
+ *
+ * Clear buffer by filling zeros
+ *
+ * @param Buffer
+ * @param BufferSize
+ */
+__inline
+VOID
+AhciZeroMemory (
+    __out PCHAR Buffer,
+    __in ULONG BufferSize
+    )
+{
+    ULONG i;
+    for (i = 0; i < BufferSize; i++)
+    {
+        Buffer[i] = 0;
+    }
+
+    return;
+}// -- AhciZeroMemory();
+
+/**
+ * @name IsPortValid
+ * @implemented
+ *
+ * Tells wheather given port is implemented or not
+ *
+ * @param AdapterExtension
+ * @param PathId
+ *
+ * @return
+ * return TRUE if provided port is valid (implemented) or not
+ */
+__inline
+BOOLEAN
+IsPortValid (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in ULONG pathId
+    )
+{
+    NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
+
+    if (pathId >= AdapterExtension->PortCount)
+    {
+        return FALSE;
+    }
+
+    return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive;
+}// -- IsPortValid()
+
+/**
+ * @name AddQueue
+ * @implemented
+ *
+ * Add Srb to Queue
+ *
+ * @param Queue
+ * @param Srb
+ *
+ * @return
+ * return TRUE if Srb is successfully added to Queue
+ *
+ */
+__inline
+BOOLEAN
+AddQueue (
+    __inout PAHCI_QUEUE Queue,
+    __in PVOID Srb
+    )
+{
+    NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
+    NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
+
+    if (Queue->Tail == ((Queue->Head + 1) % MAXIMUM_QUEUE_BUFFER_SIZE))
+        return FALSE;
+
+    Queue->Buffer[Queue->Head++] = Srb;
+    Queue->Head %= MAXIMUM_QUEUE_BUFFER_SIZE;
+
+    return TRUE;
+}// -- AddQueue();
+
+/**
+ * @name RemoveQueue
+ * @implemented
+ *
+ * Remove and return Srb from Queue
+ *
+ * @param Queue
+ *
+ * @return
+ * return Srb
+ *
+ */
+__inline
+PVOID
+RemoveQueue (
+    __inout PAHCI_QUEUE Queue
+    )
+{
+    PVOID Srb;
+
+    NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
+    NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
+
+    if (Queue->Head == Queue->Tail)
+        return NULL;
+
+    Srb = Queue->Buffer[Queue->Tail++];
+    Queue->Tail %= MAXIMUM_QUEUE_BUFFER_SIZE;
+
+    return Srb;
+}// -- RemoveQueue();
+
+/**
+ * @name GetSrbExtension
+ * @implemented
+ *
+ * GetSrbExtension from Srb make sure It is properly aligned
+ *
+ * @param Srb
+ *
+ * @return
+ * return SrbExtension
+ *
+ */
+__inline
+PAHCI_SRB_EXTENSION
+GetSrbExtension (
+    __in PSCSI_REQUEST_BLOCK Srb
+    )
+{
+    ULONG Offset;
+    ULONG_PTR SrbExtension;
+
+    SrbExtension = (ULONG_PTR)Srb->SrbExtension;
+    Offset = SrbExtension % 128;
+
+    // CommandTable should be 128 byte aligned
+    if (Offset != 0)
+        Offset = 128 - Offset;
+
+    return (PAHCI_SRB_EXTENSION)(SrbExtension + Offset);
+}// -- PAHCI_SRB_EXTENSION();
+
+/**
+ * @name AhciGetLba
+ * @implemented
+ *
+ * Find the logical address of demand block from Cdb
+ *
+ * @param Srb
+ *
+ * @return
+ * return Logical Address of the block
+ *
+ */
+__inline
+ULONG64
+AhciGetLba (
+    __in PCDB Cdb,
+    __in ULONG CdbLength
+    )
+{
+    ULONG64 lba = 0;
+
+    NT_ASSERT(Cdb != NULL);
+    NT_ASSERT(CdbLength != 0);
+
+    if (CdbLength == 0x10)
+    {
+        REVERSE_BYTES_QUAD(&lba, Cdb->CDB16.LogicalBlock);
+    }
+    else
+    {
+        lba |= Cdb->CDB10.LogicalBlockByte3 << 0;
+        lba |= Cdb->CDB10.LogicalBlockByte2 << 8;
+        lba |= Cdb->CDB10.LogicalBlockByte1 << 16;
+        lba |= Cdb->CDB10.LogicalBlockByte0 << 24;
+    }
+
+    return lba;
+}// -- AhciGetLba();
\ No newline at end of file
diff --git a/reactos/drivers/storage/storahci/storahci.h b/reactos/drivers/storage/storahci/storahci.h
new file mode 100644 (file)
index 0000000..6adcc50
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * PROJECT:        ReactOS Kernel
+ * LICENSE:        GNU GPLv2 only as published by the Free Software Foundation
+ * PURPOSE:        To Implement AHCI Miniport driver targeting storport NT 5.2
+ * PROGRAMMERS:    Aman Priyadarshi (aman.eureka@gmail.com)
+ */
+
+#include <ntddk.h>
+#include <ata.h>
+#include <storport.h>
+
+#define DEBUG 1
+#pragma warning(disable:4214) // bit field types other than int
+#pragma warning(disable:4201) // nameless struct/union
+
+#define MAXIMUM_AHCI_PORT_COUNT             32
+#define MAXIMUM_AHCI_PRDT_ENTRIES           32
+#define MAXIMUM_AHCI_PORT_NCS               30
+#define MAXIMUM_QUEUE_BUFFER_SIZE           255
+#define MAXIMUM_TRANSFER_LENGTH             (128*1024) // 128 KB
+
+#define DEVICE_ATA_BLOCK_SIZE               512
+
+// device type (DeviceParams)
+#define AHCI_DEVICE_TYPE_ATA                1
+#define AHCI_DEVICE_TYPE_ATAPI              2
+#define AHCI_DEVICE_TYPE_NODEVICE           3
+
+// section 3.1.2
+#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
+#define AHCI_ATA_CFIS_FeaturesLow           3
+#define AHCI_ATA_CFIS_LBA0                  4
+#define AHCI_ATA_CFIS_LBA1                  5
+#define AHCI_ATA_CFIS_LBA2                  6
+#define AHCI_ATA_CFIS_Device                7
+#define AHCI_ATA_CFIS_LBA3                  8
+#define AHCI_ATA_CFIS_LBA4                  9
+#define AHCI_ATA_CFIS_LBA5                  10
+#define AHCI_ATA_CFIS_FeaturesHigh          11
+#define AHCI_ATA_CFIS_SectorCountLow        12
+#define AHCI_ATA_CFIS_SectorCountHigh       13
+
+// ATA Functions
+#define ATA_FUNCTION_ATA_COMMAND            0x100
+#define ATA_FUNCTION_ATA_IDENTIFY           0x101
+#define ATA_FUNCTION_ATA_READ               0x102
+
+// ATAPI Functions
+#define ATA_FUNCTION_ATAPI_COMMAND          0x200
+
+// ATA Flags
+#define ATA_FLAGS_DATA_IN                   (1 << 1)
+#define ATA_FLAGS_DATA_OUT                  (1 << 2)
+#define ATA_FLAGS_48BIT_COMMAND             (1 << 3)
+#define ATA_FLAGS_USE_DMA                   (1 << 4)
+
+#define IsAtaCommand(AtaFunction)           (AtaFunction & ATA_FUNCTION_ATA_COMMAND)
+#define IsAtapiCommand(AtaFunction)         (AtaFunction & ATA_FUNCTION_ATAPI_COMMAND)
+#define IsDataTransferNeeded(SrbExtension)  (SrbExtension->Flags & (ATA_FLAGS_DATA_IN | ATA_FLAGS_DATA_OUT))
+#define IsAdapterCAPS64(CAP)                (CAP & AHCI_Global_HBA_CAP_S64A)
+
+// 3.1.1 NCS = CAP[12:08] -> Align
+#define AHCI_Global_Port_CAP_NCS(x)         (((x) & 0xF00) >> 8)
+
+#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
+#define AhciDebugPrint(format, ...) StorPortDebugPrint(0, format, __VA_ARGS__)
+
+typedef
+VOID
+(*PAHCI_COMPLETION_ROUTINE) (
+    __in PVOID PortExtension,
+    __in PVOID Srb
+    );
+
+//////////////////////////////////////////////////////////////
+//              ---- 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
+                            // Port multiplier
+                            // Reserved
+                            // Data transfer direction, 1 - device to host
+                            // Interrupt bit
+                            // Auto-activate. Specifies if DMA Activate FIS is needed
+    UCHAR Reserved[2];      // Reserved
+    ULONG DmaBufferLow;     // DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
+    ULONG DmaBufferHigh;
+    ULONG Reserved2;        // More reserved
+    ULONG DmaBufferOffset;  // Byte offset into buffer. First 2 bits must be 0
+    ULONG TranferCount;     // Number of bytes to transfer. Bit 0 must be 0
+    ULONG Reserved3;        // Reserved
+} AHCI_FIS_DMA_SETUP;
+
+typedef struct _AHCI_PIO_SETUP_FIS
+{
+    UCHAR FisType;
+    UCHAR Reserved1 :5;
+    UCHAR D :1;
+    UCHAR I :1;
+    UCHAR Reserved2 :1;
+    UCHAR Status;
+    UCHAR Error;
+
+    UCHAR SectorNumber;
+    UCHAR CylLow;
+    UCHAR CylHigh;
+    UCHAR Dev_Head;
+
+    UCHAR SectorNumb_Exp;
+    UCHAR CylLow_Exp;
+    UCHAR CylHigh_Exp;
+    UCHAR Reserved3;
+
+    UCHAR SectorCount;
+    UCHAR SectorCount_Exp;
+    UCHAR Reserved4;
+    UCHAR E_Status;
+
+    USHORT TransferCount;
+    UCHAR Reserved5[2];
+} AHCI_PIO_SETUP_FIS;
+
+typedef struct _AHCI_D2H_REGISTER_FIS
+{
+    UCHAR FisType;
+    UCHAR Reserved1 :6;
+    UCHAR I:1;
+    UCHAR Reserved2 :1;
+    UCHAR Status;
+    UCHAR Error;
+
+    UCHAR SectorNumber;
+    UCHAR CylLow;
+    UCHAR CylHigh;
+    UCHAR Dev_Head;
+
+    UCHAR SectorNum_Exp;
+    UCHAR CylLow_Exp;
+    UCHAR CylHigh_Exp;
+    UCHAR Reserved;
+
+    UCHAR SectorCount;
+    UCHAR SectorCount_Exp;
+    UCHAR Reserved3[2];
+
+    UCHAR Reserved4[4];
+} AHCI_D2H_REGISTER_FIS;
+
+typedef struct _AHCI_SET_DEVICE_BITS_FIS
+{
+    UCHAR FisType;
+
+    UCHAR PMPort: 4;
+    UCHAR Reserved1 :2;
+    UCHAR I :1;
+    UCHAR N :1;
+
+    UCHAR Status_Lo :3;
+    UCHAR Reserved2 :1;
+    UCHAR Status_Hi :3;
+    UCHAR Reserved3 :1;
+
+    UCHAR Error;
+
+    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;
+
+//////////////////////////////////////////////////////////////
+//              ---------------------------                 //
+//////////////////////////////////////////////////////////////
+
+typedef union _AHCI_COMMAND_HEADER_DESCRIPTION
+{
+    struct
+    {
+        ULONG CFL : 5;       // Command FIS Length
+        ULONG A : 1;         // IsATAPI
+        ULONG W : 1;         // Write
+        ULONG P : 1;         // Prefetchable
+
+        ULONG R : 1;         // Reset
+        ULONG B : 1;         // BIST
+        ULONG C : 1;         //Clear Busy upon R_OK
+        ULONG RSV : 1;
+        ULONG PMP : 4;       //Port Multiplier Port
+
+        ULONG PRDTL : 16;    //Physical Region Descriptor Table Length
+    };
+
+    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
+{
+    struct
+    {
+        ULONG ST : 1;
+        ULONG SUD : 1;
+        ULONG POD : 1;
+        ULONG CLO : 1;
+        ULONG FRE : 1;
+        ULONG RSV0 : 3;
+        ULONG CCS : 5;
+        ULONG MPSS : 1;
+        ULONG FR : 1;
+        ULONG CR : 1;
+        ULONG CPS : 1;
+        ULONG PMA : 1;
+        ULONG HPCP : 1;
+        ULONG MPSP : 1;
+        ULONG CPD : 1;
+        ULONG ESP : 1;
+        ULONG FBSCP : 1;
+        ULONG APSTE : 1;
+        ULONG ATAPI : 1;
+        ULONG DLAE : 1;
+        ULONG ALPE : 1;
+        ULONG ASP : 1;
+        ULONG ICC : 4;
+    };
+
+    ULONG Status;
+} AHCI_PORT_CMD;
+
+typedef union _AHCI_SERIAL_ATA_CONTROL
+{
+    struct
+    {
+        ULONG DET :4;
+        ULONG SPD :4;
+        ULONG IPM :4;
+        ULONG SPM :4;
+        ULONG PMP :4;
+        ULONG DW11_Reserved :12;
+    };
+
+    ULONG Status;
+}  AHCI_SERIAL_ATA_CONTROL;
+
+typedef union _AHCI_SERIAL_ATA_STATUS
+{
+    struct
+    {
+        ULONG DET :4;
+        ULONG SPD :4;
+        ULONG IPM :4;
+        ULONG RSV0 :20;
+    };
+
+    ULONG Status;
+}  AHCI_SERIAL_ATA_STATUS;
+
+typedef union _AHCI_TASK_FILE_DATA
+{
+    struct
+    {
+        struct _STS
+        {
+            UCHAR ERR : 1;
+            UCHAR CS1 : 2;
+            UCHAR DRQ : 1;
+            UCHAR CS2 : 3;
+            UCHAR BSY : 1;
+        } STS;
+        UCHAR ERR;
+        USHORT RSV;
+    };
+
+    ULONG Status;
+} AHCI_TASK_FILE_DATA;
+
+typedef struct _AHCI_PRDT
+{
+    ULONG DBA;
+    ULONG DBAU;
+    ULONG RSV0;
+
+    ULONG DBC : 22;
+    ULONG RSV1 : 9;
+    ULONG I : 1;
+} AHCI_PRDT, *PAHCI_PRDT;
+
+// 4.2.3 Command Table
+typedef struct _AHCI_COMMAND_TABLE
+{
+    // (16 * 32) + 64 + 16 + 48 = 648
+    // 128 byte aligned :D
+    UCHAR CFIS[64];
+    UCHAR ACMD[16];
+    UCHAR RSV0[48];
+    AHCI_PRDT PRDT[MAXIMUM_AHCI_PRDT_ENTRIES];
+} AHCI_COMMAND_TABLE, *PAHCI_COMMAND_TABLE;
+
+// 4.2.2 Command Header
+typedef struct _AHCI_COMMAND_HEADER
+{
+    AHCI_COMMAND_HEADER_DESCRIPTION DI;   // DW 0
+    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
+typedef struct _AHCI_RECEIVED_FIS
+{
+    struct _AHCI_FIS_DMA_SETUP          DmaSetupFIS;      // 0x00 -- DMA Setup FIS
+    ULONG                               pad0;             // 4 BYTE padding
+    struct _AHCI_PIO_SETUP_FIS          PioSetupFIS;      // 0x20 -- PIO Setup FIS
+    ULONG                               pad1[3];          // 12 BYTE padding
+    struct _AHCI_D2H_REGISTER_FIS       RegisterFIS;      // 0x40 -- Register – Device to Host FIS
+    ULONG                               pad2;             // 4 BYTE padding
+    struct _AHCI_SET_DEVICE_BITS_FIS    SetDeviceFIS;     // 0x58 -- Set Device Bit FIS
+    ULONG                               UnknowFIS[16];    // 0x60 -- Unknown FIS
+    ULONG                               Reserved[24];     // 0xA0 -- Reserved
+} AHCI_RECEIVED_FIS, *PAHCI_RECEIVED_FIS;
+
+// Holds Port Information
+typedef struct _AHCI_PORT
+{
+    ULONG   CLB;                                // 0x00, command list base address, 1K-byte aligned
+    ULONG   CLBU;                               // 0x04, command list base address upper 32 bits
+    ULONG   FB;                                 // 0x08, FIS base address, 256-byte aligned
+    ULONG   FBU;                                // 0x0C, FIS base address upper 32 bits
+    ULONG   IS;                                 // 0x10, interrupt status
+    ULONG   IE;                                 // 0x14, interrupt enable
+    ULONG   CMD;                                // 0x18, command and status
+    ULONG   RSV0;                               // 0x1C, Reserved
+    ULONG   TFD;                                // 0x20, task file data
+    ULONG   SIG;                                // 0x24, signature
+    ULONG   SSTS;                               // 0x28, SATA status (SCR0:SStatus)
+    ULONG   SCTL;                               // 0x2C, SATA control (SCR2:SControl)
+    ULONG   SERR;                               // 0x30, SATA error (SCR1:SError)
+    ULONG   SACT;                               // 0x34, SATA active (SCR3:SActive)
+    ULONG   CI;                                 // 0x38, command issue
+    ULONG   SNTF;                               // 0x3C, SATA notification (SCR4:SNotification)
+    ULONG   FBS;                                // 0x40, FIS-based switch control
+    ULONG   RSV1[11];                           // 0x44 ~ 0x6F, Reserved
+    ULONG   Vendor[4];                          // 0x70 ~ 0x7F, vendor specific
+} AHCI_PORT, *PAHCI_PORT;
+
+typedef union _AHCI_INTERRUPT_ENABLE
+{
+    struct
+    {
+        ULONG DHRE :1;
+        ULONG PSE :1;
+        ULONG DSE :1;
+        ULONG SDBE :1;
+        ULONG UFE :1;
+        ULONG DPE :1;
+        ULONG PCE :1;
+        ULONG DMPE :1;
+        ULONG DW5_Reserved :14;
+        ULONG PRCE :1;
+        ULONG IPME :1;
+        ULONG OFE :1;
+        ULONG DW5_Reserved2 :1;
+        ULONG INFE :1;
+        ULONG IFE :1;
+        ULONG HBDE :1;
+        ULONG HBFE :1;
+        ULONG TFEE :1;
+        ULONG CPDE :1;
+    };
+
+    ULONG Status;
+} AHCI_INTERRUPT_ENABLE;
+
+typedef struct _AHCI_MEMORY_REGISTERS
+{
+    // 0x00 - 0x2B, Generic Host Control
+    ULONG CAP;                                  // 0x00, Host capability
+    ULONG GHC;                                  // 0x04, Global host control
+    ULONG IS;                                   // 0x08, Interrupt status
+    ULONG PI;                                   // 0x0C, Port implemented
+    ULONG VS;                                   // 0x10, Version
+    ULONG CCC_CTL;                              // 0x14, Command completion coalescing control
+    ULONG CCC_PTS;                              // 0x18, Command completion coalescing ports
+    ULONG EM_LOC;                               // 0x1C, Enclosure management location
+    ULONG EM_CTL;                               // 0x20, Enclosure management control
+    ULONG CAP2;                                 // 0x24, Host capabilities extended
+    ULONG BOHC;                                 // 0x28, BIOS/OS handoff control and status
+    ULONG Reserved[0x1d];                       // 0x2C - 0x9F, Reserved
+    ULONG VendorSpecific[0x18];                 // 0xA0 - 0xFF, Vendor specific registers
+    AHCI_PORT PortList[MAXIMUM_AHCI_PORT_COUNT];
+} AHCI_MEMORY_REGISTERS, *PAHCI_MEMORY_REGISTERS;
+
+// Holds information for each attached attached port to a given adapter.
+typedef struct _AHCI_PORT_EXTENSION
+{
+    ULONG PortNumber;
+    ULONG QueueSlots;                                   // slots which we have already assigned task (Slot)
+    ULONG CommandIssuedSlots;                           // slots which has been programmed
+    ULONG MaxPortQueueDepth;
+
+    struct
+    {
+        UCHAR RemovableDevice;
+        UCHAR Lba48BitMode;
+        UCHAR AccessType;
+        UCHAR DeviceType;
+        UCHAR IsActive;
+        LARGE_INTEGER MaxLba;
+        ULONG BytesPerLogicalSector;
+        ULONG BytesPerPhysicalSector;
+        UCHAR VendorId[41];
+        UCHAR RevisionID[9];
+        UCHAR SerialNumber[21];
+    } 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;
+    STOR_DEVICE_POWER_STATE DevicePowerState;           // Device Power State
+    PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
+    STOR_PHYSICAL_ADDRESS IdentifyDeviceDataPhysicalAddress;
+    struct _AHCI_ADAPTER_EXTENSION* AdapterExtension;   // Port's Adapter Information
+} AHCI_PORT_EXTENSION, *PAHCI_PORT_EXTENSION;
+
+// Holds Adapter Information
+typedef struct _AHCI_ADAPTER_EXTENSION
+{
+    ULONG   SystemIoBusNumber;
+    ULONG   SlotNumber;
+    ULONG   AhciBaseAddress;
+    PULONG  IS;// Interrupt Status, In case of MSIM == `1`
+    ULONG   PortImplemented;// bit-mapping of ports which are implemented
+    ULONG   PortCount;
+
+    USHORT  VendorID;
+    USHORT  DeviceID;
+    USHORT  RevisionID;
+
+    ULONG   Version;
+    ULONG   CAP;
+    ULONG   CAP2;
+    ULONG   LastInterruptPort;
+    ULONG   CurrentCommandSlot;
+
+    PVOID NonCachedExtension; // holds virtual address to noncached buffer allocated for Port Extension
+
+    struct
+    {
+        // Message per port or shared port?
+        ULONG MessagePerPort : 1;
+        ULONG Removed : 1;
+        ULONG Reserved : 30; // not in use -- maintain 4 byte alignment
+    } StateFlags;
+
+    PAHCI_MEMORY_REGISTERS ABAR_Address;
+    AHCI_PORT_EXTENSION PortExtension[MAXIMUM_AHCI_PORT_COUNT];
+} AHCI_ADAPTER_EXTENSION, *PAHCI_ADAPTER_EXTENSION;
+
+typedef struct _LOCAL_SCATTER_GATHER_LIST
+{
+    ULONG                       NumberOfElements;
+    ULONG_PTR                   Reserved;
+    STOR_SCATTER_GATHER_ELEMENT List[MAXIMUM_AHCI_PRDT_ENTRIES];
+} LOCAL_SCATTER_GATHER_LIST, *PLOCAL_SCATTER_GATHER_LIST;
+
+typedef struct _AHCI_SRB_EXTENSION
+{
+    AHCI_COMMAND_TABLE CommandTable;
+    ULONG AtaFunction;
+    ULONG Flags;
+
+    UCHAR CommandReg;
+    UCHAR FeaturesLow;
+    UCHAR LBA0;
+    UCHAR LBA1;
+    UCHAR LBA2;
+    UCHAR Device;
+    UCHAR LBA3;
+    UCHAR LBA4;
+    UCHAR LBA5;
+    UCHAR FeaturesHigh;
+
+    UCHAR SectorCountLow;
+    UCHAR SectorCountHigh;
+
+    ULONG SlotIndex;
+    LOCAL_SCATTER_GATHER_LIST Sgl;
+    PLOCAL_SCATTER_GATHER_LIST pSgl;
+    PAHCI_COMPLETION_ROUTINE CompletionRoutine;
+
+    // for alignment purpose -- 128 byte alignment
+    // do not try to access (R/W) this field
+    UCHAR Reserved[128];
+} AHCI_SRB_EXTENSION, *PAHCI_SRB_EXTENSION;
+
+//////////////////////////////////////////////////////////////
+//                       Declarations                       //
+//////////////////////////////////////////////////////////////
+
+VOID
+AhciProcessIO (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in UCHAR PathId,
+    __in PSCSI_REQUEST_BLOCK Srb
+    );
+
+BOOLEAN
+AhciAdapterReset (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+    );
+
+__inline
+VOID
+AhciZeroMemory (
+    __out PCHAR Buffer,
+    __in ULONG BufferSize
+    );
+
+__inline
+BOOLEAN
+IsPortValid (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in ULONG pathId
+    );
+
+UCHAR DeviceRequestSense (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    );
+
+UCHAR DeviceRequestReadWrite (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    );
+
+UCHAR DeviceRequestCapacity (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    );
+
+UCHAR
+DeviceInquiryRequest (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    );
+
+UCHAR DeviceRequestComplete (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __in PSCSI_REQUEST_BLOCK Srb,
+    __in PCDB Cdb
+    );
+
+UCHAR DeviceReportLuns (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
+    __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
+    );
+
+__inline
+PAHCI_SRB_EXTENSION
+GetSrbExtension(
+    __in PSCSI_REQUEST_BLOCK Srb
+    );
+
+__inline
+ULONG64
+AhciGetLba (
+    __in PCDB Cdb,
+    __in ULONG CdbLength
+    );
+
+//////////////////////////////////////////////////////////////
+//                       Assertions                         //
+//////////////////////////////////////////////////////////////
+
+// 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);
+
+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);
diff --git a/reactos/drivers/storage/storahci/storahci.inf b/reactos/drivers/storage/storahci/storahci.inf
new file mode 100644 (file)
index 0000000..f291c2b
--- /dev/null
@@ -0,0 +1,77 @@
+;\r
+; PROJECT:        ROS Kernel\r
+; LICENSE:        GNU GPLv2 only as published by the Free Software Foundation\r
+; PURPOSE:        Storahci Driver INF\r
+; PROGRAMMERS:    Aman Priyadarshi (aman.eureka@gmail.com)\r
+;\r
+\r
+[version]\r
+signature="$Windows NT$"\r
+Class=hdc\r
+ClassGuid={4D36E96A-E325-11CE-BFC1-08002BE10318}\r
+Provider=%ROS%\r
+\r
+[SourceDisksNames]\r
+1 = %DeviceDesc%,,,\r
+\r
+[SourceDisksFiles]\r
+storahci.sys = 1\r
+\r
+[DestinationDirs]\r
+DefaultDestDir = 12 ; DIRID_DRIVERS\r
+\r
+[Manufacturer]\r
+%ROS%=STORAHCI,NTx86\r
+\r
+[STORAHCI]\r
+\r
+[STORAHCI.NTx86]\r
+%SATA_AHCI.DeviceDesc%=storahci_Inst, PCI\CC_010601; Standard SATA AHCI Controller\r
+\r
+[ControlFlags]\r
+ExcludeFromSelect = *\r
+\r
+[storahci_Inst]\r
+CopyFiles = storahci_CopyFiles\r
+\r
+[storahci_Inst.HW]\r
+; Enables Storport IPM for this adapter\r
+HKR, "StorPort", "EnableIdlePowerManagement", %REG_DWORD%, 0x01\r
+\r
+[storahci_Inst.Services]\r
+AddService = storahci, %SPSVCINST_ASSOCSERVICE%, storahci_Service_Inst, Miniport_EventLog_Inst\r
+\r
+[storahci_Service_Inst]\r
+DisplayName    = %DeviceDesc%\r
+ServiceType    = %SERVICE_KERNEL_DRIVER%\r
+StartType      = %SERVICE_BOOT_START%\r
+ErrorControl   = %SERVICE_ERROR_CRITICAL%\r
+ServiceBinary  = %12%\storahci.sys\r
+LoadOrderGroup = SCSI Miniport\r
+AddReg         = ahci_addreg\r
+\r
+[storahci_CopyFiles]\r
+storahci.sys,,,1\r
+\r
+[ahci_addreg]\r
+HKR, "Parameters\PnpInterface", "5", %REG_DWORD%, 0x00000001\r
+HKR, "Parameters", "BusType", %REG_DWORD%, 0x0000000B\r
+\r
+[Miniport_EventLog_Inst]\r
+AddReg = Miniport_EventLog_AddReg\r
+\r
+[Miniport_EventLog_AddReg]\r
+HKR,,EventMessageFile,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\IoLogMsg.dll"\r
+HKR,,TypesSupported,%REG_DWORD%,7\r
+\r
+[Strings]\r
+ROS                     = "ReactOS"\r
+DeviceDesc              = "AHCI SATA Driver"\r
+SATA_AHCI.DeviceDesc    = "Standard SATA AHCI Controller"\r
+\r
+SPSVCINST_ASSOCSERVICE = 0x00000002\r
+SERVICE_KERNEL_DRIVER  = 1\r
+SERVICE_BOOT_START     = 0\r
+SERVICE_ERROR_CRITICAL = 3\r
+REG_EXPAND_SZ          = 0x00020000\r
+REG_DWORD              = 0x00010001\r
diff --git a/reactos/drivers/storage/storahci/storahci.rc b/reactos/drivers/storage/storahci/storahci.rc
new file mode 100644 (file)
index 0000000..5950ce2
--- /dev/null
@@ -0,0 +1,22 @@
+//
+// PROJECT:        ReactOS Kernel
+// LICENSE:        GNU GPLv2 only as published by the Free Software Foundation
+// PURPOSE:        To Implement AHCI Miniport driver targeting storport NT 5.2
+// PROGRAMMERS:    Aman Priyadarshi (aman.eureka@gmail.com)
+//
+
+#define VERSION        1
+#define VERSION_STR "1.0"
+
+#define REACTOS_FILETYPE              VFT_DRV
+#define REACTOS_FILESUBTYPE           VFT2_DRV_SYSTEM
+#define REACTOS_FILEVERSION           VERSION
+#define REACTOS_PRODUCTVERSION        VERSION
+#define REACTOS_STR_COMPANY_NAME      "ReactOS Development Team"
+#define REACTOS_STR_FILE_DESCRIPTION  "AHCI Storport Miniport Driver"
+#define REACTOS_STR_FILE_VERSION      VERSION_STR
+#define REACTOS_STR_INTERNAL_NAME     "storahci.sys"
+#define REACTOS_STR_ORIGINAL_FILENAME "storahci.sys"
+#define REACTOS_STR_LEGAL_COPYRIGHT   "Copyright 2016 ReactOS Team"
+#define REACTOS_STR_PRODUCT_NAME      "AHCI Driver for ReactOS"
+#define REACTOS_STR_PRODUCT_VERSION   VERSION_STR