* Return true if intialization was successful
*/
BOOLEAN
+NTAPI
AhciPortInitialize (
- __in PAHCI_PORT_EXTENSION PortExtension
+ __in PVOID DeviceExtension
)
{
- ULONG mappedLength, portNumber;
+ 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;
- DebugPrint("AhciPortInitialize()\n");
+ AhciDebugPrint("AhciPortInitialize()\n");
+ PortExtension = (PAHCI_PORT_EXTENSION)DeviceExtension;
adapterExtension = PortExtension->AdapterExtension;
abar = adapterExtension->ABAR_Address;
portNumber = PortExtension->PortNumber;
if ((mappedLength == 0) || ((commandListPhysical.LowPart % 1024) != 0))
{
- DebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
+ AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
return FALSE;
}
if ((mappedLength == 0) || ((receivedFISPhysical.LowPart % 256) != 0))
{
- DebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength);
+ 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’)
+ // ? 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))
PortExtension->IdentifyDeviceData,
&mappedLength);
- NT_ASSERT(mappedLength == sizeof(IDENTIFY_DEVICE_DATA));
-
// 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();
__in PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
{
- PVOID portsExtension = NULL;
PCHAR nonCachedExtension, tmp;
- ULONG status, index, NCS, AlignedNCS;
+ ULONG index, NCS, AlignedNCS;
ULONG portCount, portImplemented, nonCachedExtensionSize;
+ PAHCI_PORT_EXTENSION PortExtension;
- DebugPrint("AhciAllocateResourceForAdapter()\n");
+ AhciDebugPrint("AhciAllocateResourceForAdapter()\n");
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
AlignedNCS = ROUND_UP(NCS, 8);
break;
portCount = index + 1;
- DebugPrint("\tPort Count: %d\n", portCount);
+ AhciDebugPrint("\tPort Count: %d\n", portCount);
AdapterExtension->PortCount = portCount;
nonCachedExtensionSize = sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
if (AdapterExtension->NonCachedExtension == NULL)
{
- DebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
+ AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
return FALSE;
}
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;
+ PortExtension->PortNumber = index;
+ PortExtension->DeviceParams.IsActive = TRUE;
+ PortExtension->AdapterExtension = AdapterExtension;
+ PortExtension->CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension;
tmp = (PCHAR)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
- AdapterExtension->PortExtension[index].ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp;
- AdapterExtension->PortExtension[index].IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS));
+ PortExtension->ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp;
+ PortExtension->IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS));
+ PortExtension->MaxPortQueueDepth = NCS;
nonCachedExtension += nonCachedExtensionSize;
}
}
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 PVOID HwDeviceExtension,
+ __in PVOID SystemArgument1,
+ __in PVOID SystemArgument2
+ )
+{
+ PSCSI_REQUEST_BLOCK Srb;
+ PAHCI_SRB_EXTENSION SrbExtension;
+ STOR_LOCK_HANDLE lockhandle = {0};
+ PAHCI_COMPLETION_ROUTINE CompletionRoutine;
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
+ PAHCI_PORT_EXTENSION PortExtension;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n");
+
+ AdapterExtension = (PAHCI_ADAPTER_EXTENSION)HwDeviceExtension;
+ PortExtension = (PAHCI_PORT_EXTENSION)SystemArgument1;
+
+ 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 PVOID DeviceExtension
+ )
+{
+ ULONG index;
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
+ PAHCI_PORT_EXTENSION PortExtension;
+
+ AhciDebugPrint("AhciHwPassiveInitialize()\n");
+
+ AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
+
+ 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
* return TRUE if intialization was successful
*/
BOOLEAN
+NTAPI
AhciHwInitialize (
- __in PVOID AdapterExtension
+ __in PVOID DeviceExtension
)
{
- ULONG ghc, messageCount, status;
- PAHCI_ADAPTER_EXTENSION adapterExtension;
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
+ AHCI_GHC ghc;
- DebugPrint("AhciHwInitialize()\n");
+ AhciDebugPrint("AhciHwInitialize()\n");
- adapterExtension = AdapterExtension;
- adapterExtension->StateFlags.MessagePerPort = FALSE;
+ AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
+ 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;
- DebugPrint("\tMultiple MSI based message not supported\n");
+ AdapterExtension->StateFlags.MessagePerPort = TRUE;
+ AhciDebugPrint("\tMultiple MSI based message not supported\n");
}
+ StorPortEnablePassiveInitialization(AdapterExtension, AhciHwPassiveInitialize);
+
return TRUE;
}// -- AhciHwInitialize();
PSCSI_REQUEST_BLOCK Srb;
PAHCI_SRB_EXTENSION SrbExtension;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
- PAHCI_COMPLETION_ROUTINE CompletionRoutine;
- DebugPrint("AhciCompleteIssuedSrb()\n");
+ AhciDebugPrint("AhciCompleteIssuedSrb()\n");
NT_ASSERT(CommandsToComplete != 0);
- DebugPrint("\tCompleted Commands: %d\n", CommandsToComplete);
+ AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete);
AdapterExtension = PortExtension->AdapterExtension;
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
{
if (((1 << i) & CommandsToComplete) != 0)
{
- Srb = &PortExtension->Slot[i];
- NT_ASSERT(Srb != NULL);
+ Srb = PortExtension->Slot[i];
- if (Srb->SrbStatus == SRB_STATUS_PENDING)
+ if (Srb == NULL)
{
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ continue;
}
SrbExtension = GetSrbExtension(Srb);
- CompletionRoutine = SrbExtension->CompletionRoutine;
+ NT_ASSERT(SrbExtension != NULL);
- if (CompletionRoutine != NULL)
+ if (SrbExtension->CompletionRoutine != NULL)
{
- // now it's completion routine responsibility to set SrbStatus
- CompletionRoutine(AdapterExtension, PortExtension, Srb);
+ 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);
}
AHCI_INTERRUPT_STATUS PxISMasked;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
- DebugPrint("AhciInterruptHandler()\n");
- DebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
+ AhciDebugPrint("AhciInterruptHandler()\n");
+ AhciDebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
AdapterExtension = PortExtension->AdapterExtension;
NT_ASSERT(IsPortValid(AdapterExtension, PortExtension->PortNumber));
// 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);
+ AhciDebugPrint("\tFatal Error: %x\n", PxIS.Status);
}
// Normal Command Completion
* return FALSE Indicates the interrupt was not ours.
*/
BOOLEAN
-AhciHwInterrupt(
- __in PAHCI_ADAPTER_EXTENSION AdapterExtension
+NTAPI
+AhciHwInterrupt (
+ __in PVOID DeviceExtension
)
{
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
ULONG portPending, nextPort, i, portCount;
- DebugPrint("AhciHwInterrupt()\n");
+ AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
if (AdapterExtension->StateFlags.Removed)
{
}
portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS);
+
// we process interrupt for implemented ports only
portCount = AdapterExtension->PortCount;
portPending = portPending & AdapterExtension->PortImplemented;
for (i = 1; i <= portCount; i++)
{
nextPort = (AdapterExtension->LastInterruptPort + i) % portCount;
-
if ((portPending & (0x1 << nextPort)) == 0)
continue;
NT_ASSERT(IsPortValid(AdapterExtension, nextPort));
- if ((nextPort == AdapterExtension->LastInterruptPort) ||
- (AdapterExtension->PortExtension[nextPort].IsActive == FALSE))
+ if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE)
{
- return 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;
}
- DebugPrint("\tSomething went wrong");
+ AhciDebugPrint("\tSomething went wrong");
return FALSE;
}// -- AhciHwInterrupt();
* return FALSE if the request must be submitted later
*/
BOOLEAN
+NTAPI
AhciHwStartIo (
- __in PVOID AdapterExtension,
+ __in PVOID DeviceExtension,
__in PSCSI_REQUEST_BLOCK Srb
)
{
- UCHAR function, pathId;
- PAHCI_ADAPTER_EXTENSION adapterExtension;
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
- DebugPrint("AhciHwStartIo()\n");
+ AhciDebugPrint("AhciHwStartIo()\n");
- pathId = Srb->PathId;
- function = Srb->Function;
- adapterExtension = AdapterExtension;
+ AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
- if (!IsPortValid(adapterExtension, pathId))
+ if (!IsPortValid(AdapterExtension, Srb->PathId))
{
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
- StorPortNotification(RequestComplete, adapterExtension, Srb);
+ StorPortNotification(RequestComplete, AdapterExtension, Srb);
return TRUE;
}
- // 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.
- if (function == SRB_FUNCTION_PNP)
+ switch(Srb->Function)
{
- PSCSI_PNP_REQUEST_BLOCK pnpRequest;
-
- pnpRequest = (PSCSI_PNP_REQUEST_BLOCK)Srb;
- if ((pnpRequest->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST) != 0)
- {
- if ((pnpRequest->PnPAction == StorRemoveDevice) ||
- (pnpRequest->PnPAction == StorSurpriseRemoval))
- {
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- adapterExtension->StateFlags.Removed = 1;
- DebugPrint("\tAdapter removed\n");
- }
- else if (pnpRequest->PnPAction == StorStopDevice)
+ case SRB_FUNCTION_PNP:
{
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- DebugPrint("\tRequested to Stop the adapter\n");
+ // 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;
+ }
}
- else
+ break;
+ case SRB_FUNCTION_EXECUTE_SCSI:
{
- Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
- }
+ // 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;
+ }
- StorPortNotification(RequestComplete, adapterExtension, Srb);
- return TRUE;
- }
- }
+ NT_ASSERT(cdb != NULL);
- if (function == 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.
- if (Srb->CdbLength > 0)
- {
- PCDB cdb = (PCDB)&Srb->Cdb;
- if (cdb->CDB10.OperationCode == SCSIOP_INQUIRY)
- {
- Srb->SrbStatus = DeviceInquiryRequest(adapterExtension, Srb, cdb);
- }
- else
- {
- Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ 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;
+ }
}
- }
- else
- {
- Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
- }
-
- StorPortNotification(RequestComplete, adapterExtension, Srb);
- return TRUE;
+ break;
+ default:
+ AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb->Function);
+ Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
+ break;
}
- DebugPrint("\tUnknown function code recieved: %x\n", function);
- Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
- StorPortNotification(RequestComplete, adapterExtension, Srb);
+ if (Srb->SrbStatus != SRB_STATUS_PENDING)
+ {
+ StorPortNotification(RequestComplete, AdapterExtension, Srb);
+ }
+ else
+ {
+ AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
+ }
return TRUE;
}// -- AhciHwStartIo();
* return TRUE if bus was successfully reset
*/
BOOLEAN
+NTAPI
AhciHwResetBus (
__in PVOID AdapterExtension,
__in ULONG PathId
)
{
- STOR_LOCK_HANDLE lockhandle;
- PAHCI_ADAPTER_EXTENSION adapterExtension;
+ STOR_LOCK_HANDLE lockhandle = {0};
+// PAHCI_ADAPTER_EXTENSION adapterExtension;
- DebugPrint("AhciHwResetBus()\n");
+ AhciDebugPrint("AhciHwResetBus()\n");
- adapterExtension = AdapterExtension;
+// adapterExtension = AdapterExtension;
if (IsPortValid(AdapterExtension, PathId))
{
- AhciZeroMemory(&lockhandle, sizeof(lockhandle));
-
// Acquire Lock
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
* @remarks Called by Storport.
*/
ULONG
+NTAPI
AhciHwFindAdapter (
- __in PVOID AdapterExtension,
+ __in PVOID DeviceExtension,
__in PVOID HwContext,
__in PVOID BusInformation,
- __in PVOID ArgumentString,
+ __in PCHAR ArgumentString,
__inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
__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;
PAHCI_ADAPTER_EXTENSION adapterExtension;
- DebugPrint("AhciHwFindAdapter()\n");
+ AhciDebugPrint("AhciHwFindAdapter()\n");
+
+ UNREFERENCED_PARAMETER(HwContext);
+ UNREFERENCED_PARAMETER(BusInformation);
+ UNREFERENCED_PARAMETER(ArgumentString);
+ UNREFERENCED_PARAMETER(Reserved3);
- adapterExtension = AdapterExtension;
+ adapterExtension = DeviceExtension;
adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG))
{
- DebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG), pci_cfg_len);
+ 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 = pci_cfg_buf;
+ 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);
- DebugPrint("\tVendorID:%d DeviceID:%d RevisionID:%d\n", adapterExtension->VendorID,
- adapterExtension->DeviceID,
- adapterExtension->RevisionID);
+ AhciDebugPrint("\tVendorID: %04x DeviceID: %04x RevisionID: %02x\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++)
{
- accessRange = *ConfigInfo->AccessRanges;
if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
{
abar = StorPortGetDeviceBase(adapterExtension,
if (abar == NULL)
{
- DebugPrint("\tabar == NULL\n");
+ AhciDebugPrint("\tabar == NULL\n");
return SP_RETURN_ERROR; // corrupted information supplied
}
adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
- adapterExtension->LastInterruptPort = -1;
+ 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 = 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");
+ AhciDebugPrint("\tAE Already set, Reset()\n");
if (!AhciAdapterReset(adapterExtension))
{
- DebugPrint("\tReset Failed!\n");
+ AhciDebugPrint("\tReset Failed!\n");
return SP_RETURN_ERROR;// reset failed
}
}
- 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);
if (adapterExtension->PortImplemented == 0)
{
- DebugPrint("\tadapterExtension->PortImplemented == 0\n");
+ AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n");
return SP_RETURN_ERROR;
}
- ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;//128 KB
- ConfigInfo->NumberOfPhysicalBreaks = 0x21;
+ 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->MaximumNumberOfLogicalUnits = 1;
ConfigInfo->ResetTargetSupported = TRUE;
+ ConfigInfo->NumberOfPhysicalBreaks = 0x21;
+ ConfigInfo->MaximumNumberOfLogicalUnits = 1;
ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT;
+ ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
- 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))
{
- DebugPrint("\tAhciAllocateResourceForAdapter() == FALSE\n");
+ NT_ASSERT(FALSE);
return SP_RETURN_ERROR;
}
* NT_STATUS in case of driver loaded successfully.
*/
ULONG
+NTAPI
DriverEntry (
__in PVOID DriverObject,
__in PVOID RegistryPath
)
{
- HW_INITIALIZATION_DATA hwInitializationData;
- ULONG i, status;
-
- DebugPrint("Storahci Loaded\n");
-
+ ULONG status;
// initialize the hardware data structure
- AhciZeroMemory(&hwInitializationData, sizeof(HW_INITIALIZATION_DATA));
+ HW_INITIALIZATION_DATA hwInitializationData = {0};
// set size of hardware initialization structure
hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
hwInitializationData.HwFindAdapter = AhciHwFindAdapter;
// adapter specific information
- hwInitializationData.NeedPhysicalAddresses = TRUE;
hwInitializationData.TaggedQueuing = TRUE;
hwInitializationData.AutoRequestSense = TRUE;
hwInitializationData.MultipleRequestPerLu = TRUE;
+ hwInitializationData.NeedPhysicalAddresses = TRUE;
hwInitializationData.NumberOfAccessRanges = 6;
hwInitializationData.AdapterInterfaceType = PCIBus;
&hwInitializationData,
NULL);
- DebugPrint("\tstatus:%x\n", status);
+ NT_ASSERT(status == STATUS_SUCCESS);
return status;
}// -- DriverEntry();
* @param PortExtension
* @param Srb
*
+ * @return
+ * Number of CFIS fields used in DWORD
*/
-VOID
+ULONG
AhciATA_CFIS (
__in PAHCI_PORT_EXTENSION PortExtension,
__in PAHCI_SRB_EXTENSION SrbExtension
{
PAHCI_COMMAND_TABLE cmdTable;
- DebugPrint("AhciATA_CFIS()\n");
+ UNREFERENCED_PARAMETER(PortExtension);
- cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
+ AhciDebugPrint("AhciATA_CFIS()\n");
- NT_ASSERT(sizeof(cmdTable->CFIS) == 64);
+ cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
- AhciZeroMemory(&cmdTable->CFIS, sizeof(cmdTable->CFIS));
+ AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS));
- cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = 0x27; // FIS Type
- cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C
+ cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = FIS_TYPE_REG_H2D; // FIS Type
+ cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C
cmdTable->CFIS[AHCI_ATA_CFIS_CommandReg] = SrbExtension->CommandReg;
cmdTable->CFIS[AHCI_ATA_CFIS_FeaturesLow] = SrbExtension->FeaturesLow;
cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountLow] = SrbExtension->SectorCountLow;
cmdTable->CFIS[AHCI_ATA_CFIS_SectorCountHigh] = SrbExtension->SectorCountHigh;
- return;
+ return 5;
}// -- AhciATA_CFIS();
/**
* @param PortExtension
* @param Srb
*
+ * @return
+ * Number of CFIS fields used in DWORD
*/
-VOID
+ULONG
AhciATAPI_CFIS (
__in PAHCI_PORT_EXTENSION PortExtension,
__in PAHCI_SRB_EXTENSION SrbExtension
)
{
- DebugPrint("AhciATAPI_CFIS()\n");
+ 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();
/**
PLOCAL_SCATTER_GATHER_LIST sgl;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
- DebugPrint("AhciBuild_PRDT()\n");
+ AhciDebugPrint("AhciBuild_PRDT()\n");
- sgl = &SrbExtension->Sgl;
+ sgl = SrbExtension->pSgl;
cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
AdapterExtension = PortExtension->AdapterExtension;
{
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;
__in ULONG SlotIndex
)
{
- ULONG prdtlen, sig, length;
+ ULONG prdtlen, sig, length, cfl;
PAHCI_SRB_EXTENSION SrbExtension;
PAHCI_COMMAND_HEADER CommandHeader;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress;
- DebugPrint("AhciProcessSrb()\n");
+ AhciDebugPrint("AhciProcessSrb()\n");
NT_ASSERT(Srb->PathId == PortExtension->PortNumber);
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;
}
}
// program the CFIS in the CommandTable
CommandHeader = &PortExtension->CommandList[SlotIndex];
- if (IsAtaCommand(SrbExtension->AtaFunction))
+ cfl = 0;
+ if (IsAtapiCommand(SrbExtension->AtaFunction))
+ {
+ cfl = AhciATAPI_CFIS(PortExtension, SrbExtension);
+ }
+ else if (IsAtaCommand(SrbExtension->AtaFunction))
{
- AhciATA_CFIS(PortExtension, SrbExtension);
+ cfl = AhciATA_CFIS(PortExtension, SrbExtension);
}
- else if (IsAtapiCommand(SrbExtension->AtaFunction))
+ else
{
- AhciATAPI_CFIS(PortExtension, SrbExtension);
+ NT_ASSERT(FALSE);
}
prdtlen = 0;
// Program the command header
CommandHeader->DI.PRDTL = prdtlen; // number of entries in PRD table
- CommandHeader->DI.CFL = 5;
+ CommandHeader->DI.CFL = cfl;
+ CommandHeader->DI.A = (SrbExtension->AtaFunction & ATA_FUNCTION_ATAPI_COMMAND) ? 1 : 0;
CommandHeader->DI.W = (SrbExtension->Flags & ATA_FLAGS_DATA_OUT) ? 1 : 0;
CommandHeader->DI.P = 0; // ATA Specifications says so
CommandHeader->DI.PMP = 0; // Port Multiplier
CommandHeader->Reserved[3] = 0;
// set CommandHeader CTBA
- // I am really not sure if SrbExtension is 128 byte aligned or not
- // Command FIS will not work if it is not so.
CommandTablePhysicalAddress = StorPortGetPhysicalAddress(AdapterExtension,
NULL,
SrbExtension,
&length);
+ NT_ASSERT(length != 0);
+
// command table alignment
NT_ASSERT((CommandTablePhysicalAddress.LowPart % 128) == 0);
- CommandHeader->CTBA0 = CommandTablePhysicalAddress.LowPart;
+ CommandHeader->CTBA = CommandTablePhysicalAddress.LowPart;
if (IsAdapterCAPS64(AdapterExtension->CAP))
{
- CommandHeader->CTBA_U0 = CommandTablePhysicalAddress.HighPart;
+ CommandHeader->CTBA_U = CommandTablePhysicalAddress.HighPart;
}
// mark this slot
PortExtension->Slot[SlotIndex] = Srb;
- PortExtension->QueueSlots |= SlotIndex;
+ PortExtension->QueueSlots |= 1 << SlotIndex;
return;
}// -- AhciProcessSrb();
* @param PortExtension
*
*/
+
+#ifdef _MSC_VER // avoid MSVC C4700
+ #pragma warning(push)
+ #pragma warning(disable: 4700)
+#endif
+
VOID
AhciActivatePort (
__in PAHCI_PORT_EXTENSION PortExtension
)
{
- ULONG cmd, QueueSlots, slotToActivate, tmp;
+ AHCI_PORT_CMD cmd;
+ ULONG QueueSlots, slotToActivate, tmp;
PAHCI_ADAPTER_EXTENSION AdapterExtension;
- DebugPrint("AhciActivatePort()\n");
+ 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 = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
+ cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
- if ((cmd&1) == 0) // PxCMD.ST == 0
+ if (cmd.ST == 0) // PxCMD.ST == 0
+ {
return;
+ }
// get the lowest set bit
tmp = QueueSlots & (QueueSlots - 1);
return;
}// -- AhciActivatePort();
+#ifdef _MSC_VER // avoid MSVC C4700
+ #pragma warning(pop)
+#endif
+
/**
* @name AhciProcessIO
* @implemented
__in PSCSI_REQUEST_BLOCK Srb
)
{
- STOR_LOCK_HANDLE lockhandle;
PSCSI_REQUEST_BLOCK tmpSrb;
+ STOR_LOCK_HANDLE lockhandle = {0};
PAHCI_PORT_EXTENSION PortExtension;
ULONG commandSlotMask, occupiedSlots, slotIndex, NCS;
- DebugPrint("AhciProcessIO()\n");
- DebugPrint("\tPathId: %d\n", PathId);
+ 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->IsActive == FALSE)
- return; // we should wait for device to get active
-
- AhciZeroMemory(&lockhandle, sizeof(lockhandle));
-
- // Acquire Lock
- StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
+ 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);
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 PVOID _Extension,
+ __in PVOID _Srb
+ )
+{
+ PAHCI_PORT_EXTENSION PortExtension;
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
+ PSCSI_REQUEST_BLOCK Srb;
+ BOOLEAN status;
+
+ AhciDebugPrint("AtapiInquiryCompletion()\n");
+
+ PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
+ Srb = (PSCSI_REQUEST_BLOCK)_Srb;
+
+ 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
- * @not_implemented
+ * @implemented
*
* InquiryCompletion routine should be called after device signals
* for device inquiry request is completed (through interrupt)
*/
VOID
InquiryCompletion (
- __in PAHCI_ADAPTER_EXTENSION AdapterExtension,
- __in PAHCI_PORT_EXTENSION PortExtension,
- __in PSCSI_REQUEST_BLOCK Srb
+ __in PVOID _Extension,
+ __in PVOID _Srb
)
{
- ULONG SrbStatus;
+ PAHCI_PORT_EXTENSION PortExtension;
+ PSCSI_REQUEST_BLOCK Srb;
+
+// PCDB cdb;
+ BOOLEAN status;
+ PINQUIRYDATA InquiryData;
PAHCI_SRB_EXTENSION SrbExtension;
+ PAHCI_ADAPTER_EXTENSION AdapterExtension;
+ PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
- DebugPrint("InquiryCompletion()\n");
+ AhciDebugPrint("InquiryCompletion()\n");
+
+ PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
+ Srb = (PSCSI_REQUEST_BLOCK)_Srb;
- NT_ASSERT(PortExtension != NULL);
NT_ASSERT(Srb != NULL);
+ NT_ASSERT(PortExtension != NULL);
- SrbStatus = Srb->SrbStatus;
+// cdb = (PCDB)&Srb->Cdb;
+ InquiryData = Srb->DataBuffer;
SrbExtension = GetSrbExtension(Srb);
+ AdapterExtension = PortExtension->AdapterExtension;
+ IdentifyDeviceData = PortExtension->IdentifyDeviceData;
- if (SrbStatus == SRB_STATUS_SUCCESS)
+ if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
{
- if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
+ 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)
{
- AdapterExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
+ PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->Max48BitLBA[0];
+ PortExtension->DeviceParams.MaxLba.HighPart = IdentifyDeviceData->Max48BitLBA[1];
}
else
{
- AdapterExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
+ 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);
}
- // TODO: Set Device Paramters
+
+ 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 if (SrbStatus == SRB_STATUS_NO_DEVICE)
+ else
{
- AdapterExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
+ AhciDebugPrint("\tATAPI Device\n");
+ PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
+ PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
}
- else
+
+ // INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
+ if (Srb->DataTransferLength < INQUIRYDATABUFFERSIZE)
{
- return;
+ 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
* @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,
)
{
PVOID DataBuffer;
- ULONG DataBufferLength;
- PAHCI_PORT_EXTENSION PortExtension;
PAHCI_SRB_EXTENSION SrbExtension;
+ PAHCI_PORT_EXTENSION PortExtension;
+ PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
+ ULONG DataBufferLength, RequiredDataBufferLength;
- DebugPrint("DeviceInquiryRequest()\n");
+ AhciDebugPrint("DeviceInquiryRequest()\n");
+ NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_INQUIRY);
NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
SrbExtension = GetSrbExtension(Srb);
PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
- // 3.6.1
- // If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
- if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
+ if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
+ {
+ return AhciATAPICommand(AdapterExtension, Srb, Cdb);
+ }
+
+ if (Srb->Lun != 0)
{
- DebugPrint("\tEVPD Inquired\n");
+ 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->LBA0 = 0;
SrbExtension->LBA1 = 0;
SrbExtension->LBA2 = 0;
- SrbExtension->Device = 0;
+ SrbExtension->Device = 0xA0;
SrbExtension->LBA3 = 0;
SrbExtension->LBA4 = 0;
SrbExtension->LBA5 = 0;
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
{
- DebugPrint("\tVPD Inquired\n");
+ AhciDebugPrint("\tVPD Inquired\n");
DataBuffer = Srb->DataBuffer;
DataBufferLength = Srb->DataTransferLength;
+ RequiredDataBufferLength = DataBufferLength; // make the compiler happy :p
if (DataBuffer == NULL)
{
AhciZeroMemory(DataBuffer, DataBufferLength);
- // not supported
- return SRB_STATUS_BAD_FUNCTION;
- }
+ 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;
+ }
- AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
- return SRB_STATUS_PENDING;
+ Srb->DataTransferLength = RequiredDataBufferLength;
+ return SRB_STATUS_SUCCESS;
+ }
}// -- DeviceInquiryRequest();
/**
__in PAHCI_ADAPTER_EXTENSION AdapterExtension
)
{
- ULONG ghc, ticks, ghcStatus;
+ ULONG ticks;
+ AHCI_GHC ghc;
PAHCI_MEMORY_REGISTERS abar = NULL;
- DebugPrint("AhciAdapterReset()\n");
+ AhciDebugPrint("AhciAdapterReset()\n");
abar = AdapterExtension->ABAR_Address;
if (abar == NULL) // basic sanity
}
// HR -- Very first bit (lowest significant)
- ghc = AHCI_Global_HBA_CONTROL_HR;
- StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc);
+ ghc.HR = 1;
+ StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status);
for (ticks = 0; ticks < 50; ++ticks)
{
- ghcStatus = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
- if ((ghcStatus & AHCI_Global_HBA_CONTROL_HR) == 0)
+ ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
+ if (ghc.HR == 0)
{
break;
}
if (ticks == 50)// 1 second
{
- DebugPrint("\tDevice Timeout\n");
+ AhciDebugPrint("\tDevice Timeout\n");
return FALSE;
}
BOOLEAN
IsPortValid (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
- __in UCHAR pathId
+ __in ULONG pathId
)
{
- NT_ASSERT(pathId >= 0);
+ NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
if (pathId >= AdapterExtension->PortCount)
{
return FALSE;
}
- return AdapterExtension->PortExtension[pathId].IsActive;
+ return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive;
}// -- IsPortValid()
/**
ULONG Offset;
ULONG_PTR SrbExtension;
- SrbExtension = Srb->SrbExtension;
+ SrbExtension = (ULONG_PTR)Srb->SrbExtension;
Offset = SrbExtension % 128;
// CommandTable should be 128 byte aligned
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