AHCI-SATA Interface almost ready.

- tested on VM.
- need to implement Interrupt Routine (MessagePerPort) and ATA/ATAPI Based SCSI Query.

svn path=/branches/GSoC_2016/AHCI/; revision=71588
This commit is contained in:
Aman Priyadarshi 2016-06-07 11:05:32 +00:00
parent 37fd8e78e1
commit d4c9e20b36
3 changed files with 236 additions and 104 deletions

View file

@ -1,6 +1,7 @@
TARGETNAME = storahci
TARGETTYPE = MINIPORT
MSC_WARNING_LEVEL=/W4
TARGETLIBS=$(DDK_LIB_PATH)\storport.lib
INCLUDES = %BUILD%\inc

View file

@ -11,11 +11,18 @@ BOOLEAN AhciAdapterReset(
__in PAHCI_ADAPTER_EXTENSION adapterExtension
);
__inline
VOID AhciZeroMemory(
__in PCHAR buffer,
__in ULONG bufferSize
);
__inline
BOOLEAN IsPortValid(
__in PAHCI_ADAPTER_EXTENSION adapterExtension,
__in UCHAR pathId
);
/**
* @name AhciPortInitialize
* @implemented
@ -40,6 +47,7 @@ BOOLEAN AhciPortInitialize(
adapterExtension = portExtension->AdapterExtension;
abar = adapterExtension->ABAR_Address;
portExtension->Port = &abar->PortList[portExtension->PortNumber];
commandListPhysical = StorPortGetPhysicalAddress(adapterExtension, NULL, portExtension->CommandList, &mappedLength);
@ -61,6 +69,14 @@ BOOLEAN AhciPortInitialize(
StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->CLB, commandListPhysical.LowPart);
StorPortWriteRegisterUlong(adapterExtension, &portExtension->Port->FB, receivedFISPhysical.LowPart);
// 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();
@ -117,32 +133,15 @@ BOOLEAN AhciAllocateResourceForAdapter(
AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize);
// allocate memory for port extension
/* --> Allocate memory for port extension, but right now it is returning STOR_STATUS_NOT_IMPLEMENTED
so, for testing purpose, I allocated during driver entry itself.
status = StorPortAllocatePool(
adapterExtension,
portCount * sizeof(AHCI_PORT_EXTENSION),
AHCI_POOL_TAG,
(PVOID*)&portsExtension);
if (status != STOR_STATUS_SUCCESS){
StorPortDebugPrint(0, "\tstatus : %x\n", status);
return FALSE;
}
AhciZeroMemory((PCHAR)portsExtension, portCount * sizeof(AHCI_PORT_EXTENSION));
*/
nonCachedExtensionSize /= portCount;
currentCount = 0;
for (index = 0; index < 32; index++)
for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
{
adapterExtension->PortExtension[index].IsActive = FALSE;
if ((adapterExtension->PortImplemented & (1<<index)) != 0)
{
//adapterExtension->PortExtension[index] = (PAHCI_PORT_EXTENSION)((PCHAR)portsExtension + sizeof(AHCI_PORT_EXTENSION) * currentCount);
adapterExtension->PortExtension[index].PortNumber = index;
adapterExtension->PortExtension[index].IsActive = TRUE;
adapterExtension->PortExtension[index].AdapterExtension = adapterExtension;
adapterExtension->PortExtension[index].CommandList = (PAHCI_COMMAND_HEADER)(nonCachedExtension + (currentCount*nonCachedExtensionSize));
adapterExtension->PortExtension[index].ReceivedFIS = (PAHCI_RECEIVED_FIS)((PCHAR)adapterExtension->PortExtension[index].CommandList + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
@ -168,11 +167,26 @@ BOOLEAN AhciHwInitialize(
__in PVOID AdapterExtension
)
{
ULONG ghc, messageCount, status;
PAHCI_ADAPTER_EXTENSION adapterExtension;
StorPortDebugPrint(0, "AhciHwInitialize()\n");
adapterExtension = (PAHCI_ADAPTER_EXTENSION)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;
StorPortDebugPrint(0, "\tMultiple MSI based message not supported\n");
}
return TRUE;
}// -- AhciHwInitialize();
@ -199,7 +213,7 @@ BOOLEAN AhciHwInterrupt(
adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
return TRUE;
return FALSE;
}// -- AhciHwInterrupt();
/**
@ -221,14 +235,87 @@ BOOLEAN AhciHwStartIo(
)
{
UCHAR function;
UCHAR function, pathId;
PAHCI_ADAPTER_EXTENSION adapterExtension;
StorPortDebugPrint(0, "AhciHwStartIo()\n");
adapterExtension = (PAHCI_ADAPTER_EXTENSION)AdapterExtension;
pathId = Srb->PathId;
function = Srb->Function;
adapterExtension = (PAHCI_ADAPTER_EXTENSION)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;
StorPortDebugPrint(0, "\tadapter removed\n");
}
else if (pnpRequest->PnPAction == StorStopDevice)
{
Srb->SrbStatus = SRB_STATUS_SUCCESS;
StorPortDebugPrint(0, "\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)
{
StorPortDebugPrint(0, "\tINQUIRY Called!\n");
}
}
else
{
Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}
}
StorPortDebugPrint(0, "\tUnknow function code recieved: %x\n", function);
Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
StorPortNotification(RequestComplete, adapterExtension, Srb);
return TRUE;
}// -- AhciHwStartIo();
@ -374,7 +461,7 @@ ULONG AhciHwFindAdapter(
// 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 & (0x1<<31)) == 1)//Hmm, controller was already in power state
if ((ghc & AHCI_Global_HBA_CONTROL_AE) == 1)//Hmm, controller was already in power state
{
// reset controller to have it in know state
StorPortDebugPrint(0, "\tAE Already set, Reset()\n");
@ -384,10 +471,10 @@ ULONG AhciHwFindAdapter(
}
}
ghc = 0x1<<31;// only AE=1
ghc = AHCI_Global_HBA_CONTROL_AE;// only AE=1
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
adapterExtension->IS = abar->IS;
adapterExtension->IS = &abar->IS;
adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
if (adapterExtension->PortImplemented == 0){
@ -400,12 +487,12 @@ ULONG AhciHwFindAdapter(
ConfigInfo->MaximumNumberOfTargets = 1;
ConfigInfo->MaximumNumberOfLogicalUnits = 1;
ConfigInfo->ResetTargetSupported = TRUE;
ConfigInfo->NumberOfBuses = 32;
ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT;
ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
ConfigInfo->ScatterGather = TRUE;
// Turn IE -- Interrupt Enabled
ghc |= 0x2;
ghc |= AHCI_Global_HBA_CONTROL_IE;
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc);
// allocate necessary resource for each port
@ -414,9 +501,9 @@ ULONG AhciHwFindAdapter(
return SP_RETURN_ERROR;
}
for (index = 0; index < 32; index++)
for (index = 0; index < MAXIMUM_AHCI_PORT_COUNT; index++)
{
if ((adapterExtension->PortImplemented & (1<<index)) != 0)
if ((adapterExtension->PortImplemented & (0x1<<index)) != 0)
AhciPortInitialize(&adapterExtension->PortExtension[index]);
}
@ -443,7 +530,7 @@ ULONG DriverEntry(
HW_INITIALIZATION_DATA hwInitializationData;
ULONG i, status;
StorPortDebugPrint(0, "Storahci Loaded 10023\n");
StorPortDebugPrint(0, "Storahci Loaded\n");
// initialize the hardware data structure
AhciZeroMemory((PCHAR)&hwInitializationData, sizeof(HW_INITIALIZATION_DATA));
@ -478,6 +565,7 @@ ULONG DriverEntry(
RegistryPath,
&hwInitializationData,
NULL);
StorPortDebugPrint(0, "\tstatus:%x\n", status);
return status;
}// -- DriverEntry();
@ -538,6 +626,7 @@ BOOLEAN AhciAdapterReset(
*
* @param buffer
*/
__inline
VOID AhciZeroMemory(
__in PCHAR buffer,
__in ULONG bufferSize
@ -547,3 +636,26 @@ VOID AhciZeroMemory(
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 bus was successfully reset
*/
__inline
BOOLEAN IsPortValid(
__in PAHCI_ADAPTER_EXTENSION adapterExtension,
__in UCHAR pathId
)
{
if (pathId >= MAXIMUM_AHCI_PORT_COUNT)
return FALSE;
return adapterExtension->PortExtension[pathId].IsActive;
}// -- IsPortValid()

View file

@ -9,6 +9,17 @@
#include "storport.h"
#define AHCI_POOL_TAG 'ahci'
#define MAXIMUM_AHCI_PORT_COUNT 12
// section 3.1.2
#define AHCI_Global_HBA_CONTROL_HR (0x1<<0)
#define AHCI_Global_HBA_CONTROL_IE (0x1<<1)
#define AHCI_Global_HBA_CONTROL_MRSM (0x1<<2)
#define AHCI_Global_HBA_CONTROL_AE (0x1<<31)
//////////////////////////////////////////////////////////////
// ---- Support Structures --- //
//////////////////////////////////////////////////////////////
typedef struct _AHCI_FIS_DMA_SETUP
{
@ -54,12 +65,11 @@ typedef struct _AHCI_PIO_SETUP_FIS
USHORT TransferCount;
UCHAR Reserved5[2];
} AHCI_PIO_SETUP_FIS;
} AHCI_PIO_SETUP_FIS;
typedef struct _AHCI_D2H_REGISTER_FIS
{
UCHAR FisType; // 0x34
UCHAR FisType;
UCHAR Reserved1 :6;
UCHAR I:1;
UCHAR Reserved2 :1;
@ -83,9 +93,9 @@ typedef struct _AHCI_D2H_REGISTER_FIS
UCHAR Reserved4[4];
} AHCI_D2H_REGISTER_FIS;
typedef struct _AHCI_SET_DEVICE_BITS_FIS {
UCHAR FisType; //0xA1
typedef struct _AHCI_SET_DEVICE_BITS_FIS
{
UCHAR FisType;
UCHAR PMPort: 4;
UCHAR Reserved1 :2;
@ -100,9 +110,13 @@ typedef struct _AHCI_SET_DEVICE_BITS_FIS {
UCHAR Error;
UCHAR Reserved5[4];
} AHCI_SET_DEVICE_BITS_FIS;
} AHCI_SET_DEVICE_BITS_FIS;
// 4.2.2
//////////////////////////////////////////////////////////////
// --------------------------- //
//////////////////////////////////////////////////////////////
// 4.2.2 Command Header
typedef struct _AHCI_COMMAND_HEADER
{
ULONG HEADER_DESCRIPTION; // DW 0
@ -115,84 +129,81 @@ typedef struct _AHCI_COMMAND_HEADER
// Received FIS
typedef struct _AHCI_RECEIVED_FIS
{
AHCI_FIS_DMA_SETUP DmaSetupFIS; // 0x00 -- DMA Setup FIS
ULONG pad0; // 4 BYTE padding
AHCI_PIO_SETUP_FIS PioSetupFIS; // 0x20 -- PIO Setup FIS
ULONG pad1[3]; // 12 BYTE padding
AHCI_D2H_REGISTER_FIS RegisterFIS; // 0x40 -- Register Device to Host FIS
ULONG pad2; // 4 BYTE padding
AHCI_SET_DEVICE_BITS_FIS SetDeviceFIS; // 0x58 -- Set Device Bit FIS
ULONG UnknowFIS[16]; // 0x60 -- Unknown FIS
ULONG Reserved[24]; // 0xA0 -- Reserved
struct _AHCI_FIS_DMA_SETUP DmaSetupFIS; // 0x00 -- DMA Setup FIS
ULONG pad0; // 4 BYTE padding
struct _AHCI_PIO_SETUP_FIS PioSetupFIS; // 0x20 -- PIO Setup FIS
ULONG pad1[3]; // 12 BYTE padding
struct _AHCI_D2H_REGISTER_FIS RegisterFIS; // 0x40 -- Register Device to Host FIS
ULONG pad2; // 4 BYTE padding
struct _AHCI_SET_DEVICE_BITS_FIS SetDeviceFIS; // 0x58 -- Set Device Bit FIS
ULONG UnknowFIS[16]; // 0x60 -- Unknown FIS
ULONG Reserved[24]; // 0xA0 -- Reserved
} AHCI_RECEIVED_FIS, *PAHCI_RECEIVED_FIS;
// Holds Port Information
typedef struct _AHCI_PORT
{
ULONG CLB; // 0x00, command list base address, 1K-byte aligned
ULONG CLBU; // 0x04, command list base address upper 32 bits
ULONG FB; // 0x08, FIS base address, 256-byte aligned
ULONG FBU; // 0x0C, FIS base address upper 32 bits
ULONG IS; // 0x10, interrupt status
ULONG IE; // 0x14, interrupt enable
ULONG CMD; // 0x18, command and status
ULONG RSV0; // 0x1C, Reserved
ULONG TFD; // 0x20, task file data
ULONG SIG; // 0x24, signature
ULONG SSTS; // 0x28, SATA status (SCR0:SStatus)
ULONG SCTL; // 0x2C, SATA control (SCR2:SControl)
ULONG SERR; // 0x30, SATA error (SCR1:SError)
ULONG SACT; // 0x34, SATA active (SCR3:SActive)
ULONG CI; // 0x38, command issue
ULONG SNTF; // 0x3C, SATA notification (SCR4:SNotification)
ULONG FBS; // 0x40, FIS-based switch control
ULONG RSV1[11]; // 0x44 ~ 0x6F, Reserved
ULONG Vendor[4]; // 0x70 ~ 0x7F, vendor specific
ULONG CLB; // 0x00, command list base address, 1K-byte aligned
ULONG CLBU; // 0x04, command list base address upper 32 bits
ULONG FB; // 0x08, FIS base address, 256-byte aligned
ULONG FBU; // 0x0C, FIS base address upper 32 bits
ULONG IS; // 0x10, interrupt status
ULONG IE; // 0x14, interrupt enable
ULONG CMD; // 0x18, command and status
ULONG RSV0; // 0x1C, Reserved
ULONG TFD; // 0x20, task file data
ULONG SIG; // 0x24, signature
ULONG SSTS; // 0x28, SATA status (SCR0:SStatus)
ULONG SCTL; // 0x2C, SATA control (SCR2:SControl)
ULONG SERR; // 0x30, SATA error (SCR1:SError)
ULONG SACT; // 0x34, SATA active (SCR3:SActive)
ULONG CI; // 0x38, command issue
ULONG SNTF; // 0x3C, SATA notification (SCR4:SNotification)
ULONG FBS; // 0x40, FIS-based switch control
ULONG RSV1[11]; // 0x44 ~ 0x6F, Reserved
ULONG Vendor[4]; // 0x70 ~ 0x7F, vendor specific
} AHCI_PORT, *PAHCI_PORT;
typedef struct _AHCI_MEMORY_REGISTERS
{
// 0x00 - 0x2B, Generic Host Control
ULONG CAP; // 0x00, Host capability
ULONG GHC; // 0x04, Global host control
ULONG IS; // 0x08, Interrupt status
ULONG PI; // 0x0C, Port implemented
ULONG VS; // 0x10, Version
ULONG CCC_CTL; // 0x14, Command completion coalescing control
ULONG CCC_PTS; // 0x18, Command completion coalescing ports
ULONG EM_LOC; // 0x1C, Enclosure management location
ULONG EM_CTL; // 0x20, Enclosure management control
ULONG CAP2; // 0x24, Host capabilities extended
ULONG BOHC; // 0x28, BIOS/OS handoff control and status
// 0x2C - 0x9F, Reserved
ULONG Reserved[0xA0-0x2C];
// 0xA0 - 0xFF, Vendor specific registers
ULONG VendorSpecific[0x100-0xA0];
AHCI_PORT PortList[32];//1~32
ULONG CAP; // 0x00, Host capability
ULONG GHC; // 0x04, Global host control
ULONG IS; // 0x08, Interrupt status
ULONG PI; // 0x0C, Port implemented
ULONG VS; // 0x10, Version
ULONG CCC_CTL; // 0x14, Command completion coalescing control
ULONG CCC_PTS; // 0x18, Command completion coalescing ports
ULONG EM_LOC; // 0x1C, Enclosure management location
ULONG EM_CTL; // 0x20, Enclosure management control
ULONG CAP2; // 0x24, Host capabilities extended
ULONG BOHC; // 0x28, BIOS/OS handoff control and status
ULONG Reserved[0xA0-0x2C]; // 0x2C - 0x9F, Reserved
ULONG VendorSpecific[0x100-0xA0]; // 0xA0 - 0xFF, Vendor specific registers
AHCI_PORT PortList[MAXIMUM_AHCI_PORT_COUNT];
} AHCI_MEMORY_REGISTERS, *PAHCI_MEMORY_REGISTERS;
struct _AHCI_ADAPTER_EXTENSION;
// Holds information for each attached attached port to a given adapter.
typedef struct _AHCI_PORT_EXTENSION
{
ULONG PortNumber;
struct _AHCI_ADAPTER_EXTENSION* AdapterExtension;
PAHCI_COMMAND_HEADER CommandList;
BOOLEAN IsActive;
PAHCI_PORT Port; // AHCI Port Infomation
PAHCI_RECEIVED_FIS ReceivedFIS;
PAHCI_PORT Port;
PAHCI_COMMAND_HEADER CommandList;
STOR_DEVICE_POWER_STATE DevicePowerState; // Device Power State
struct _AHCI_ADAPTER_EXTENSION* AdapterExtension; // Port's Adapter Information
} AHCI_PORT_EXTENSION, *PAHCI_PORT_EXTENSION;
// Holds Adapter Information
typedef struct _AHCI_ADAPTER_EXTENSION
{
ULONG AdapterNumber;
ULONG SystemIoBusNumber;
ULONG SlotNumber;
ULONG AhciBaseAddress;
ULONG IS; // Interrupt status
ULONG PortImplemented;
PULONG IS;// Interrupt Status, In case of MSIM == `1`
ULONG PortImplemented;// bit-mapping of ports which are implemented
USHORT VendorID;
USHORT DeviceID;
@ -202,10 +213,18 @@ typedef struct _AHCI_ADAPTER_EXTENSION
ULONG CAP;
ULONG CAP2;
PVOID NonCachedExtension;
PVOID NonCachedExtension;// holds virtual address to noncached buffer allocated for Port Extension
struct
{
// Message per port or shared port?
ULONG MessagePerPort : 1;
ULONG Removed : 1;
ULONG Reserved : 30; // not in use -- maintain 4 byte alignment
} StateFlags;
PAHCI_MEMORY_REGISTERS ABAR_Address;
AHCI_PORT_EXTENSION PortExtension[32];
AHCI_PORT_EXTENSION PortExtension[MAXIMUM_AHCI_PORT_COUNT];
} AHCI_ADAPTER_EXTENSION, *PAHCI_ADAPTER_EXTENSION;
typedef struct _AHCI_SRB_EXTENSION