Implemented Dpc Routine, managed Srb functions and some code fixes!
[reactos.git] / drivers / storage / storahci / storahci.c
index 473e88c..5cfd7e0 100644 (file)
@@ -23,6 +23,7 @@ AhciPortInitialize (
     __in PAHCI_PORT_EXTENSION PortExtension
     )
 {
+    AHCI_PORT_CMD cmd;
     ULONG mappedLength, portNumber;
     PAHCI_MEMORY_REGISTERS abar;
     PAHCI_ADAPTER_EXTENSION adapterExtension;
@@ -35,7 +36,7 @@ AhciPortInitialize (
     portNumber = PortExtension->PortNumber;
 
     NT_ASSERT(abar != NULL);
-    NT_ASSERT(portNumber < MAXIMUM_AHCI_PORT_COUNT);
+    NT_ASSERT(portNumber < adapterExtension->PortCount);
 
     PortExtension->Port = &abar->PortList[portNumber];
 
@@ -61,29 +62,51 @@ AhciPortInitialize (
         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))
+    {
+        DebugPrint("\tPort is not idle: %x\n", cmd);
+    }
+
     // 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 ((adapterExtension->CAP & AHCI_Global_HBA_CAP_S64A) != 0)
+    if (IsAdapterCAPS64(adapterExtension->CAP))
     {
         StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLBU, commandListPhysical.HighPart);
     }
 
     StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FB, receivedFISPhysical.LowPart);
-    if ((adapterExtension->CAP & AHCI_Global_HBA_CAP_S64A) != 0)
+    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)-1);
-    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->IS, (ULONG)-1);
-    StorPortWriteRegisterUlong(adapterExtension, PortExtension->AdapterExtension->IS, (1 << PortExtension->PortNumber));
+    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->SERR, (ULONG)~0);
+    StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->IS, (ULONG)~0);
+    StorPortWriteRegisterUlong(adapterExtension, adapterExtension->IS, (1 << PortExtension->PortNumber));
 
     return TRUE;
 }// -- AhciPortInitialize();
