reactos/drivers/storage/storahci/storahci.c
Aman Priyadarshi dcf485d6f3 Added AHCI_Global_HBA_CAP_S64A support
Added AhciProcessIO
Added RC file
Added CMAKE file
And Some fixes

svn path=/branches/GSoC_2016/AHCI/; revision=71641
2016-06-15 17:07:26 +00:00

887 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* PROJECT: ReactOS Kernel
* LICENSE: GNU GPLv2 only as published by the Free Software Foundation
* PURPOSE: To Implement AHCI Miniport driver targeting storport NT 5.2
* PROGRAMMERS: Aman Priyadarshi (aman.eureka@gmail.com)
*/
#include "storahci.h"
/**
* @name AhciPortInitialize
* @implemented
*
* Initialize port by setting up PxCLB & PxFB Registers
*
* @param PortExtension
*
* @return
* Return true if intialization was successful
*/
BOOLEAN
AhciPortInitialize (
__in PAHCI_PORT_EXTENSION PortExtension
)
{
ULONG mappedLength, portNumber;
PAHCI_MEMORY_REGISTERS abar;
PAHCI_ADAPTER_EXTENSION adapterExtension;
STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical;
DebugPrint("AhciPortInitialize()\n");
adapterExtension = PortExtension->AdapterExtension;
abar = adapterExtension->ABAR_Address;
portNumber = PortExtension->PortNumber;
NT_ASSERT(abar != NULL);
NT_ASSERT(portNumber < MAXIMUM_AHCI_PORT_COUNT);
PortExtension->Port = &abar->PortList[portNumber];
commandListPhysical = StorPortGetPhysicalAddress(adapterExtension,
NULL,
PortExtension->CommandList,
&mappedLength);
if ((mappedLength == 0) || ((commandListPhysical.LowPart % 1024) != 0))
{
DebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
return FALSE;
}
receivedFISPhysical = StorPortGetPhysicalAddress(adapterExtension,
NULL,
PortExtension->ReceivedFIS,
&mappedLength);
if ((mappedLength == 0) || ((receivedFISPhysical.LowPart % 256) != 0))
{
DebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength);
return FALSE;
}
// 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)
{
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLBU, commandListPhysical.HighPart);
}
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FB, receivedFISPhysical.LowPart);
if ((adapterExtension->CAP & AHCI_Global_HBA_CAP_S64A) != 0)
{
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FBU, receivedFISPhysical.HighPart);
}
// 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));
return TRUE;
}// -- AhciPortInitialize();
/**
* @name AhciAllocateResourceForAdapter
* @implemented
*
* Allocate memory from poll for required pointers
*
* @param AdapterExtension
* @param ConfigInfo
*
* @return
* return TRUE if allocation was successful
*/
BOOLEAN
AhciAllocateResourceForAdapter (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
{
PVOID portsExtension = NULL;
PCHAR nonCachedExtension;
ULONG status, index, NCS, AlignedNCS;
ULONG portCount, portImplemented, nonCachedExtensionSize;
DebugPrint("AhciAllocateResourceForAdapter()\n");
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
AlignedNCS = ROUND_UP(NCS, 8);
// get port count -- Number of set bits in `AdapterExtension->PortImplemented`
portCount = 0;
portImplemented = AdapterExtension->PortImplemented;
// 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(portCount <= MAXIMUM_AHCI_PORT_COUNT);
DebugPrint("\tPort Count: %d\n", portCount);
nonCachedExtensionSize = sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
sizeof(AHCI_RECEIVED_FIS);
// align nonCachedExtensionSize to 1024
nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024);
AdapterExtension->NonCachedExtension = StorPortGetUncachedExtension(AdapterExtension,
ConfigInfo,
nonCachedExtensionSize * portCount);
if (AdapterExtension->NonCachedExtension == NULL)
{
DebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
return FALSE;
}
nonCachedExtension = AdapterExtension->NonCachedExtension;
AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount);
for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
{
AdapterExtension->PortExtension[index].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);
nonCachedExtension += nonCachedExtensionSize;
}
}
return TRUE;
}// -- AhciAllocateResourceForAdapter();
/**
* @name AhciHwInitialize
* @implemented
*
* initializes the HBA and finds all devices that are of interest to the miniport driver.
*
* @param adapterExtension
*
* @return
* return TRUE if intialization was successful
*/
BOOLEAN
AhciHwInitialize (
__in PVOID AdapterExtension
)
{
ULONG ghc, messageCount, status;
PAHCI_ADAPTER_EXTENSION adapterExtension;
DebugPrint("AhciHwInitialize()\n");
adapterExtension = AdapterExtension;
adapterExtension->StateFlags.MessagePerPort = FALSE;
// First check what type of interrupt/synchronization device is using
ghc = 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)
{
adapterExtension->StateFlags.MessagePerPort = TRUE;
DebugPrint("\tMultiple MSI based message not supported\n");
}
return TRUE;
}// -- AhciHwInitialize();
/**
* @name AhciInterruptHandler
* @not_implemented
*
* Interrupt Handler for PortExtension
*
* @param PortExtension
*
* @return
* return TRUE Indicates the interrupt was handled correctly
* return FALSE Indicates something went wrong
*/
BOOLEAN
AhciInterruptHandler (
__in PAHCI_PORT_EXTENSION PortExtension
)
{
DebugPrint("AhciInterruptHandler()\n");
DebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
return FALSE;
}// -- AhciInterruptHandler();
/**
* @name AhciHwInterrupt
* @implemented
*
* The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
*
* @param adapterExtension
*
* @return
* return TRUE Indicates that an interrupt was pending on adapter.
* return FALSE Indicates the interrupt was not ours.
*/
BOOLEAN
AhciHwInterrupt(
__in PVOID AdapterExtension
)
{
ULONG portPending, nextPort, i;
PAHCI_ADAPTER_EXTENSION adapterExtension;
DebugPrint("AhciHwInterrupt()\n");
adapterExtension = AdapterExtension;
if (adapterExtension->StateFlags.Removed)
{
return FALSE;
}
portPending = StorPortReadRegisterUlong(adapterExtension, adapterExtension->IS);
// we process interrupt for implemented ports only
portPending = portPending & adapterExtension->PortImplemented;
if (portPending == 0)
{
return FALSE;
}
for (i = 1; i <= MAXIMUM_AHCI_PORT_COUNT; i++)
{
nextPort = (adapterExtension->LastInterruptPort + i) % MAXIMUM_AHCI_PORT_COUNT;
if ((portPending & (0x1 << nextPort)) == 0)
continue;
if ((nextPort == adapterExtension->LastInterruptPort) ||
(adapterExtension->PortExtension[nextPort].IsActive == FALSE))
{
return FALSE;
}
// we can assign this interrupt to this port
adapterExtension->LastInterruptPort = nextPort;
return AhciInterruptHandler(&adapterExtension->PortExtension[nextPort]);
}
DebugPrint("\tSomething went wrong");
return FALSE;
}// -- AhciHwInterrupt();
/**
* @name AhciHwStartIo
* @implemented
*
* The Storport driver calls the HwStorStartIo routine one time for each incoming I/O request.
*
* @param adapterExtension
* @param Srb
*
* @return
* return TRUE if the request was accepted
* return FALSE if the request must be submitted later
*/
BOOLEAN
AhciHwStartIo (
__in PVOID AdapterExtension,
__in PSCSI_REQUEST_BLOCK Srb
)
{
UCHAR function, pathId;
PAHCI_ADAPTER_EXTENSION adapterExtension;
DebugPrint("AhciHwStartIo()\n");
pathId = Srb->PathId;
function = Srb->Function;
adapterExtension = AdapterExtension;
if (!IsPortValid(adapterExtension, pathId))
{
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
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)
{
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)
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
DebugPrint("\tRequested to Stop the adapter\n");
}
else
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
}
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}
}
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);
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}
}
else
{
Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}
}
DebugPrint("\tUnknow function code recieved: %x\n", function);
Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}// -- AhciHwStartIo();
/**
* @name AhciHwResetBus
* @not_implemented
*
* The HwStorResetBus routine is called by the port driver to clear error conditions.
*
* @param adapterExtension
* @param PathId
*
* @return
* return TRUE if bus was successfully reset
*/
BOOLEAN
AhciHwResetBus (
__in PVOID AdapterExtension,
__in ULONG PathId
)
{
PAHCI_ADAPTER_EXTENSION adapterExtension;
DebugPrint("AhciHwResetBus()\n");
adapterExtension = AdapterExtension;
if (IsPortValid(AdapterExtension, PathId))
{
// TODO: Reset Port
}
return FALSE;
}// -- AhciHwResetBus();
/**
* @name AhciHwFindAdapter
* @implemented
*
* The HwStorFindAdapter routine uses the supplied configuration to determine whether a specific
* HBA is supported and, if it is, to return configuration information about that adapter.
*
* 10.1 Platform Communication
* http://www.intel.in/content/dam/www/public/us/en/documents/technical-specifications/serial-ata-ahci-spec-rev1_2.pdf
* @param DeviceExtension
* @param HwContext
* @param BusInformation
* @param ArgumentString
* @param ConfigInfo
* @param Reserved3
*
* @return
* SP_RETURN_FOUND
* Indicates that a supported HBA was found and that the HBA-relevant configuration information was successfully determined and set in the PORT_CONFIGURATION_INFORMATION structure.
*
* SP_RETURN_ERROR
* Indicates that an HBA was found but there was an error obtaining the configuration information. If possible, such an error should be logged with StorPortLogError.
*
* SP_RETURN_BAD_CONFIG
* Indicates that the supplied configuration information was invalid for the adapter.
*
* SP_RETURN_NOT_FOUND
* Indicates that no supported HBA was found for the supplied configuration information.
*
* @remarks Called by Storport.
*/
ULONG
AhciHwFindAdapter (
__in PVOID AdapterExtension,
__in PVOID HwContext,
__in PVOID BusInformation,
__in PVOID ArgumentString,
__inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
__in PBOOLEAN Reserved3
)
{
ULONG ghc;
ULONG index;
ULONG portCount, portImplemented;
ULONG pci_cfg_len;
UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
PACCESS_RANGE accessRange;
PAHCI_MEMORY_REGISTERS abar;
PPCI_COMMON_CONFIG pciConfigData;
PAHCI_ADAPTER_EXTENSION adapterExtension;
DebugPrint("AhciHwFindAdapter()\n");
adapterExtension = AdapterExtension;
adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
// get PCI configuration header
pci_cfg_len = StorPortGetBusData(
adapterExtension,
PCIConfiguration,
adapterExtension->SystemIoBusNumber,
adapterExtension->SlotNumber,
pci_cfg_buf,
sizeof(PCI_COMMON_CONFIG));
if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG))
{
DebugPrint("\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;
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, its 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);
// 2.1.11
abar = NULL;
if (ConfigInfo->NumberOfAccessRanges > 0)
{
for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
{
accessRange = *ConfigInfo->AccessRanges;
if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
{
abar = StorPortGetDeviceBase(adapterExtension,
ConfigInfo->AdapterInterfaceType,
ConfigInfo->SystemIoBusNumber,
accessRange[index].RangeStart,
accessRange[index].RangeLength,
!accessRange[index].RangeInMemory);
break;
}
}
}
if (abar == NULL)
{
DebugPrint("\tabar == NULL\n");
return SP_RETURN_ERROR; // corrupted information supplied
}
adapterExtension->ABAR_Address = abar;
adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
adapterExtension->LastInterruptPort = -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);
// AE := Highest Significant bit of GHC
if ((ghc & AHCI_Global_HBA_CONTROL_AE) != 0)//Hmm, controller was already in power state
{
// reset controller to have it in known state
DebugPrint("\tAE Already set, Reset()\n");
if (!AhciAdapterReset(adapterExtension))
{
DebugPrint("\tReset Failed!\n");
return SP_RETURN_ERROR;// reset failed
}
}
ghc = AHCI_Global_HBA_CONTROL_AE;// only AE=1
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
adapterExtension->IS = &abar->IS;
adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
if (adapterExtension->PortImplemented == 0)
{
DebugPrint("\tadapterExtension->PortImplemented == 0\n");
return SP_RETURN_ERROR;
}
ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;//128 KB
ConfigInfo->NumberOfPhysicalBreaks = 0x21;
ConfigInfo->MaximumNumberOfTargets = 1;
ConfigInfo->MaximumNumberOfLogicalUnits = 1;
ConfigInfo->ResetTargetSupported = TRUE;
ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT;
ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
ConfigInfo->ScatterGather = TRUE;
// Turn IE -- Interrupt Enabled
ghc |= AHCI_Global_HBA_CONTROL_IE;
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
// allocate necessary resource for each port
if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo))
{
DebugPrint("\tAhciAllocateResourceForAdapter() == FALSE\n");
return SP_RETURN_ERROR;
}
for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
{
if ((adapterExtension->PortImplemented & (0x1<<index)) != 0)
AhciPortInitialize(&adapterExtension->PortExtension[index]);
}
return SP_RETURN_FOUND;
}// -- AhciHwFindAdapter();
/**
* @name DriverEntry
* @implemented
*
* Initial Entrypoint for storahci miniport driver
*
* @param DriverObject
* @param RegistryPath
*
* @return
* NT_STATUS in case of driver loaded successfully.
*/
ULONG
DriverEntry (
__in PVOID DriverObject,
__in PVOID RegistryPath
)
{
HW_INITIALIZATION_DATA hwInitializationData;
ULONG i, status;
DebugPrint("Storahci Loaded\n");
// initialize the hardware data structure
AhciZeroMemory(&hwInitializationData, sizeof(HW_INITIALIZATION_DATA));
// set size of hardware initialization structure
hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
// identity required miniport entry point routines
hwInitializationData.HwStartIo = AhciHwStartIo;
hwInitializationData.HwResetBus = AhciHwResetBus;
hwInitializationData.HwInterrupt = AhciHwInterrupt;
hwInitializationData.HwInitialize = AhciHwInitialize;
hwInitializationData.HwFindAdapter = AhciHwFindAdapter;
// adapter specific information
hwInitializationData.NeedPhysicalAddresses = TRUE;
hwInitializationData.TaggedQueuing = TRUE;
hwInitializationData.AutoRequestSense = TRUE;
hwInitializationData.MultipleRequestPerLu = TRUE;
hwInitializationData.NumberOfAccessRanges = 6;
hwInitializationData.AdapterInterfaceType = PCIBus;
hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
// set required extension sizes
hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
// register our hw init data
status = StorPortInitialize(DriverObject,
RegistryPath,
&hwInitializationData,
NULL);
DebugPrint("\tstatus:%x\n", status);
return status;
}// -- DriverEntry();
/**
* @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 ghc, ticks, ghcStatus;
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 = AHCI_Global_HBA_CONTROL_HR;
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc);
for (ticks = 0; ticks < 50; ++ticks)
{
ghcStatus = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
if ((ghcStatus & AHCI_Global_HBA_CONTROL_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;
}
}// -- 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 UCHAR pathId
)
{
NT_ASSERT(pathId >= 0);
if (pathId >= MAXIMUM_AHCI_PORT_COUNT)
{
return FALSE;
}
return AdapterExtension->PortExtension[pathId].IsActive;
}// -- IsPortValid()
/**
* @name AhciProcessIO
* @not_implemented
*
* Acquire Exclusive lock to port, populate pending commands to command List
* program controller's port to process new commands in command list.
*
* @param AdapterExtension
* @param pathId
* @param Srb
*
*/
VOID
AhciProcessIO (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in UCHAR pathId
)
{
STOR_LOCK_HANDLE lockhandle;
PAHCI_PORT_EXTENSION PortExtension;
ULONG commandSlotMask, occupiedSlots, slotIndex;
DebugPrint("AhciProcessIO()\n");
DebugPrint("\tPathId: %d\n", pathId);
PortExtension = &AdapterExtension->PortExtension[pathId];
NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
if (PortExtension->IsActive == FALSE)
return; // we should wait for device to get active
AhciZeroMemory(&lockhandle, sizeof(lockhandle));
// Acquire Lock
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
occupiedSlots = PortExtension->OccupiedSlots; // Busy command slots for given port
commandSlotMask = (1 << AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP)) - 1; // available slots mask
commandSlotMask = (commandSlotMask & ~occupiedSlots);
if(commandSlotMask != 0)
{
for (slotIndex = 0; slotIndex <= AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP); slotIndex++)
{
// find first free slot
if ((commandSlotMask & (1 << slotIndex)) != 0)
{
// TODO: remove from queue and process it
}
}
}
// Release Lock
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
}// -- AhciProcessIO();
/**
* @name DeviceInquiryRequest
* @implemented
*
* Tells wheather given port is implemented or not
*
* @param AdapterExtension
* @param Srb
* @param Cdb
*
* @return
* return STOR status for DeviceInquiryRequest
*
* @remark
* http://www.seagate.com/staticfiles/support/disc/manuals/Interface%20manuals/100293068c.pdf
*/
ULONG
DeviceInquiryRequest (
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
__in PSCSI_REQUEST_BLOCK Srb,
__in PCDB Cdb
)
{
PVOID DataBuffer;
ULONG DataBufferLength;
DebugPrint("DeviceInquiryRequest()\n");
// 3.6.1
// If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
{
DebugPrint("\tEVPD Inquired\n");
}
else
{
DebugPrint("\tVPD Inquired\n");
DataBuffer = Srb->DataBuffer;
DataBufferLength = Srb->DataTransferLength;
if (DataBuffer == NULL)
{
return SRB_STATUS_INVALID_REQUEST;
}
AhciZeroMemory(DataBuffer, DataBufferLength);
}
AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
return SRB_STATUS_SUCCESS;
}// -- DeviceInquiryRequest();