@@ -106,10 +129,10 @@ AhciAllocateResourceForAdapter (
     __in PPORT_CONFIGURATION_INFORMATION ConfigInfo
     )
 {
-    PVOID portsExtension = NULL;
-    PCHAR nonCachedExtension;
-    ULONG status, index, NCS, AlignedNCS;
+    PCHAR nonCachedExtension, tmp;
+    ULONG index, NCS, AlignedNCS;
     ULONG portCount, portImplemented, nonCachedExtensionSize;
+    PAHCI_PORT_EXTENSION PortExtension;
 
     DebugPrint("AhciAllocateResourceForAdapter()\n");
 
@@ -120,20 +143,18 @@ AhciAllocateResourceForAdapter (
     portCount = 0;
     portImplemented = AdapterExtension->PortImplemented;
 
-    // make sure we don't allocate too much memory for the ports we have not implemented
-    // LOGIC: AND with all MAXIMUM_AHCI_PORT_COUNT (low significant) bits set
-    portImplemented = portImplemented & ((1 << MAXIMUM_AHCI_PORT_COUNT) - 1);
-    while (portImplemented > 0)
-    {
-        portCount++;
-        portImplemented &= (portImplemented - 1);
-    }
+    NT_ASSERT(portImplemented != 0);
+    for (index = MAXIMUM_AHCI_PORT_COUNT - 1; index > 0; index--)
+        if ((portImplemented & (1 << index)) != 0)
+            break;
 
-    NT_ASSERT(portCount <= MAXIMUM_AHCI_PORT_COUNT);
+    portCount = index + 1;
     DebugPrint("\tPort Count: %d\n", portCount);
 
+    AdapterExtension->PortCount = portCount;
     nonCachedExtensionSize =    sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
-                                sizeof(AHCI_RECEIVED_FIS);
+                                sizeof(AHCI_RECEIVED_FIS) +
+                                sizeof(IDENTIFY_DEVICE_DATA);
 
     // align nonCachedExtensionSize to 1024
     nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024);
@@ -151,16 +172,23 @@ AhciAllocateResourceForAdapter (
     nonCachedExtension = AdapterExtension->NonCachedExtension;
     AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount);
 
-    for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
+    for (index = 0; index < portCount; index++)
     {
-        AdapterExtension->PortExtension[index].IsActive = FALSE;
+        PortExtension = &AdapterExtension->PortExtension[index];
+
+        PortExtension->DeviceParams.IsActive = FALSE;
         if ((AdapterExtension->PortImplemented & (1 << index)) != 0)
         {
-            AdapterExtension->PortExtension[index].PortNumber = index;
-            AdapterExtension->PortExtension[index].IsActive = TRUE;
-            AdapterExtension->PortExtension[index].AdapterExtension = AdapterExtension;
-            AdapterExtension->PortExtension[index].CommandList = nonCachedExtension;
-            AdapterExtension->PortExtension[index].ReceivedFIS = (PAHCI_RECEIVED_FIS)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
+            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;
         }
     }
@@ -168,6 +196,292 @@ AhciAllocateResourceForAdapter (
     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;
+
+    DebugPrint("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)))
+    {
+        DebugPrint("\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))
+                {
+                    DebugPrint("\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)
+                {
+                    DebugPrint("\tFailed to start Port\n");
+                    return FALSE;
+                }
+
+                return TRUE;
+            }
+        default:
+            // unhandled case
+            DebugPrint("\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;
+    STOR_LOCK_HANDLE lockhandle;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PAHCI_COMPLETION_ROUTINE CompletionRoutine;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(SystemArgument2);
+
+    DebugPrint("AhciCommandCompletionDpcRoutine()\n");
+
+    AhciZeroMemory(&lockhandle, sizeof(lockhandle));
+
+    StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
+    Srb = RemoveQueue(&PortExtension->CompletionQueue);
+
+    NT_ASSERT(Srb != NULL);
+
+    if (Srb->SrbStatus == SRB_STATUS_PENDING)
+    {
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;
+    }
+
+    SrbExtension = GetSrbExtension(Srb);
+    CompletionRoutine = SrbExtension->CompletionRoutine;
+
+    if (CompletionRoutine != NULL)
+    {
+        // now it's completion routine responsibility to set SrbStatus
+        CompletionRoutine(PortExtension, Srb);
+    }
+    else
+    {
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;
+        StorPortNotification(RequestComplete, AdapterExtension, Srb);
+    }
+
+    StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
+    return;
+}// -- AhciCommandCompletionDpcRoutine();
+
+/**
+ * @name AhciHwPassiveInitialize
+ * @implemented
+ *
+ * initializes the HBA and finds all devices that are of interest to the miniport driver. (at PASSIVE LEVEL)
+ *
+ * @param adapterExtension
+ *
+ * @return
+ * return TRUE if intialization was successful
+ */
+BOOLEAN
+AhciHwPassiveInitialize (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+    )
+{
+    ULONG index;
+    PAHCI_PORT_EXTENSION PortExtension;
+
+    DebugPrint("AhciHwPassiveInitialize()\n");
+
+    for (index = 0; index < AdapterExtension->PortCount; index++)
+    {
+        if ((AdapterExtension->PortImplemented & (0x1 << index)) != 0)
+        {
+            PortExtension = &AdapterExtension->PortExtension[index];
+            PortExtension->DeviceParams.IsActive = AhciStartPort(PortExtension);
+            StorPortInitializeDpc(AdapterExtension, &PortExtension->CommandCompletion, AhciCommandCompletionDpcRoutine);
+        }
+    }
+
+    return TRUE;
+}// -- AhciHwPassiveInitialize();
+
 /**
  * @name AhciHwInitialize
  * @implemented
@@ -181,33 +495,77 @@ AhciAllocateResourceForAdapter (
  */
 BOOLEAN
 AhciHwInitialize (
-    __in PVOID AdapterExtension
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
     )
 {
-    ULONG ghc, messageCount, status;
-    PAHCI_ADAPTER_EXTENSION adapterExtension;
+    AHCI_GHC ghc;
+    MESSAGE_INTERRUPT_INFORMATION messageInfo;
 
     DebugPrint("AhciHwInitialize()\n");
 
-    adapterExtension = AdapterExtension;
-    adapterExtension->StateFlags.MessagePerPort = FALSE;
+    AdapterExtension->StateFlags.MessagePerPort = FALSE;
 
     // First check what type of interrupt/synchronization device is using
-    ghc = StorPortReadRegisterUlong(adapterExtension, &adapterExtension->ABAR_Address->GHC);
+    ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &AdapterExtension->ABAR_Address->GHC);
 
     // When set to ‘1’ by hardware, indicates that the HBA requested more than one MSI vector
     // but has reverted to using the first vector only.  When this bit is cleared to ‘0’,
     // the HBA has not reverted to single MSI mode (i.e. hardware is already in single MSI mode,
     // software has allocated the number of messages requested
-    if ((ghc & AHCI_Global_HBA_CONTROL_MRSM) == 0)
+    if (ghc.MRSM == 0)
     {
-        adapterExtension->StateFlags.MessagePerPort = TRUE;
+        AdapterExtension->StateFlags.MessagePerPort = TRUE;
         DebugPrint("\tMultiple MSI based message not supported\n");
     }
 
+    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_ADAPTER_EXTENSION AdapterExtension;
+
+    DebugPrint("AhciCompleteIssuedSrb()\n");
+
+    NT_ASSERT(CommandsToComplete != 0);
+
+    DebugPrint("\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];
+            NT_ASSERT(Srb != NULL);
+
+            AddQueue(&PortExtension->CompletionQueue, Srb);
+            StorPortIssueDpc(AdapterExtension, &PortExtension->CommandCompletion, PortExtension, Srb);
+        }
+    }
+
+    return;
+}// -- AhciCompleteIssuedSrb();
+
 /**
  * @name AhciInterruptHandler
  * @not_implemented
@@ -216,19 +574,90 @@ AhciHwInitialize (
  *
  * @param PortExtension
  *
- * @return
- * return TRUE Indicates the interrupt was handled correctly
- * return FALSE Indicates something went wrong
  */
-BOOLEAN
+VOID
 AhciInterruptHandler (
     __in PAHCI_PORT_EXTENSION PortExtension
     )
 {
+    ULONG is, ci, sact, outstanding;
+    AHCI_INTERRUPT_STATUS PxIS;
+    AHCI_INTERRUPT_STATUS PxISMasked;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
     DebugPrint("AhciInterruptHandler()\n");
     DebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
 
-    return FALSE;
+    AdapterExtension = PortExtension->AdapterExtension;
+    NT_ASSERT(IsPortValid(AdapterExtension, PortExtension->PortNumber));
+
+    // 5.5.3
+    // 1. Software determines the cause of the interrupt by reading the PxIS register.
+    //    It is possible for multiple bits to be set
+    // 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
+    // 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
+    // 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
+    //    the list of commands previously issued by software that are still outstanding.
+    //    If executing native queued commands, software reads the PxSACT register and compares the current
+    //    value to the list of commands previously issued by software.
+    //    Software completes with success any outstanding command whose corresponding bit has been cleared in
+    //    the respective register. PxCI and PxSACT are volatile registers; software should only use their values
+    //    to determine commands that have completed, not to determine which commands have previously been issued.
+    // 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
+    PxISMasked.Status = 0;
+    PxIS.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IS);
+
+    // 6.2.2
+    // Fatal Error
+    // signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
+    if (PxIS.HBFS || PxIS.HBDS || PxIS.IFS || PxIS.TFES)
+    {
+        // In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
+        // any native command queuing commands. To recover, the port must be restarted
+        // To detect an error that requires software recovery actions to be performed,
+        // software should check whether any of the following status bits are set on an interrupt:
+        // PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES.  If any of these bits are set,
+        // software should perform the appropriate error recovery actions based on whether
+        // non-queued commands were being issued or native command queuing commands were being issued.
+
+        DebugPrint("\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();
 
 /**
@@ -237,54 +666,57 @@ AhciInterruptHandler (
  *
  * The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
  *
- * @param adapterExtension
+ * @param AdapterExtension
  *
  * @return
  * return TRUE Indicates that an interrupt was pending on adapter.
  * return FALSE Indicates the interrupt was not ours.
  */
 BOOLEAN
-AhciHwInterrupt(
-    __in PVOID AdapterExtension
+AhciHwInterrupt (
+    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
     )
 {
-    ULONG portPending, nextPort, i;
-    PAHCI_ADAPTER_EXTENSION adapterExtension;
-
-    DebugPrint("AhciHwInterrupt()\n");
+    ULONG portPending, nextPort, i, portCount;
 
-    adapterExtension = AdapterExtension;
-
-    if (adapterExtension->StateFlags.Removed)
+    if (AdapterExtension->StateFlags.Removed)
     {
         return FALSE;
     }
 
-    portPending = StorPortReadRegisterUlong(adapterExtension, adapterExtension->IS);
+    portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS);
+
     // we process interrupt for implemented ports only
-    portPending = portPending & adapterExtension->PortImplemented;
+    portCount = AdapterExtension->PortCount;
+    portPending = portPending & AdapterExtension->PortImplemented;
 
     if (portPending == 0)
     {
         return FALSE;
     }
 
-    for (i = 1; i <= MAXIMUM_AHCI_PORT_COUNT; i++)
+    for (i = 1; i <= portCount; i++)
     {
-        nextPort = (adapterExtension->LastInterruptPort + i) % MAXIMUM_AHCI_PORT_COUNT;
-
+        nextPort = (AdapterExtension->LastInterruptPort + i) % portCount;
         if ((portPending & (0x1 << nextPort)) == 0)
             continue;
 
-        if ((nextPort == adapterExtension->LastInterruptPort) ||
-            (adapterExtension->PortExtension[nextPort].IsActive == FALSE))
+        NT_ASSERT(IsPortValid(AdapterExtension, nextPort));
+
+        if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE)
         {
-            return FALSE;
+            continue;
         }
 
         // we can assign this interrupt to this port
-        adapterExtension->LastInterruptPort = nextPort;
-        return AhciInterruptHandler(&adapterExtension->PortExtension[nextPort]);
+        AdapterExtension->LastInterruptPort = nextPort;
+        AhciInterruptHandler(&AdapterExtension->PortExtension[nextPort]);
+
+        portPending &= ~(1 << nextPort);
+
+        // interrupt belongs to this device
+        // should always return TRUE
+        return TRUE;
     }
 
     DebugPrint("\tSomething went wrong");
@@ -293,7 +725,7 @@ AhciHwInterrupt(
 
 /**
  * @name AhciHwStartIo
- * @implemented
+ * @not_implemented
  *
  * The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
  *
@@ -319,6 +751,8 @@ AhciHwStartIo (
     function = Srb->Function;
     adapterExtension = AdapterExtension;
 
+    DebugPrint("\tFunction: %x\n", function);
+
     if (!IsPortValid(adapterExtension, pathId))
     {
         Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
@@ -341,7 +775,7 @@ AhciHwStartIo (
             {
                 Srb->SrbStatus = SRB_STATUS_SUCCESS;
                 adapterExtension->StateFlags.Removed = 1;
-                DebugPrint("\tadapter removed\n");
+                DebugPrint("\tAdapter removed\n");
             }
             else if (pnpRequest->PnPAction == StorStopDevice)
             {
@@ -360,6 +794,7 @@ AhciHwStartIo (
 
     if (function == SRB_FUNCTION_EXECUTE_SCSI)
     {
+        DebugPrint("\tSRB_FUNCTION_EXECUTE_SCSI\n");
         // https://msdn.microsoft.com/en-us/windows/hardware/drivers/storage/handling-srb-function-execute-scsi
         // On receipt of an SRB_FUNCTION_EXECUTE_SCSI request, a miniport driver's HwScsiStartIo
         // routine does the following:
@@ -378,23 +813,35 @@ AhciHwStartIo (
         if (Srb->CdbLength > 0)
         {
             PCDB cdb = (PCDB)&Srb->Cdb;
-            if (cdb->CDB10.OperationCode == SCSIOP_INQUIRY)
+            NT_ASSERT(cdb != NULL);
+
+            switch(cdb->CDB10.OperationCode)
             {
-                Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb);
-                StorPortNotification(RequestComplete, adapterExtension, Srb);
-                return TRUE;
+                case SCSIOP_INQUIRY:
+                    Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb, TRUE);
+                    break;
+                case SCSIOP_REPORT_LUNS:
+                    Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb, FALSE);
+                    break;
+                default:
+                {
+                    DebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
+                    Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+                }
+                break;
             }
         }
         else
         {
             Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
-            StorPortNotification(RequestComplete, adapterExtension, Srb);
-            return TRUE;
         }
+
+        StorPortNotification(RequestComplete, adapterExtension, Srb);
+        return TRUE;
     }
 
-    DebugPrint("\tUnknow function code recieved: %x\n", function);
-    Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
+    DebugPrint("\tUnknown function code recieved: %x\n", function);
+    Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
     StorPortNotification(RequestComplete, adapterExtension, Srb);
     return TRUE;
 }// -- AhciHwStartIo();
@@ -417,6 +864,7 @@ AhciHwResetBus (
     __in ULONG PathId
     )
 {
+    STOR_LOCK_HANDLE lockhandle;
     PAHCI_ADAPTER_EXTENSION adapterExtension;
 
     DebugPrint("AhciHwResetBus()\n");
@@ -425,7 +873,15 @@ AhciHwResetBus (
 
     if (IsPortValid(AdapterExtension, PathId))
     {
-        // TODO: Reset Port
+        AhciZeroMemory(&lockhandle, sizeof(lockhandle));
+
+        // Acquire Lock
+        StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
+
+        // TODO: Perform port reset
+
+        // Release lock
+        StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
     }
 
     return FALSE;
@@ -473,12 +929,10 @@ AhciHwFindAdapter (
     __in PBOOLEAN Reserved3
     )
 {
-    ULONG ghc;
-    ULONG index;
-    ULONG portCount, portImplemented;
-    ULONG pci_cfg_len;
-    UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
+    AHCI_GHC ghc;
+    ULONG index, pci_cfg_len;
     PACCESS_RANGE accessRange;
+    UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
 
     PAHCI_MEMORY_REGISTERS abar;
     PPCI_COMMON_CONFIG pciConfigData;
@@ -486,6 +940,11 @@ AhciHwFindAdapter (
 
     DebugPrint("AhciHwFindAdapter()\n");
 
+    UNREFERENCED_PARAMETER(HwContext);
+    UNREFERENCED_PARAMETER(BusInformation);
+    UNREFERENCED_PARAMETER(ArgumentString);
+    UNREFERENCED_PARAMETER(Reserved3);
+
     adapterExtension = AdapterExtension;
     adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
     adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
@@ -520,9 +979,9 @@ AhciHwFindAdapter (
     abar = NULL;
     if (ConfigInfo->NumberOfAccessRanges > 0)
     {
+        accessRange = *(ConfigInfo->AccessRanges);
         for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
         {
-            accessRange = *ConfigInfo->AccessRanges;
             if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
             {
                 abar = StorPortGetDeviceBase(adapterExtension,
@@ -551,9 +1010,9 @@ AhciHwFindAdapter (
     // 10.1.2
     // 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
     // 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
-    ghc = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
+    ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
     // AE := Highest Significant bit of GHC
-    if ((ghc & AHCI_Global_HBA_CONTROL_AE) != 0)//Hmm, controller was already in power state
+    if (ghc.AE != 0)// Hmm, controller was already in power state
     {
         // reset controller to have it in known state
         DebugPrint("\tAE Already set, Reset()\n");
@@ -564,8 +1023,10 @@ AhciHwFindAdapter (
         }
     }
 
-    ghc = AHCI_Global_HBA_CONTROL_AE;// only AE=1
-    StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
+    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);
@@ -586,8 +1047,9 @@ AhciHwFindAdapter (
     ConfigInfo->ScatterGather = TRUE;
 
     // Turn IE -- Interrupt Enabled
-    ghc |= AHCI_Global_HBA_CONTROL_IE;
-    StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
+    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))
@@ -596,9 +1058,9 @@ AhciHwFindAdapter (
         return SP_RETURN_ERROR;
     }
 
-    for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
+    for (index = 0; index < adapterExtension->PortCount; index++)
     {
-        if ((adapterExtension->PortImplemented & (0x1<<index)) != 0)
+        if ((adapterExtension->PortImplemented & (0x1 << index)) != 0)
             AhciPortInitialize(&adapterExtension->PortExtension[index]);
     }
 
@@ -623,8 +1085,8 @@ DriverEntry (
     __in PVOID RegistryPath
     )
 {
+    ULONG status;
     HW_INITIALIZATION_DATA hwInitializationData;
-    ULONG i, status;
 
     DebugPrint("Storahci Loaded\n");
 
@@ -661,177 +1123,517 @@ DriverEntry (
                                 &hwInitializationData,
                                 NULL);
 
-    DebugPrint("\tstatus:%x\n", status);
+    DebugPrint("\tstatus: %x\n", status);
     return status;
 }// -- DriverEntry();
 
 /**
- * @name AhciAdapterReset
+ * @name AhciATA_CFIS
  * @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.
+ * create ATA CFIS from Srb
  *
- * @param AdapterExtension
+ * @param PortExtension
+ * @param Srb
  *
  * @return
- * TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
+ * Number of CFIS fields used in DWORD
  */
-BOOLEAN
-AhciAdapterReset (
-    __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+ULONG
+AhciATA_CFIS (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PAHCI_SRB_EXTENSION SrbExtension
     )
 {
-    ULONG ghc, ticks, ghcStatus;
-    PAHCI_MEMORY_REGISTERS abar = NULL;
+    PAHCI_COMMAND_TABLE cmdTable;
 
-    DebugPrint("AhciAdapterReset()\n");
+    UNREFERENCED_PARAMETER(PortExtension);
 
-    abar = AdapterExtension->ABAR_Address;
-    if (abar == NULL) // basic sanity
-    {
-        return FALSE;
-    }
+    DebugPrint("AhciATA_CFIS()\n");
 
-    // HR -- Very first bit (lowest significant)
-    ghc = AHCI_Global_HBA_CONTROL_HR;
-    StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc);
+    cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
 
-    for (ticks = 0; ticks < 50; ++ticks)
-    {
-        ghcStatus = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
-        if ((ghcStatus & AHCI_Global_HBA_CONTROL_HR) == 0)
-        {
-            break;
-        }
-        StorPortStallExecution(20000);
-    }
+    AhciZeroMemory(&cmdTable->CFIS, sizeof(cmdTable->CFIS));
 
-    if (ticks == 50)// 1 second
-    {
-        DebugPrint("\tDevice Timeout\n");
-        return FALSE;
-    }
+    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;
 
-    return TRUE;
-}// -- AhciAdapterReset();
+    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 AhciZeroMemory
- * @implemented
+ * @name AhciATAPI_CFIS
+ * @not_implemented
  *
- * Clear buffer by filling zeros
+ * create ATAPI CFIS from Srb
  *
- * @param Buffer
- * @param BufferSize
+ * @param PortExtension
+ * @param Srb
+ *
+ * @return
+ * Number of CFIS fields used in DWORD
  */
-__inline
-VOID
-AhciZeroMemory (
-    __out PCHAR Buffer,
-    __in ULONG BufferSize
+ULONG
+AhciATAPI_CFIS (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PAHCI_SRB_EXTENSION SrbExtension
     )
 {
-    ULONG i;
-    for (i = 0; i < BufferSize; i++)
-    {
-        Buffer[i] = 0;
-    }
-}// -- AhciZeroMemory();
+    UNREFERENCED_PARAMETER(PortExtension);
+    UNREFERENCED_PARAMETER(SrbExtension);
+
+    DebugPrint("AhciATAPI_CFIS()\n");
+
+    return 2;
+}// -- AhciATAPI_CFIS();
 
 /**
- * @name IsPortValid
+ * @name AhciBuild_PRDT
  * @implemented
  *
- * Tells wheather given port is implemented or not
+ * Build PRDT for data transfer
  *
- * @param AdapterExtension
- * @param PathId
+ * @param PortExtension
+ * @param Srb
  *
  * @return
- * return TRUE if provided port is valid (implemented) or not
+ * Return number of entries in PRDT.
  */
-__inline
-BOOLEAN
-IsPortValid (
-    __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
-    __in UCHAR pathId
+ULONG
+AhciBuild_PRDT (
+    __in PAHCI_PORT_EXTENSION PortExtension,
+    __in PAHCI_SRB_EXTENSION SrbExtension
     )
 {
-    NT_ASSERT(pathId >= 0);
+    ULONG index;
+    PAHCI_COMMAND_TABLE cmdTable;
+    PLOCAL_SCATTER_GATHER_LIST sgl;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    DebugPrint("AhciBuild_PRDT()\n");
+
+    sgl = &SrbExtension->Sgl;
+    cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
+    AdapterExtension = PortExtension->AdapterExtension;
+
+    NT_ASSERT(sgl != NULL);
+    NT_ASSERT(sgl->NumberOfElements < MAXIMUM_AHCI_PRDT_ENTRIES);
 
-    if (pathId >= MAXIMUM_AHCI_PORT_COUNT)
+    for (index = 0; index < sgl->NumberOfElements; index++)
     {
-        return FALSE;
+        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 AdapterExtension->PortExtension[pathId].IsActive;
-}// -- IsPortValid()
+    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;
+
+    DebugPrint("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)
+        {
+            DebugPrint("\tATA Device Found!\n");
+            SrbExtension->CommandReg = IDE_COMMAND_IDENTIFY;
+        }
+        else
+        {
+            DebugPrint("\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 (IsAtaCommand(SrbExtension->AtaFunction))
+    {
+        cfl = AhciATA_CFIS(PortExtension, SrbExtension);
+    }
+    else if (IsAtapiCommand(SrbExtension->AtaFunction))
+    {
+        cfl = AhciATAPI_CFIS(PortExtension, SrbExtension);
+    }
+
+    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 sact, ci;
+    ULONG QueueSlots, slotToActivate, tmp;
+    PAHCI_ADAPTER_EXTENSION AdapterExtension;
+
+    DebugPrint("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;
+    }
+
+    sact = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SACT);
+    ci = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CI);
+
+    // 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
- * @not_implemented
+ * @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 PathId
  * @param Srb
  *
  */
 VOID
 AhciProcessIO (
     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
-    __in UCHAR pathId
+    __in UCHAR PathId,
+    __in PSCSI_REQUEST_BLOCK Srb
     )
 {
     STOR_LOCK_HANDLE lockhandle;
+    PSCSI_REQUEST_BLOCK tmpSrb;
     PAHCI_PORT_EXTENSION PortExtension;
-    ULONG commandSlotMask, occupiedSlots, slotIndex;
+    ULONG commandSlotMask, occupiedSlots, slotIndex, NCS;
 
     DebugPrint("AhciProcessIO()\n");
-    DebugPrint("\tPathId: %d\n", pathId);
+    DebugPrint("\tPathId: %d\n", PathId);
 
-    PortExtension = &AdapterExtension->PortExtension[pathId];
+    PortExtension = &AdapterExtension->PortExtension[PathId];
 
-    NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
-
-    if (PortExtension->IsActive == FALSE)
-        return; // we should wait for device to get active
+    NT_ASSERT(PathId < AdapterExtension->PortCount);
 
     AhciZeroMemory(&lockhandle, sizeof(lockhandle));
 
     // Acquire Lock
     StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
 
-    occupiedSlots = PortExtension->OccupiedSlots; // Busy command slots for given port
-    commandSlotMask = (1 << AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)) - 1; // available slots mask
+    // 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)
     {
-        for (slotIndex = 0; slotIndex <= AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); slotIndex++)
+        // iterate over HBA port slots
+        for (slotIndex = 0; slotIndex < NCS; slotIndex++)
         {
             // find first free slot
             if ((commandSlotMask & (1 << slotIndex)) != 0)
             {
-                // TODO: remove from queue and process it
+                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 InquiryCompletion
+ * @not_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;
+    PLUN_LIST LunList;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
+    ULONG SrbStatus, LunCount, DataBufferLength;
+
+    DebugPrint("InquiryCompletion()\n");
+
+    NT_ASSERT(PortExtension != NULL);
+    NT_ASSERT(Srb != NULL);
+
+    cdb = (PCDB)&Srb->Cdb;
+    SrbStatus = Srb->SrbStatus;
+    SrbExtension = GetSrbExtension(Srb);
+
+    if (SrbStatus == SRB_STATUS_SUCCESS)
+    {
+        IdentifyDeviceData = PortExtension->IdentifyDeviceData;
+
+        if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
+        {
+            DebugPrint("Device: ATA\n");
+            PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
+            if (IdentifyDeviceData->GeneralConfiguration.RemovableMedia)
+            {
+                PortExtension->DeviceParams.RemovableDevice = 1;
+            }
+
+            if (IdentifyDeviceData->CommandSetSupport.BigLba && IdentifyDeviceData->CommandSetActive.BigLba)
+            {
+                PortExtension->DeviceParams.Lba48BitMode = 1;
+            }
+
+            PortExtension->DeviceParams.AccessType = DIRECT_ACCESS_DEVICE;
+
+            // TODO: Add other device params
+        }
+        else
+        {
+            DebugPrint("Device: ATAPI\n");
+            PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
+
+            PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
+        }
+    }
+    else if (SrbStatus == SRB_STATUS_NO_DEVICE)
+    {
+        DebugPrint("Device: No Device\n");
+        PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
+    }
+    else
+    {
+        return;
+    }
+
+    if ((cdb != NULL) && (cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS))
+    {
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;
+        Srb->ScsiStatus = SCSISTAT_GOOD;
+
+        SrbExtension->AtaFunction = 0;
+        DataBufferLength = Srb->DataTransferLength;
+
+        LunList = (PLUN_LIST)Srb->DataBuffer;
+        if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_NODEVICE)
+        {
+            LunCount = 0;
+        }
+        else
+        {
+            LunCount = 1;
+        }
+
+        if (DataBufferLength < sizeof(LUN_LIST))
+        {
+            DebugPrint("\tSRB_STATUS_DATA_OVERRUN\n");
+            Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+        }
+        else
+        {
+            LunList->LunListLength[0] = 0;
+            LunList->LunListLength[1] = 0;
+            LunList->LunListLength[2] = 0;
+            LunList->LunListLength[3] = 8;
+
+            // followed by 8 entries
+            LunList->Lun[0][0] = 0;
+            LunList->Lun[0][1] = 0;
+            LunList->Lun[0][2] = 0;
+            LunList->Lun[0][3] = 0;
+            LunList->Lun[0][4] = 0;
+            LunList->Lun[0][5] = 0;
+            LunList->Lun[0][6] = 0;
+            LunList->Lun[0][7] = 0;
+        }
+    }
+
+    return;
+}// -- InquiryCompletion();
+
 /**
  * @name DeviceInquiryRequest
  * @implemented
@@ -848,25 +1650,65 @@ AhciProcessIO (
  * @remark
  * http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
  */
-ULONG
+UCHAR
 DeviceInquiryRequest (
     __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
     __in PSCSI_REQUEST_BLOCK Srb,
-    __in PCDB Cdb
+    __in PCDB Cdb,
+    __in BOOLEAN HasProductDataRequest
     )
 {
     PVOID DataBuffer;
-    ULONG DataBufferLength;
+    PAHCI_PORT_EXTENSION PortExtension;
+    PAHCI_SRB_EXTENSION SrbExtension;
+    PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
+    ULONG DataBufferLength, RequiredDataBufferLength;
 
     DebugPrint("DeviceInquiryRequest()\n");
 
-    // 3.6.1
-    // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
-    if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
+    NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
+
+    SrbExtension = GetSrbExtension(Srb);
+    PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
+
+    if (Srb->Lun != 0)
     {
+        return SRB_STATUS_SELECTION_TIMEOUT;
+    }
+    else if ((HasProductDataRequest == FALSE) || (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0))
+    {
+        // 3.6.1
+        // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
         DebugPrint("\tEVPD Inquired\n");
+        NT_ASSERT(SrbExtension != NULL);
+
+        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);
+
+        AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
+        return SRB_STATUS_PENDING;
     }
-    else
+    else if (HasProductDataRequest == TRUE)
     {
         DebugPrint("\tVPD Inquired\n");
 
@@ -879,8 +1721,244 @@ DeviceInquiryRequest (
         }
 
         AhciZeroMemory(DataBuffer, DataBufferLength);
+
+        switch(Cdb->CDB6INQUIRY3.PageCode)
+        {
+            case VPD_SUPPORTED_PAGES:
+            {
+                DebugPrint("\tVPD_SUPPORTED_PAGES\n");
+                RequiredDataBufferLength = sizeof(VPD_SUPPORTED_PAGES_PAGE);
+                if (DataBufferLength < RequiredDataBufferLength)
+                {
+                    DebugPrint("\tDataBufferLength: %d Required: %d\n", DataBufferLength, RequiredDataBufferLength);
+                    return SRB_STATUS_INVALID_REQUEST;
+                }
+                else
+                {
+                    VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer;
+                    VpdOutputBuffer->DeviceType = PortExtension->DeviceParams.DeviceType;
+                    VpdOutputBuffer->DeviceTypeQualifier = 0;
+                    VpdOutputBuffer->PageCode = VPD_SUPPORTED_PAGES;
+                    VpdOutputBuffer->PageLength = 1;
+                    VpdOutputBuffer->SupportedPageList[0] = VPD_SUPPORTED_PAGES;
+
+                    return SRB_STATUS_SUCCESS;
+                }
+            }
+            break;
+            default:
+                DebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode);
+                break;
+        }
     }
 
-    AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
-    return SRB_STATUS_SUCCESS;
+    return SRB_STATUS_INVALID_REQUEST;
 }// -- 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;
+
+    DebugPrint("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
+    {
+        DebugPrint("\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();