2016-06-02 14:43:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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)
|
|
|
|
|
*/
|
|
|
|
|
|
2016-06-02 14:13:06 +00:00
|
|
|
|
#include "storahci.h"
|
|
|
|
|
|
2016-06-03 15:54:21 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciPortInitialize
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Initialize port by setting up PxCLB & PxFB Registers
|
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* @param PortExtension
|
2016-06-03 15:54:21 +00:00
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* Return true if intialization was successful
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciPortInitialize (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID DeviceExtension
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-03 15:54:21 +00:00
|
|
|
|
{
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-07-04 19:01:07 +00:00
|
|
|
|
AHCI_PORT_CMD cmd;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
PAHCI_MEMORY_REGISTERS abar;
|
2016-08-14 12:54:10 +00:00
|
|
|
|
ULONG mappedLength, portNumber, ticks;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION adapterExtension;
|
|
|
|
|
STOR_PHYSICAL_ADDRESS commandListPhysical, receivedFISPhysical;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciPortInitialize()\n");
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PortExtension = (PAHCI_PORT_EXTENSION)DeviceExtension;
|
2016-06-10 08:27:20 +00:00
|
|
|
|
adapterExtension = PortExtension->AdapterExtension;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
abar = adapterExtension->ABAR_Address;
|
2016-06-10 08:27:20 +00:00
|
|
|
|
portNumber = PortExtension->PortNumber;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
NT_ASSERT(abar != NULL);
|
2016-06-16 21:14:03 +00:00
|
|
|
|
NT_ASSERT(portNumber < adapterExtension->PortCount);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
PortExtension->Port = &abar->PortList[portNumber];
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
commandListPhysical = StorPortGetPhysicalAddress(adapterExtension,
|
|
|
|
|
NULL,
|
|
|
|
|
PortExtension->CommandList,
|
|
|
|
|
&mappedLength);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
if ((mappedLength == 0) || ((commandListPhysical.LowPart % 1024) != 0))
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tcommandListPhysical mappedLength:%d\n", mappedLength);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
return FALSE;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
receivedFISPhysical = StorPortGetPhysicalAddress(adapterExtension,
|
|
|
|
|
NULL,
|
|
|
|
|
PortExtension->ReceivedFIS,
|
|
|
|
|
&mappedLength);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
if ((mappedLength == 0) || ((receivedFISPhysical.LowPart % 256) != 0))
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\treceivedFISPhysical mappedLength:%d\n", mappedLength);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-04 19:01:07 +00:00
|
|
|
|
// 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))
|
|
|
|
|
{
|
2016-08-14 12:54:10 +00:00
|
|
|
|
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);
|
2016-07-04 19:01:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-03 15:54:21 +00:00
|
|
|
|
// 10.1.2 For each implemented port, system software shall allocate memory for and program:
|
2017-10-13 19:52:38 +00:00
|
|
|
|
// ? PxCLB and PxCLBU (if CAP.S64A is set to ‘1’)
|
|
|
|
|
// ? PxFB and PxFBU (if CAP.S64A is set to ‘1’)
|
2016-06-09 23:47:19 +00:00
|
|
|
|
// Note: Assuming 32bit support only
|
2016-06-10 08:27:20 +00:00
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLB, commandListPhysical.LowPart);
|
2016-06-20 11:49:22 +00:00
|
|
|
|
if (IsAdapterCAPS64(adapterExtension->CAP))
|
2016-06-15 17:07:26 +00:00
|
|
|
|
{
|
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->CLBU, commandListPhysical.HighPart);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FB, receivedFISPhysical.LowPart);
|
2016-06-20 11:49:22 +00:00
|
|
|
|
if (IsAdapterCAPS64(adapterExtension->CAP))
|
2016-06-15 17:07:26 +00:00
|
|
|
|
{
|
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->FBU, receivedFISPhysical.HighPart);
|
|
|
|
|
}
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PortExtension->IdentifyDeviceDataPhysicalAddress = StorPortGetPhysicalAddress(adapterExtension,
|
|
|
|
|
NULL,
|
|
|
|
|
PortExtension->IdentifyDeviceData,
|
|
|
|
|
&mappedLength);
|
|
|
|
|
|
2016-06-07 11:05:32 +00:00
|
|
|
|
// set device power state flag to D0
|
2016-06-10 08:27:20 +00:00
|
|
|
|
PortExtension->DevicePowerState = StorPowerDeviceD0;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
|
|
|
|
// clear pending interrupts
|
2016-07-04 19:01:07 +00:00
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->SERR, (ULONG)~0);
|
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &PortExtension->Port->IS, (ULONG)~0);
|
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, adapterExtension->IS, (1 << PortExtension->PortNumber));
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-06-03 15:54:21 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}// -- AhciPortInitialize();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciAllocateResourceForAdapter
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Allocate memory from poll for required pointers
|
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* @param AdapterExtension
|
2016-06-03 15:54:21 +00:00
|
|
|
|
* @param ConfigInfo
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return TRUE if allocation was successful
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
|
|
|
|
AhciAllocateResourceForAdapter (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
|
|
|
|
__in PPORT_CONFIGURATION_INFORMATION ConfigInfo
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-03 15:54:21 +00:00
|
|
|
|
{
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PCHAR nonCachedExtension, tmp;
|
2016-07-04 20:20:25 +00:00
|
|
|
|
ULONG index, NCS, AlignedNCS;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
ULONG portCount, portImplemented, nonCachedExtensionSize;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciAllocateResourceForAdapter()\n");
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AlignedNCS = ROUND_UP(NCS, 8);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
// get port count -- Number of set bits in `AdapterExtension->PortImplemented`
|
2016-06-03 15:54:21 +00:00
|
|
|
|
portCount = 0;
|
2016-06-10 08:27:20 +00:00
|
|
|
|
portImplemented = AdapterExtension->PortImplemented;
|
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
NT_ASSERT(portImplemented != 0);
|
|
|
|
|
for (index = MAXIMUM_AHCI_PORT_COUNT - 1; index > 0; index--)
|
|
|
|
|
if ((portImplemented & (1 << index)) != 0)
|
|
|
|
|
break;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
portCount = index + 1;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tPort Count: %d\n", portCount);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
AdapterExtension->PortCount = portCount;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
nonCachedExtensionSize = sizeof(AHCI_COMMAND_HEADER) * AlignedNCS + //should be 1K aligned
|
2016-06-27 12:58:04 +00:00
|
|
|
|
sizeof(AHCI_RECEIVED_FIS) +
|
|
|
|
|
sizeof(IDENTIFY_DEVICE_DATA);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
// align nonCachedExtensionSize to 1024
|
|
|
|
|
nonCachedExtensionSize = ROUND_UP(nonCachedExtensionSize, 1024);
|
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
AdapterExtension->NonCachedExtension = StorPortGetUncachedExtension(AdapterExtension,
|
|
|
|
|
ConfigInfo,
|
|
|
|
|
nonCachedExtensionSize * portCount);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
if (AdapterExtension->NonCachedExtension == NULL)
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tadapterExtension->NonCachedExtension == NULL\n");
|
2016-06-03 15:54:21 +00:00
|
|
|
|
return FALSE;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
nonCachedExtension = AdapterExtension->NonCachedExtension;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciZeroMemory(nonCachedExtension, nonCachedExtensionSize * portCount);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
for (index = 0; index < portCount; index++)
|
2016-06-03 15:54:21 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PortExtension = &AdapterExtension->PortExtension[index];
|
|
|
|
|
|
|
|
|
|
PortExtension->DeviceParams.IsActive = FALSE;
|
2016-06-10 08:27:20 +00:00
|
|
|
|
if ((AdapterExtension->PortImplemented & (1 << index)) != 0)
|
2016-06-03 15:54:21 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PortExtension->PortNumber = index;
|
|
|
|
|
PortExtension->DeviceParams.IsActive = TRUE;
|
|
|
|
|
PortExtension->AdapterExtension = AdapterExtension;
|
|
|
|
|
PortExtension->CommandList = (PAHCI_COMMAND_HEADER)nonCachedExtension;
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
|
|
|
|
tmp = (PCHAR)(nonCachedExtension + sizeof(AHCI_COMMAND_HEADER) * AlignedNCS);
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PortExtension->ReceivedFIS = (PAHCI_RECEIVED_FIS)tmp;
|
|
|
|
|
PortExtension->IdentifyDeviceData = (PIDENTIFY_DEVICE_DATA)(tmp + sizeof(AHCI_RECEIVED_FIS));
|
|
|
|
|
PortExtension->MaxPortQueueDepth = NCS;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
nonCachedExtension += nonCachedExtensionSize;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}// -- AhciAllocateResourceForAdapter();
|
|
|
|
|
|
2016-07-04 19:01:07 +00:00
|
|
|
|
/**
|
|
|
|
|
* @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;
|
2016-07-05 16:51:17 +00:00
|
|
|
|
AHCI_TASK_FILE_DATA tfd;
|
|
|
|
|
AHCI_INTERRUPT_ENABLE ie;
|
2016-07-04 19:01:07 +00:00
|
|
|
|
AHCI_SERIAL_ATA_STATUS ssts;
|
|
|
|
|
AHCI_SERIAL_ATA_CONTROL sctl;
|
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciStartPort()\n");
|
2016-07-04 19:01:07 +00:00
|
|
|
|
|
|
|
|
|
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)))
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tCOMRESET\n");
|
2016-07-04 19:01:07 +00:00
|
|
|
|
// 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);
|
2016-07-05 16:51:17 +00:00
|
|
|
|
switch (ssts.DET)
|
2016-07-04 19:01:07 +00:00
|
|
|
|
{
|
2016-07-05 16:51:17 +00:00
|
|
|
|
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
|
2016-07-19 16:50:59 +00:00
|
|
|
|
// so better to turn this port off
|
2016-07-05 16:51:17 +00:00
|
|
|
|
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))
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tUnhandled Case BSY-DRQ\n");
|
2016-07-05 16:51:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Device to Host Register FIS Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.DHRE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* PIO Setup FIS Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.PSE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* DMA Setup FIS Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.DSE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Set Device Bits FIS Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.SDBE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Unknown FIS Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.UFE = 0;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Descriptor Processed Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.DPE = 0;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Port Change Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.PCE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Device Mechanical Presence Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.DMPE = 0;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* PhyRdy Change Interrupt Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.PRCE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Incorrect Port Multiplier Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.IPME = 0;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Overflow Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.OFE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Interface Non-fatal Error Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.INFE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Interface Fatal Error Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.IFE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Host Bus Data Error Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.HBDE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Host Bus Fatal Error Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.HBFE = 1;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* Task File Error Enable */
|
2016-07-05 16:51:17 +00:00
|
|
|
|
ie.TFEE = 1;
|
|
|
|
|
|
|
|
|
|
cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/* 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?
|
2016-07-05 16:51:17 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IE, ie.Status);
|
2016-07-05 16:51:17 +00:00
|
|
|
|
|
|
|
|
|
cmd.ST = 1;
|
|
|
|
|
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CMD, cmd.Status);
|
|
|
|
|
cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
|
|
|
|
|
|
|
|
|
|
if (cmd.ST != 1)
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tFailed to start Port\n");
|
2016-07-05 16:51:17 +00:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2016-07-19 16:50:59 +00:00
|
|
|
|
default:
|
|
|
|
|
// unhandled case
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tDET == %x Unsupported\n", ssts.DET);
|
2016-07-05 16:51:17 +00:00
|
|
|
|
return FALSE;
|
2016-07-04 19:01:07 +00:00
|
|
|
|
}
|
|
|
|
|
}// -- AhciStartPort();
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciCommandCompletionDpcRoutine
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Handles Completed Commands
|
|
|
|
|
*
|
|
|
|
|
* @param Dpc
|
|
|
|
|
* @param AdapterExtension
|
|
|
|
|
* @param SystemArgument1
|
|
|
|
|
* @param SystemArgument2
|
|
|
|
|
*/
|
|
|
|
|
VOID
|
|
|
|
|
AhciCommandCompletionDpcRoutine (
|
|
|
|
|
__in PSTOR_DPC Dpc,
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID HwDeviceExtension,
|
|
|
|
|
__in PVOID SystemArgument1,
|
2016-07-19 16:50:59 +00:00
|
|
|
|
__in PVOID SystemArgument2
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
PSCSI_REQUEST_BLOCK Srb;
|
|
|
|
|
PAHCI_SRB_EXTENSION SrbExtension;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
STOR_LOCK_HANDLE lockhandle = {0};
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PAHCI_COMPLETION_ROUTINE CompletionRoutine;
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
|
|
|
|
UNREFERENCED_PARAMETER(Dpc);
|
|
|
|
|
UNREFERENCED_PARAMETER(SystemArgument2);
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciCommandCompletionDpcRoutine()\n");
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
AdapterExtension = (PAHCI_ADAPTER_EXTENSION)HwDeviceExtension;
|
|
|
|
|
PortExtension = (PAHCI_PORT_EXTENSION)SystemArgument1;
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
|
|
|
|
|
Srb = RemoveQueue(&PortExtension->CompletionQueue);
|
2016-07-24 12:41:07 +00:00
|
|
|
|
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
|
|
|
|
NT_ASSERT(Srb != NULL);
|
|
|
|
|
|
|
|
|
|
if (Srb->SrbStatus == SRB_STATUS_PENDING)
|
|
|
|
|
{
|
|
|
|
|
Srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
|
}
|
2016-07-24 12:41:07 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
|
|
|
|
SrbExtension = GetSrbExtension(Srb);
|
2016-07-24 12:41:07 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
CompletionRoutine = SrbExtension->CompletionRoutine;
|
2016-07-24 12:41:07 +00:00
|
|
|
|
NT_ASSERT(CompletionRoutine != NULL);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-24 12:41:07 +00:00
|
|
|
|
// now it's completion routine responsibility to set SrbStatus
|
|
|
|
|
CompletionRoutine(PortExtension, Srb);
|
|
|
|
|
|
|
|
|
|
StorPortNotification(RequestComplete, AdapterExtension, Srb);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
|
|
|
|
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 (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID DeviceExtension
|
2016-07-19 16:50:59 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
ULONG index;
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciHwPassiveInitialize()\n");
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
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();
|
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
/**
|
2016-06-04 12:52:38 +00:00
|
|
|
|
* @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
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciHwInitialize (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID DeviceExtension
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-04 12:52:38 +00:00
|
|
|
|
{
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
AHCI_GHC ghc;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciHwInitialize()\n");
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
AdapterExtension->StateFlags.MessagePerPort = FALSE;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
|
|
|
|
// First check what type of interrupt/synchronization device is using
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &AdapterExtension->ABAR_Address->GHC);
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
// 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
|
2016-07-19 16:50:59 +00:00
|
|
|
|
if (ghc.MRSM == 0)
|
2016-06-07 11:05:32 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
AdapterExtension->StateFlags.MessagePerPort = TRUE;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tMultiple MSI based message not supported\n");
|
2016-06-07 11:05:32 +00:00
|
|
|
|
}
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
StorPortEnablePassiveInitialization(AdapterExtension, AhciHwPassiveInitialize);
|
2016-07-04 19:01:07 +00:00
|
|
|
|
|
2016-06-04 12:52:38 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}// -- AhciHwInitialize();
|
|
|
|
|
|
2016-06-30 16:04:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciCompleteIssuedSrb
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Complete issued Srbs
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
VOID
|
|
|
|
|
AhciCompleteIssuedSrb (
|
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension,
|
|
|
|
|
__in ULONG CommandsToComplete
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
ULONG NCS, i;
|
|
|
|
|
PSCSI_REQUEST_BLOCK Srb;
|
2016-07-24 12:41:07 +00:00
|
|
|
|
PAHCI_SRB_EXTENSION SrbExtension;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciCompleteIssuedSrb()\n");
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
|
|
|
|
NT_ASSERT(CommandsToComplete != 0);
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tCompleted Commands: %d\n", CommandsToComplete);
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
|
|
|
|
AdapterExtension = PortExtension->AdapterExtension;
|
|
|
|
|
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < NCS; i++)
|
|
|
|
|
{
|
|
|
|
|
if (((1 << i) & CommandsToComplete) != 0)
|
|
|
|
|
{
|
2016-07-04 19:01:07 +00:00
|
|
|
|
Srb = PortExtension->Slot[i];
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
2016-07-24 12:41:07 +00:00
|
|
|
|
if (Srb == NULL)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SrbExtension = GetSrbExtension(Srb);
|
|
|
|
|
NT_ASSERT(SrbExtension != NULL);
|
|
|
|
|
|
|
|
|
|
if (SrbExtension->CompletionRoutine != NULL)
|
|
|
|
|
{
|
|
|
|
|
AddQueue(&PortExtension->CompletionQueue, Srb);
|
|
|
|
|
StorPortIssueDpc(AdapterExtension, &PortExtension->CommandCompletion, PortExtension, Srb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-25 11:09:25 +00:00
|
|
|
|
NT_ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
|
2016-07-24 12:41:07 +00:00
|
|
|
|
Srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
|
StorPortNotification(RequestComplete, AdapterExtension, Srb);
|
|
|
|
|
}
|
2016-06-30 16:04:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}// -- AhciCompleteIssuedSrb();
|
|
|
|
|
|
2016-06-07 18:06:51 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciInterruptHandler
|
2016-06-15 17:07:26 +00:00
|
|
|
|
* @not_implemented
|
2016-06-07 18:06:51 +00:00
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* Interrupt Handler for PortExtension
|
2016-06-07 18:06:51 +00:00
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* @param PortExtension
|
2016-06-07 18:06:51 +00:00
|
|
|
|
*
|
|
|
|
|
*/
|
2016-06-16 17:02:55 +00:00
|
|
|
|
VOID
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciInterruptHandler (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-07 18:06:51 +00:00
|
|
|
|
{
|
2016-06-27 12:58:04 +00:00
|
|
|
|
ULONG is, ci, sact, outstanding;
|
2016-06-16 17:02:55 +00:00
|
|
|
|
AHCI_INTERRUPT_STATUS PxIS;
|
|
|
|
|
AHCI_INTERRUPT_STATUS PxISMasked;
|
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciInterruptHandler()\n");
|
|
|
|
|
AhciDebugPrint("\tPort Number: %d\n", PortExtension->PortNumber);
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
AdapterExtension = PortExtension->AdapterExtension;
|
|
|
|
|
NT_ASSERT(IsPortValid(AdapterExtension, PortExtension->PortNumber));
|
|
|
|
|
|
|
|
|
|
// 5.5.3
|
|
|
|
|
// 1. Software determines the cause of the interrupt by reading the PxIS register.
|
|
|
|
|
// It is possible for multiple bits to be set
|
|
|
|
|
// 2. Software clears appropriate bits in the PxIS register corresponding to the cause of the interrupt.
|
|
|
|
|
// 3. Software clears the interrupt bit in IS.IPS corresponding to the port.
|
|
|
|
|
// 4. If executing non-queued commands, software reads the PxCI register, and compares the current value to
|
|
|
|
|
// the list of commands previously issued by software that are still outstanding.
|
|
|
|
|
// If executing native queued commands, software reads the PxSACT register and compares the current
|
|
|
|
|
// value to the list of commands previously issued by software.
|
|
|
|
|
// Software completes with success any outstanding command whose corresponding bit has been cleared in
|
|
|
|
|
// the respective register. PxCI and PxSACT are volatile registers; software should only use their values
|
|
|
|
|
// to determine commands that have completed, not to determine which commands have previously been issued.
|
|
|
|
|
// 5. If there were errors, noted in the PxIS register, software performs error recovery actions (see section 6.2.2).
|
|
|
|
|
PxISMasked.Status = 0;
|
|
|
|
|
PxIS.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->IS);
|
|
|
|
|
|
|
|
|
|
// 6.2.2
|
|
|
|
|
// Fatal Error
|
|
|
|
|
// signified by the setting of PxIS.HBFS, PxIS.HBDS, PxIS.IFS, or PxIS.TFES
|
|
|
|
|
if (PxIS.HBFS || PxIS.HBDS || PxIS.IFS || PxIS.TFES)
|
|
|
|
|
{
|
|
|
|
|
// In this state, the HBA shall not issue any new commands nor acknowledge DMA Setup FISes to process
|
|
|
|
|
// any native command queuing commands. To recover, the port must be restarted
|
|
|
|
|
// To detect an error that requires software recovery actions to be performed,
|
|
|
|
|
// software should check whether any of the following status bits are set on an interrupt:
|
|
|
|
|
// PxIS.HBFS, PxIS.HBDS, PxIS.IFS, and PxIS.TFES. If any of these bits are set,
|
|
|
|
|
// software should perform the appropriate error recovery actions based on whether
|
|
|
|
|
// non-queued commands were being issued or native command queuing commands were being issued.
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tFatal Error: %x\n", PxIS.Status);
|
2016-06-16 17:02:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Normal Command Completion
|
|
|
|
|
// 3.3.5
|
|
|
|
|
// A D2H Register FIS has been received with the ‘I’ bit set, and has been copied into system memory.
|
|
|
|
|
PxISMasked.DHRS = PxIS.DHRS;
|
|
|
|
|
// A PIO Setup FIS has been received with the ‘I’ bit set, it has been copied into system memory.
|
|
|
|
|
PxISMasked.PSS = PxIS.PSS;
|
|
|
|
|
// A DMA Setup FIS has been received with the ‘I’ bit set and has been copied into system memory.
|
|
|
|
|
PxISMasked.DSS = PxIS.DSS;
|
|
|
|
|
// A Set Device Bits FIS has been received with the ‘I’ bit set and has been copied into system memory/
|
|
|
|
|
PxISMasked.SDBS = PxIS.SDBS;
|
|
|
|
|
// A PRD with the ‘I’ bit set has transferred all of its data.
|
|
|
|
|
PxISMasked.DPS = PxIS.DPS;
|
|
|
|
|
|
|
|
|
|
if (PxISMasked.Status != 0)
|
|
|
|
|
{
|
|
|
|
|
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->IS, PxISMasked.Status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 10.7.1.1
|
|
|
|
|
// Clear port interrupt
|
|
|
|
|
// It is set by the level of the virtual interrupt line being a set, and cleared by a write of ‘1’ from the software.
|
2016-06-27 12:58:04 +00:00
|
|
|
|
is = (1 << PortExtension->PortNumber);
|
|
|
|
|
StorPortWriteRegisterUlong(AdapterExtension, AdapterExtension->IS, is);
|
|
|
|
|
|
|
|
|
|
ci = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CI);
|
|
|
|
|
sact = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SACT);
|
|
|
|
|
|
|
|
|
|
outstanding = ci | sact; // NOTE: Including both non-NCQ and NCQ based commands
|
|
|
|
|
if ((PortExtension->CommandIssuedSlots & (~outstanding)) != 0)
|
|
|
|
|
{
|
2016-06-30 16:04:50 +00:00
|
|
|
|
AhciCompleteIssuedSrb(PortExtension, (PortExtension->CommandIssuedSlots & (~outstanding)));
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PortExtension->CommandIssuedSlots &= outstanding;
|
|
|
|
|
}
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
return;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
}// -- AhciInterruptHandler();
|
|
|
|
|
|
2016-06-04 12:52:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciHwInterrupt
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* The Storport driver calls the HwStorInterrupt routine after the HBA generates an interrupt request.
|
|
|
|
|
*
|
2016-06-16 21:14:03 +00:00
|
|
|
|
* @param AdapterExtension
|
2016-06-04 12:52:38 +00:00
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return TRUE Indicates that an interrupt was pending on adapter.
|
|
|
|
|
* return FALSE Indicates the interrupt was not ours.
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-07-19 16:50:59 +00:00
|
|
|
|
AhciHwInterrupt (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID DeviceExtension
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-04 12:52:38 +00:00
|
|
|
|
{
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
2016-06-16 21:14:03 +00:00
|
|
|
|
ULONG portPending, nextPort, i, portCount;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
|
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
if (AdapterExtension->StateFlags.Removed)
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-06-07 18:06:51 +00:00
|
|
|
|
return FALSE;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
}
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
portPending = StorPortReadRegisterUlong(AdapterExtension, AdapterExtension->IS);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-06-07 18:06:51 +00:00
|
|
|
|
// we process interrupt for implemented ports only
|
2016-06-16 21:14:03 +00:00
|
|
|
|
portCount = AdapterExtension->PortCount;
|
|
|
|
|
portPending = portPending & AdapterExtension->PortImplemented;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
|
|
|
|
if (portPending == 0)
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-06-07 18:06:51 +00:00
|
|
|
|
return FALSE;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
}
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
for (i = 1; i <= portCount; i++)
|
2016-06-07 18:06:51 +00:00
|
|
|
|
{
|
2016-06-16 21:14:03 +00:00
|
|
|
|
nextPort = (AdapterExtension->LastInterruptPort + i) % portCount;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
if ((portPending & (0x1 << nextPort)) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
NT_ASSERT(IsPortValid(AdapterExtension, nextPort));
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
if (AdapterExtension->PortExtension[nextPort].DeviceParams.IsActive == FALSE)
|
2016-07-04 19:01:07 +00:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 18:06:51 +00:00
|
|
|
|
// we can assign this interrupt to this port
|
2016-06-16 21:14:03 +00:00
|
|
|
|
AdapterExtension->LastInterruptPort = nextPort;
|
|
|
|
|
AhciInterruptHandler(&AdapterExtension->PortExtension[nextPort]);
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
portPending &= ~(1 << nextPort);
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
// interrupt belongs to this device
|
|
|
|
|
// should always return TRUE
|
|
|
|
|
return TRUE;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tSomething went wrong");
|
2016-06-07 11:05:32 +00:00
|
|
|
|
return FALSE;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}// -- AhciHwInterrupt();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciHwStartIo
|
2016-06-20 11:49:22 +00:00
|
|
|
|
* @not_implemented
|
2016-06-04 12:52:38 +00:00
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciHwStartIo (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID DeviceExtension,
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-04 12:52:38 +00:00
|
|
|
|
{
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciHwStartIo()\n");
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
AdapterExtension = (PAHCI_ADAPTER_EXTENSION)DeviceExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
if (!IsPortValid(AdapterExtension, Srb->PathId))
|
2016-06-07 11:05:32 +00:00
|
|
|
|
{
|
|
|
|
|
Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
StorPortNotification(RequestComplete, AdapterExtension, Srb);
|
2016-06-07 11:05:32 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
switch(Srb->Function)
|
2016-06-07 11:05:32 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
case SRB_FUNCTION_PNP:
|
2016-06-07 11:05:32 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
// 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;
|
|
|
|
|
}
|
2016-06-07 11:05:32 +00:00
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
break;
|
|
|
|
|
case SRB_FUNCTION_EXECUTE_SCSI:
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
// 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;
|
|
|
|
|
}
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(cdb != NULL);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
switch(cdb->CDB10.OperationCode)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
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;
|
2016-07-25 11:09:25 +00:00
|
|
|
|
case SCSIOP_TEST_UNIT_READY:
|
|
|
|
|
Srb->SrbStatus = DeviceRequestComplete(AdapterExtension, Srb, cdb);
|
|
|
|
|
break;
|
2016-07-25 19:50:09 +00:00
|
|
|
|
case SCSIOP_MODE_SENSE:
|
|
|
|
|
Srb->SrbStatus = DeviceRequestSense(AdapterExtension, Srb, cdb);
|
|
|
|
|
break;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
case SCSIOP_READ:
|
2016-07-26 14:15:15 +00:00
|
|
|
|
case SCSIOP_WRITE:
|
2016-07-23 22:53:15 +00:00
|
|
|
|
Srb->SrbStatus = DeviceRequestReadWrite(AdapterExtension, Srb, cdb);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
AhciDebugPrint("\tOperationCode: %d\n", cdb->CDB10.OperationCode);
|
2016-07-25 11:09:25 +00:00
|
|
|
|
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
break;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
2016-06-07 11:05:32 +00:00
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
AhciDebugPrint("\tUnknown function code recieved: %x\n", Srb->Function);
|
|
|
|
|
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
|
|
|
|
|
break;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-24 12:41:07 +00:00
|
|
|
|
if (Srb->SrbStatus != SRB_STATUS_PENDING)
|
|
|
|
|
{
|
|
|
|
|
StorPortNotification(RequestComplete, AdapterExtension, Srb);
|
|
|
|
|
}
|
2016-07-25 11:09:25 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AhciProcessIO(AdapterExtension, Srb->PathId, Srb);
|
|
|
|
|
}
|
2016-06-04 12:52:38 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}// -- AhciHwStartIo();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciHwResetBus
|
2016-06-09 23:47:19 +00:00
|
|
|
|
* @not_implemented
|
2016-06-04 12:52:38 +00:00
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciHwResetBus (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PVOID AdapterExtension,
|
|
|
|
|
__in ULONG PathId
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-04 12:52:38 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
STOR_LOCK_HANDLE lockhandle = {0};
|
2017-10-13 19:52:38 +00:00
|
|
|
|
// PAHCI_ADAPTER_EXTENSION adapterExtension;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciHwResetBus()\n");
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
// adapterExtension = AdapterExtension;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-06-15 17:07:26 +00:00
|
|
|
|
if (IsPortValid(AdapterExtension, PathId))
|
|
|
|
|
{
|
2016-06-16 17:02:55 +00:00
|
|
|
|
// Acquire Lock
|
|
|
|
|
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
|
|
|
|
|
|
|
|
|
|
// TODO: Perform port reset
|
|
|
|
|
|
|
|
|
|
// Release lock
|
|
|
|
|
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
|
2016-06-15 17:07:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-07 18:06:51 +00:00
|
|
|
|
return FALSE;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}// -- AhciHwResetBus();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciHwFindAdapter
|
2016-06-02 14:43:56 +00:00
|
|
|
|
* @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.
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
ULONG
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-06-09 23:47:19 +00:00
|
|
|
|
AhciHwFindAdapter (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID DeviceExtension,
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PVOID HwContext,
|
|
|
|
|
__in PVOID BusInformation,
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PCHAR ArgumentString,
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__inout PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
|
|
|
__in PBOOLEAN Reserved3
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-02 14:13:06 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
AHCI_GHC ghc;
|
|
|
|
|
ULONG index, pci_cfg_len;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
PACCESS_RANGE accessRange;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
UCHAR pci_cfg_buf[sizeof(PCI_COMMON_CONFIG)];
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
PAHCI_MEMORY_REGISTERS abar;
|
|
|
|
|
PPCI_COMMON_CONFIG pciConfigData;
|
|
|
|
|
PAHCI_ADAPTER_EXTENSION adapterExtension;
|
2016-06-02 14:13:06 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciHwFindAdapter()\n");
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-07-04 20:20:25 +00:00
|
|
|
|
UNREFERENCED_PARAMETER(HwContext);
|
|
|
|
|
UNREFERENCED_PARAMETER(BusInformation);
|
|
|
|
|
UNREFERENCED_PARAMETER(ArgumentString);
|
|
|
|
|
UNREFERENCED_PARAMETER(Reserved3);
|
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
adapterExtension = DeviceExtension;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
adapterExtension->SlotNumber = ConfigInfo->SlotNumber;
|
|
|
|
|
adapterExtension->SystemIoBusNumber = ConfigInfo->SystemIoBusNumber;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// get PCI configuration header
|
|
|
|
|
pci_cfg_len = StorPortGetBusData(
|
|
|
|
|
adapterExtension,
|
|
|
|
|
PCIConfiguration,
|
|
|
|
|
adapterExtension->SystemIoBusNumber,
|
|
|
|
|
adapterExtension->SlotNumber,
|
2016-06-09 23:47:19 +00:00
|
|
|
|
pci_cfg_buf,
|
|
|
|
|
sizeof(PCI_COMMON_CONFIG));
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
if (pci_cfg_len != sizeof(PCI_COMMON_CONFIG))
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tpci_cfg_len != %d :: %d", sizeof(PCI_COMMON_CONFIG), pci_cfg_len);
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return SP_RETURN_ERROR;//Not a valid device at the given bus number
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
pciConfigData = (PPCI_COMMON_CONFIG)pci_cfg_buf;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
AhciDebugPrint("\tVendorID: %04x DeviceID: %04x RevisionID: %02x\n",
|
|
|
|
|
adapterExtension->VendorID,
|
|
|
|
|
adapterExtension->DeviceID,
|
|
|
|
|
adapterExtension->RevisionID);
|
2016-06-04 12:52:38 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// 2.1.11
|
|
|
|
|
abar = NULL;
|
|
|
|
|
if (ConfigInfo->NumberOfAccessRanges > 0)
|
|
|
|
|
{
|
2016-07-04 20:20:25 +00:00
|
|
|
|
accessRange = *(ConfigInfo->AccessRanges);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
for (index = 0; index < ConfigInfo->NumberOfAccessRanges; index++)
|
2016-06-02 14:43:56 +00:00
|
|
|
|
{
|
2016-06-09 23:47:19 +00:00
|
|
|
|
if (accessRange[index].RangeStart.QuadPart == adapterExtension->AhciBaseAddress)
|
2016-06-02 14:43:56 +00:00
|
|
|
|
{
|
2016-06-15 17:07:26 +00:00
|
|
|
|
abar = StorPortGetDeviceBase(adapterExtension,
|
|
|
|
|
ConfigInfo->AdapterInterfaceType,
|
|
|
|
|
ConfigInfo->SystemIoBusNumber,
|
|
|
|
|
accessRange[index].RangeStart,
|
|
|
|
|
accessRange[index].RangeLength,
|
|
|
|
|
!accessRange[index].RangeInMemory);
|
2016-06-02 14:43:56 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
if (abar == NULL)
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tabar == NULL\n");
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return SP_RETURN_ERROR; // corrupted information supplied
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
|
|
|
|
adapterExtension->ABAR_Address = abar;
|
|
|
|
|
adapterExtension->CAP = StorPortReadRegisterUlong(adapterExtension, &abar->CAP);
|
|
|
|
|
adapterExtension->CAP2 = StorPortReadRegisterUlong(adapterExtension, &abar->CAP2);
|
|
|
|
|
adapterExtension->Version = StorPortReadRegisterUlong(adapterExtension, &abar->VS);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
adapterExtension->LastInterruptPort = (ULONG)-1;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
|
|
|
|
// 10.1.2
|
|
|
|
|
// 1. Indicate that system software is AHCI aware by setting GHC.AE to ‘1’.
|
2016-06-03 15:54:21 +00:00
|
|
|
|
// 3.1.2 -- AE bit is read-write only if CAP.SAM is '0'
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// AE := Highest Significant bit of GHC
|
2016-07-19 16:50:59 +00:00
|
|
|
|
if (ghc.AE != 0)// Hmm, controller was already in power state
|
2016-06-02 14:43:56 +00:00
|
|
|
|
{
|
2016-06-07 18:06:51 +00:00
|
|
|
|
// reset controller to have it in known state
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tAE Already set, Reset()\n");
|
2016-06-10 08:27:20 +00:00
|
|
|
|
if (!AhciAdapterReset(adapterExtension))
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tReset Failed!\n");
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return SP_RETURN_ERROR;// reset failed
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ghc.Status = 0;
|
|
|
|
|
ghc.AE = 1;// only AE=1
|
2016-07-04 19:01:07 +00:00
|
|
|
|
// tell the controller that we know about AHCI
|
2016-07-19 16:50:59 +00:00
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-07 11:05:32 +00:00
|
|
|
|
adapterExtension->IS = &abar->IS;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
adapterExtension->PortImplemented = StorPortReadRegisterUlong(adapterExtension, &abar->PI);
|
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
if (adapterExtension->PortImplemented == 0)
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tadapterExtension->PortImplemented == 0\n");
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return SP_RETURN_ERROR;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
ConfigInfo->MaximumNumberOfTargets = 1;
|
|
|
|
|
ConfigInfo->ResetTargetSupported = TRUE;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
ConfigInfo->NumberOfPhysicalBreaks = 0x21;
|
|
|
|
|
ConfigInfo->MaximumNumberOfLogicalUnits = 1;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
ConfigInfo->NumberOfBuses = MAXIMUM_AHCI_PORT_COUNT;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
// Turn IE -- Interrupt Enabled
|
|
|
|
|
ghc.Status = StorPortReadRegisterUlong(adapterExtension, &abar->GHC);
|
|
|
|
|
ghc.IE = 1;
|
|
|
|
|
StorPortWriteRegisterUlong(adapterExtension, &abar->GHC, ghc.Status);
|
|
|
|
|
|
2016-06-03 15:54:21 +00:00
|
|
|
|
// allocate necessary resource for each port
|
2016-06-09 23:47:19 +00:00
|
|
|
|
if (!AhciAllocateResourceForAdapter(adapterExtension, ConfigInfo))
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(FALSE);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
return SP_RETURN_ERROR;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
for (index = 0; index < adapterExtension->PortCount; index++)
|
2016-06-03 15:54:21 +00:00
|
|
|
|
{
|
2016-06-20 11:49:22 +00:00
|
|
|
|
if ((adapterExtension->PortImplemented & (0x1 << index)) != 0)
|
2016-06-05 12:40:49 +00:00
|
|
|
|
AhciPortInitialize(&adapterExtension->PortExtension[index]);
|
2016-06-03 15:54:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return SP_RETURN_FOUND;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}// -- AhciHwFindAdapter();
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name DriverEntry
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Initial Entrypoint for storahci miniport driver
|
|
|
|
|
*
|
|
|
|
|
* @param DriverObject
|
|
|
|
|
* @param RegistryPath
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* NT_STATUS in case of driver loaded successfully.
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
ULONG
|
2017-10-13 19:52:38 +00:00
|
|
|
|
NTAPI
|
2016-06-09 23:47:19 +00:00
|
|
|
|
DriverEntry (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PVOID DriverObject,
|
|
|
|
|
__in PVOID RegistryPath
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-02 14:13:06 +00:00
|
|
|
|
{
|
2016-07-04 20:20:25 +00:00
|
|
|
|
ULONG status;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// initialize the hardware data structure
|
2016-07-23 22:53:15 +00:00
|
|
|
|
HW_INITIALIZATION_DATA hwInitializationData = {0};
|
2016-06-02 14:13:06 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// set size of hardware initialization structure
|
|
|
|
|
hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
|
2016-06-02 14:13:06 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// identity required miniport entry point routines
|
2016-06-04 12:52:38 +00:00
|
|
|
|
hwInitializationData.HwStartIo = AhciHwStartIo;
|
|
|
|
|
hwInitializationData.HwResetBus = AhciHwResetBus;
|
|
|
|
|
hwInitializationData.HwInterrupt = AhciHwInterrupt;
|
|
|
|
|
hwInitializationData.HwInitialize = AhciHwInitialize;
|
|
|
|
|
hwInitializationData.HwFindAdapter = AhciHwFindAdapter;
|
2016-06-02 14:13:06 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// adapter specific information
|
|
|
|
|
hwInitializationData.TaggedQueuing = TRUE;
|
|
|
|
|
hwInitializationData.AutoRequestSense = TRUE;
|
|
|
|
|
hwInitializationData.MultipleRequestPerLu = TRUE;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
hwInitializationData.NeedPhysicalAddresses = TRUE;
|
2016-06-02 14:13:06 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
hwInitializationData.NumberOfAccessRanges = 6;
|
|
|
|
|
hwInitializationData.AdapterInterfaceType = PCIBus;
|
|
|
|
|
hwInitializationData.MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
|
2016-06-02 14:13:06 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// set required extension sizes
|
|
|
|
|
hwInitializationData.SrbExtensionSize = sizeof(AHCI_SRB_EXTENSION);
|
|
|
|
|
hwInitializationData.DeviceExtensionSize = sizeof(AHCI_ADAPTER_EXTENSION);
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
// register our hw init data
|
2016-06-15 17:07:26 +00:00
|
|
|
|
status = StorPortInitialize(DriverObject,
|
|
|
|
|
RegistryPath,
|
|
|
|
|
&hwInitializationData,
|
|
|
|
|
NULL);
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(status == STATUS_SUCCESS);
|
2016-06-02 14:13:06 +00:00
|
|
|
|
return status;
|
|
|
|
|
}// -- DriverEntry();
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
/**
|
2016-06-20 11:49:22 +00:00
|
|
|
|
* @name AhciATA_CFIS
|
2016-06-27 12:58:04 +00:00
|
|
|
|
* @implemented
|
2016-06-20 11:49:22 +00:00
|
|
|
|
*
|
|
|
|
|
* create ATA CFIS from Srb
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
2016-07-19 16:50:59 +00:00
|
|
|
|
* @return
|
|
|
|
|
* Number of CFIS fields used in DWORD
|
2016-06-20 11:49:22 +00:00
|
|
|
|
*/
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ULONG
|
2016-06-20 11:49:22 +00:00
|
|
|
|
AhciATA_CFIS (
|
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension,
|
|
|
|
|
__in PAHCI_SRB_EXTENSION SrbExtension
|
|
|
|
|
)
|
|
|
|
|
{
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PAHCI_COMMAND_TABLE cmdTable;
|
|
|
|
|
|
2016-07-04 20:20:25 +00:00
|
|
|
|
UNREFERENCED_PARAMETER(PortExtension);
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciATA_CFIS()\n");
|
2016-06-20 11:49:22 +00:00
|
|
|
|
|
2016-06-27 12:58:04 +00:00
|
|
|
|
cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciZeroMemory((PCHAR)cmdTable->CFIS, sizeof(cmdTable->CFIS));
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
cmdTable->CFIS[AHCI_ATA_CFIS_FisType] = FIS_TYPE_REG_H2D; // FIS Type
|
|
|
|
|
cmdTable->CFIS[AHCI_ATA_CFIS_PMPort_C] = (1 << 7); // PM Port & C
|
2016-06-27 12:58:04 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
return 5;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}// -- AhciATA_CFIS();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciATAPI_CFIS
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* @not_implemented
|
|
|
|
|
*
|
2016-06-20 11:49:22 +00:00
|
|
|
|
* create ATAPI CFIS from Srb
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
2016-07-19 16:50:59 +00:00
|
|
|
|
* @return
|
|
|
|
|
* Number of CFIS fields used in DWORD
|
2016-06-20 11:49:22 +00:00
|
|
|
|
*/
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ULONG
|
2016-06-20 11:49:22 +00:00
|
|
|
|
AhciATAPI_CFIS (
|
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension,
|
|
|
|
|
__in PAHCI_SRB_EXTENSION SrbExtension
|
|
|
|
|
)
|
|
|
|
|
{
|
2016-08-18 18:03:26 +00:00
|
|
|
|
PAHCI_COMMAND_TABLE cmdTable;
|
2016-07-04 20:20:25 +00:00
|
|
|
|
UNREFERENCED_PARAMETER(PortExtension);
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciATAPI_CFIS()\n");
|
2016-06-20 11:49:22 +00:00
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
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;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}// -- AhciATAPI_CFIS();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciBuild_PRDT
|
2016-06-22 16:08:45 +00:00
|
|
|
|
* @implemented
|
2016-06-20 11:49:22 +00:00
|
|
|
|
*
|
|
|
|
|
* Build PRDT for data transfer
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* Return number of entries in PRDT.
|
|
|
|
|
*/
|
|
|
|
|
ULONG
|
|
|
|
|
AhciBuild_PRDT (
|
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension,
|
|
|
|
|
__in PAHCI_SRB_EXTENSION SrbExtension
|
|
|
|
|
)
|
|
|
|
|
{
|
2016-06-22 16:08:45 +00:00
|
|
|
|
ULONG index;
|
|
|
|
|
PAHCI_COMMAND_TABLE cmdTable;
|
|
|
|
|
PLOCAL_SCATTER_GATHER_LIST sgl;
|
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciBuild_PRDT()\n");
|
2016-06-20 11:49:22 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
sgl = SrbExtension->pSgl;
|
2016-06-22 16:08:45 +00:00
|
|
|
|
cmdTable = (PAHCI_COMMAND_TABLE)SrbExtension;
|
|
|
|
|
AdapterExtension = PortExtension->AdapterExtension;
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(sgl != NULL);
|
|
|
|
|
NT_ASSERT(sgl->NumberOfElements < MAXIMUM_AHCI_PRDT_ENTRIES);
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < sgl->NumberOfElements; index++)
|
|
|
|
|
{
|
|
|
|
|
NT_ASSERT(sgl->List[index].Length <= MAXIMUM_TRANSFER_LENGTH);
|
|
|
|
|
|
|
|
|
|
cmdTable->PRDT[index].DBA = sgl->List[index].PhysicalAddress.LowPart;
|
|
|
|
|
if (IsAdapterCAPS64(AdapterExtension->CAP))
|
|
|
|
|
{
|
|
|
|
|
cmdTable->PRDT[index].DBAU = sgl->List[index].PhysicalAddress.HighPart;
|
|
|
|
|
}
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
|
|
|
|
// 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;
|
2016-06-22 16:08:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sgl->NumberOfElements;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}// -- AhciBuild_PRDT();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciProcessSrb
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* Prepare Srb for IO processing
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
* @param Srb
|
2016-06-20 11:49:22 +00:00
|
|
|
|
* @param SlotIndex
|
2016-06-16 17:02:55 +00:00
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
VOID
|
|
|
|
|
AhciProcessSrb (
|
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension,
|
2016-06-20 11:49:22 +00:00
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb,
|
|
|
|
|
__in ULONG SlotIndex
|
2016-06-16 17:02:55 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ULONG prdtlen, sig, length, cfl;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
PAHCI_SRB_EXTENSION SrbExtension;
|
|
|
|
|
PAHCI_COMMAND_HEADER CommandHeader;
|
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
STOR_PHYSICAL_ADDRESS CommandTablePhysicalAddress;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciProcessSrb()\n");
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
NT_ASSERT(Srb->PathId == PortExtension->PortNumber);
|
|
|
|
|
|
2016-06-22 16:08:45 +00:00
|
|
|
|
SrbExtension = GetSrbExtension(Srb);
|
2016-06-20 11:49:22 +00:00
|
|
|
|
AdapterExtension = PortExtension->AdapterExtension;
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(SrbExtension != NULL);
|
|
|
|
|
NT_ASSERT(SrbExtension->AtaFunction != 0);
|
|
|
|
|
|
|
|
|
|
if ((SrbExtension->AtaFunction == ATA_FUNCTION_ATA_IDENTIFY) &&
|
2016-06-22 16:08:45 +00:00
|
|
|
|
(SrbExtension->CommandReg == IDE_COMMAND_NOT_VALID))
|
2016-06-20 11:49:22 +00:00
|
|
|
|
{
|
|
|
|
|
// Here we are safe to check SIG register
|
|
|
|
|
sig = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->SIG);
|
|
|
|
|
if (sig == 0x101)
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tATA Device Found!\n");
|
2016-06-22 16:08:45 +00:00
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_IDENTIFY;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tATAPI Device Found!\n");
|
2016-06-22 16:08:45 +00:00
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_ATAPI_IDENTIFY;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(SlotIndex < AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
|
|
|
|
|
SrbExtension->SlotIndex = SlotIndex;
|
|
|
|
|
|
|
|
|
|
// program the CFIS in the CommandTable
|
|
|
|
|
CommandHeader = &PortExtension->CommandList[SlotIndex];
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
cfl = 0;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
if (IsAtapiCommand(SrbExtension->AtaFunction))
|
|
|
|
|
{
|
|
|
|
|
cfl = AhciATAPI_CFIS(PortExtension, SrbExtension);
|
|
|
|
|
}
|
|
|
|
|
else if (IsAtaCommand(SrbExtension->AtaFunction))
|
2016-06-20 11:49:22 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
cfl = AhciATA_CFIS(PortExtension, SrbExtension);
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
else
|
2016-06-20 11:49:22 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(FALSE);
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prdtlen = 0;
|
|
|
|
|
if (IsDataTransferNeeded(SrbExtension))
|
|
|
|
|
{
|
|
|
|
|
prdtlen = AhciBuild_PRDT(PortExtension, SrbExtension);
|
|
|
|
|
NT_ASSERT(prdtlen != -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Program the command header
|
|
|
|
|
CommandHeader->DI.PRDTL = prdtlen; // number of entries in PRD table
|
2016-07-19 16:50:59 +00:00
|
|
|
|
CommandHeader->DI.CFL = cfl;
|
|
|
|
|
CommandHeader->DI.A = (SrbExtension->AtaFunction & ATA_FUNCTION_ATAPI_COMMAND) ? 1 : 0;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
CommandHeader->DI.W = (SrbExtension->Flags & ATA_FLAGS_DATA_OUT) ? 1 : 0;
|
|
|
|
|
CommandHeader->DI.P = 0; // ATA Specifications says so
|
|
|
|
|
CommandHeader->DI.PMP = 0; // Port Multiplier
|
|
|
|
|
|
|
|
|
|
// Reset -- Manual Configuation
|
|
|
|
|
CommandHeader->DI.R = 0;
|
|
|
|
|
CommandHeader->DI.B = 0;
|
|
|
|
|
CommandHeader->DI.C = 0;
|
|
|
|
|
|
|
|
|
|
CommandHeader->PRDBC = 0;
|
|
|
|
|
|
|
|
|
|
CommandHeader->Reserved[0] = 0;
|
|
|
|
|
CommandHeader->Reserved[1] = 0;
|
|
|
|
|
CommandHeader->Reserved[2] = 0;
|
|
|
|
|
CommandHeader->Reserved[3] = 0;
|
|
|
|
|
|
|
|
|
|
// set CommandHeader CTBA
|
|
|
|
|
CommandTablePhysicalAddress = StorPortGetPhysicalAddress(AdapterExtension,
|
|
|
|
|
NULL,
|
|
|
|
|
SrbExtension,
|
|
|
|
|
&length);
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
NT_ASSERT(length != 0);
|
|
|
|
|
|
2016-06-20 11:49:22 +00:00
|
|
|
|
// command table alignment
|
|
|
|
|
NT_ASSERT((CommandTablePhysicalAddress.LowPart % 128) == 0);
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
CommandHeader->CTBA = CommandTablePhysicalAddress.LowPart;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
|
|
|
|
|
if (IsAdapterCAPS64(AdapterExtension->CAP))
|
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
CommandHeader->CTBA_U = CommandTablePhysicalAddress.HighPart;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mark this slot
|
2016-06-30 16:04:50 +00:00
|
|
|
|
PortExtension->Slot[SlotIndex] = Srb;
|
2016-07-04 19:01:07 +00:00
|
|
|
|
PortExtension->QueueSlots |= 1 << SlotIndex;
|
2016-06-16 17:02:55 +00:00
|
|
|
|
return;
|
|
|
|
|
}// -- AhciProcessSrb();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciActivatePort
|
2016-06-27 12:58:04 +00:00
|
|
|
|
* @implemented
|
2016-06-16 17:02:55 +00:00
|
|
|
|
*
|
|
|
|
|
* Program Port and populate command list
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
*
|
|
|
|
|
*/
|
2018-08-29 22:50:06 +00:00
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER // avoid MSVC C4700
|
|
|
|
|
#pragma warning(push)
|
|
|
|
|
#pragma warning(disable: 4700)
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
VOID
|
|
|
|
|
AhciActivatePort (
|
|
|
|
|
__in PAHCI_PORT_EXTENSION PortExtension
|
|
|
|
|
)
|
|
|
|
|
{
|
2016-07-04 19:01:07 +00:00
|
|
|
|
AHCI_PORT_CMD cmd;
|
|
|
|
|
ULONG QueueSlots, slotToActivate, tmp;
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciActivatePort()\n");
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
2016-06-27 12:58:04 +00:00
|
|
|
|
AdapterExtension = PortExtension->AdapterExtension;
|
|
|
|
|
QueueSlots = PortExtension->QueueSlots;
|
|
|
|
|
|
|
|
|
|
if (QueueSlots == 0)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
{
|
2016-06-27 12:58:04 +00:00
|
|
|
|
return;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
|
|
|
|
// section 3.3.14
|
|
|
|
|
// Bits in this field shall only be set to ‘1’ by software when PxCMD.ST is set to ‘1’
|
2016-07-04 19:01:07 +00:00
|
|
|
|
cmd.Status = StorPortReadRegisterUlong(AdapterExtension, &PortExtension->Port->CMD);
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
2016-07-04 19:01:07 +00:00
|
|
|
|
if (cmd.ST == 0) // PxCMD.ST == 0
|
2016-07-05 16:51:17 +00:00
|
|
|
|
{
|
2016-06-27 12:58:04 +00:00
|
|
|
|
return;
|
2016-07-05 16:51:17 +00:00
|
|
|
|
}
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
|
|
|
|
// get the lowest set bit
|
|
|
|
|
tmp = QueueSlots & (QueueSlots - 1);
|
|
|
|
|
|
|
|
|
|
if (tmp == 0)
|
|
|
|
|
slotToActivate = QueueSlots;
|
|
|
|
|
else
|
|
|
|
|
slotToActivate = (QueueSlots & (~tmp));
|
|
|
|
|
|
|
|
|
|
// mark that bit off in QueueSlots
|
2016-06-30 16:04:50 +00:00
|
|
|
|
// so we can know we it is really needed to activate port or not
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PortExtension->QueueSlots &= ~slotToActivate;
|
|
|
|
|
// mark this CommandIssuedSlots
|
2016-06-30 16:04:50 +00:00
|
|
|
|
// to validate in completeIssuedCommand
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PortExtension->CommandIssuedSlots |= slotToActivate;
|
|
|
|
|
|
|
|
|
|
// tell the HBA to issue this Command Slot to the given port
|
|
|
|
|
StorPortWriteRegisterUlong(AdapterExtension, &PortExtension->Port->CI, slotToActivate);
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
return;
|
|
|
|
|
}// -- AhciActivatePort();
|
|
|
|
|
|
2018-08-29 22:50:06 +00:00
|
|
|
|
#ifdef _MSC_VER // avoid MSVC C4700
|
|
|
|
|
#pragma warning(pop)
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciProcessIO
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Acquire Exclusive lock to port, populate pending commands to command List
|
|
|
|
|
* program controller's port to process new commands in command list.
|
|
|
|
|
*
|
|
|
|
|
* @param AdapterExtension
|
|
|
|
|
* @param PathId
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
VOID
|
|
|
|
|
AhciProcessIO (
|
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
|
|
|
|
__in UCHAR PathId,
|
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
PSCSI_REQUEST_BLOCK tmpSrb;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
STOR_LOCK_HANDLE lockhandle = {0};
|
2016-06-16 17:02:55 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
ULONG commandSlotMask, occupiedSlots, slotIndex, NCS;
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciProcessIO()\n");
|
|
|
|
|
AhciDebugPrint("\tPathId: %d\n", PathId);
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
PortExtension = &AdapterExtension->PortExtension[PathId];
|
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
NT_ASSERT(PathId < AdapterExtension->PortCount);
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
// Acquire Lock
|
|
|
|
|
StorPortAcquireSpinLock(AdapterExtension, InterruptLock, NULL, &lockhandle);
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
// add Srb to queue
|
|
|
|
|
AddQueue(&PortExtension->SrbQueue, Srb);
|
|
|
|
|
|
|
|
|
|
if (PortExtension->DeviceParams.IsActive == FALSE)
|
|
|
|
|
{
|
|
|
|
|
// Release Lock
|
|
|
|
|
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
|
|
|
|
|
return; // we should wait for device to get active
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-27 12:58:04 +00:00
|
|
|
|
occupiedSlots = (PortExtension->QueueSlots | PortExtension->CommandIssuedSlots); // Busy command slots for given port
|
2016-06-20 11:49:22 +00:00
|
|
|
|
NCS = AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP);
|
|
|
|
|
commandSlotMask = (1 << NCS) - 1; // available slots mask
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
commandSlotMask = (commandSlotMask & ~occupiedSlots);
|
|
|
|
|
if(commandSlotMask != 0)
|
|
|
|
|
{
|
|
|
|
|
// iterate over HBA port slots
|
2016-06-20 11:49:22 +00:00
|
|
|
|
for (slotIndex = 0; slotIndex < NCS; slotIndex++)
|
2016-06-16 17:02:55 +00:00
|
|
|
|
{
|
|
|
|
|
// find first free slot
|
|
|
|
|
if ((commandSlotMask & (1 << slotIndex)) != 0)
|
|
|
|
|
{
|
|
|
|
|
tmpSrb = RemoveQueue(&PortExtension->SrbQueue);
|
|
|
|
|
if (tmpSrb != NULL)
|
|
|
|
|
{
|
2016-06-22 16:08:45 +00:00
|
|
|
|
NT_ASSERT(tmpSrb->PathId == PathId);
|
2016-06-20 11:49:22 +00:00
|
|
|
|
AhciProcessSrb(PortExtension, tmpSrb, slotIndex);
|
2016-06-16 17:02:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// program HBA port
|
|
|
|
|
AhciActivatePort(PortExtension);
|
|
|
|
|
|
|
|
|
|
// Release Lock
|
|
|
|
|
StorPortReleaseSpinLock(AdapterExtension, &lockhandle);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}// -- AhciProcessIO();
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* @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 (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID _Extension,
|
|
|
|
|
__in PVOID _Srb
|
2016-08-18 18:03:26 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-08-18 18:03:26 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PSCSI_REQUEST_BLOCK Srb;
|
|
|
|
|
BOOLEAN status;
|
2016-08-18 18:03:26 +00:00
|
|
|
|
|
|
|
|
|
AhciDebugPrint("AtapiInquiryCompletion()\n");
|
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
|
|
|
|
|
Srb = (PSCSI_REQUEST_BLOCK)_Srb;
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
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();
|
|
|
|
|
|
2016-06-30 16:04:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name InquiryCompletion
|
2016-08-18 18:03:26 +00:00
|
|
|
|
* @implemented
|
2016-06-30 16:04:50 +00:00
|
|
|
|
*
|
|
|
|
|
* InquiryCompletion routine should be called after device signals
|
|
|
|
|
* for device inquiry request is completed (through interrupt)
|
|
|
|
|
*
|
|
|
|
|
* @param PortExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
VOID
|
|
|
|
|
InquiryCompletion (
|
2017-10-13 19:52:38 +00:00
|
|
|
|
__in PVOID _Extension,
|
|
|
|
|
__in PVOID _Srb
|
2016-06-30 16:04:50 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
|
|
|
|
PSCSI_REQUEST_BLOCK Srb;
|
|
|
|
|
|
|
|
|
|
// PCDB cdb;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
BOOLEAN status;
|
|
|
|
|
PINQUIRYDATA InquiryData;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
PAHCI_SRB_EXTENSION SrbExtension;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PAHCI_ADAPTER_EXTENSION AdapterExtension;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("InquiryCompletion()\n");
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
PortExtension = (PAHCI_PORT_EXTENSION)_Extension;
|
|
|
|
|
Srb = (PSCSI_REQUEST_BLOCK)_Srb;
|
|
|
|
|
|
2016-06-30 16:04:50 +00:00
|
|
|
|
NT_ASSERT(Srb != NULL);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(PortExtension != NULL);
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
2017-10-13 19:52:38 +00:00
|
|
|
|
// cdb = (PCDB)&Srb->Cdb;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
InquiryData = Srb->DataBuffer;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
SrbExtension = GetSrbExtension(Srb);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AdapterExtension = PortExtension->AdapterExtension;
|
|
|
|
|
IdentifyDeviceData = PortExtension->IdentifyDeviceData;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
|
2016-06-30 16:04:50 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
if (Srb->SrbStatus == SRB_STATUS_NO_DEVICE)
|
2016-06-30 16:04:50 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_NODEVICE;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(InquiryData != NULL);
|
|
|
|
|
NT_ASSERT(Srb->SrbStatus == SRB_STATUS_SUCCESS);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
// Device specific data
|
|
|
|
|
PortExtension->DeviceParams.MaxLba.QuadPart = 0;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
if (SrbExtension->CommandReg == IDE_COMMAND_IDENTIFY)
|
|
|
|
|
{
|
|
|
|
|
PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATA;
|
|
|
|
|
if (IdentifyDeviceData->GeneralConfiguration.RemovableMedia)
|
2016-06-30 16:04:50 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PortExtension->DeviceParams.RemovableDevice = 1;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-25 11:09:25 +00:00
|
|
|
|
if ((IdentifyDeviceData->CommandSetSupport.BigLba) && (IdentifyDeviceData->CommandSetActive.BigLba))
|
2016-07-23 22:53:15 +00:00
|
|
|
|
{
|
|
|
|
|
PortExtension->DeviceParams.Lba48BitMode = 1;
|
|
|
|
|
}
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PortExtension->DeviceParams.AccessType = DIRECT_ACCESS_DEVICE;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
/* Device max address lba */
|
|
|
|
|
if (PortExtension->DeviceParams.Lba48BitMode)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->Max48BitLBA[0];
|
|
|
|
|
PortExtension->DeviceParams.MaxLba.HighPart = IdentifyDeviceData->Max48BitLBA[1];
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PortExtension->DeviceParams.MaxLba.LowPart = IdentifyDeviceData->UserAddressableSectors;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
/* Bytes Per Logical Sector */
|
|
|
|
|
if (IdentifyDeviceData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tBytesPerLogicalSector != DEVICE_ATA_BLOCK_SIZE\n");
|
|
|
|
|
NT_ASSERT(FALSE);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
PortExtension->DeviceParams.BytesPerLogicalSector = DEVICE_ATA_BLOCK_SIZE;
|
|
|
|
|
|
|
|
|
|
/* Bytes Per Physical Sector */
|
|
|
|
|
if (IdentifyDeviceData->PhysicalLogicalSectorSize.MultipleLogicalSectorsPerPhysicalSector)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tBytesPerPhysicalSector != DEVICE_ATA_BLOCK_SIZE\n");
|
|
|
|
|
NT_ASSERT(FALSE);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
PortExtension->DeviceParams.BytesPerPhysicalSector = DEVICE_ATA_BLOCK_SIZE;
|
|
|
|
|
|
2016-08-14 12:54:10 +00:00
|
|
|
|
// 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';
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
// TODO: Add other device params
|
|
|
|
|
AhciDebugPrint("\tATA Device\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AhciDebugPrint("\tATAPI Device\n");
|
|
|
|
|
PortExtension->DeviceParams.DeviceType = AHCI_DEVICE_TYPE_ATAPI;
|
|
|
|
|
PortExtension->DeviceParams.AccessType = READ_ONLY_DIRECT_ACCESS_DEVICE;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
// INQUIRYDATABUFFERSIZE = 36 ; Defined in storport.h
|
|
|
|
|
if (Srb->DataTransferLength < INQUIRYDATABUFFERSIZE)
|
|
|
|
|
{
|
|
|
|
|
AhciDebugPrint("\tDataBufferLength < sizeof(INQUIRYDATA), Could crash the driver.\n");
|
2016-08-14 12:54:10 +00:00
|
|
|
|
NT_ASSERT(FALSE);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
2016-08-14 12:54:10 +00:00
|
|
|
|
// 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';
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
// send queue depth
|
|
|
|
|
status = StorPortSetDeviceQueueDepth(PortExtension->AdapterExtension,
|
|
|
|
|
Srb->PathId,
|
|
|
|
|
Srb->TargetId,
|
|
|
|
|
Srb->Lun,
|
|
|
|
|
AHCI_Global_Port_CAP_NCS(AdapterExtension->CAP));
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(status == TRUE);
|
2016-06-30 16:04:50 +00:00
|
|
|
|
return;
|
|
|
|
|
}// -- InquiryCompletion();
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* @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();
|
|
|
|
|
|
2016-07-25 19:50:09 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name DeviceRequestSense
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Handle SCSIOP_MODE_SENSE OperationCode
|
|
|
|
|
*
|
|
|
|
|
* @param AdapterExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
* @param Cdb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return STOR status for DeviceRequestSense
|
|
|
|
|
*/
|
2016-08-18 18:03:26 +00:00
|
|
|
|
UCHAR
|
|
|
|
|
DeviceRequestSense (
|
2016-07-25 19:50:09 +00:00
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb,
|
|
|
|
|
__in PCDB Cdb
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
PMODE_PARAMETER_HEADER ModeHeader;
|
2016-08-18 18:03:26 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-07-25 19:50:09 +00:00
|
|
|
|
|
|
|
|
|
AhciDebugPrint("DeviceRequestSense()\n");
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
|
|
|
|
|
NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_MODE_SENSE);
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
|
|
|
|
|
|
|
|
|
|
if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
|
|
|
|
|
{
|
|
|
|
|
return AhciATAPICommand(AdapterExtension, Srb, Cdb);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-25 19:50:09 +00:00
|
|
|
|
ModeHeader = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(ModeHeader != NULL);
|
|
|
|
|
|
|
|
|
|
AhciZeroMemory((PCHAR)ModeHeader, Srb->DataTransferLength);
|
|
|
|
|
|
|
|
|
|
ModeHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER);
|
|
|
|
|
ModeHeader->MediumType = 0;
|
2016-07-26 14:15:15 +00:00
|
|
|
|
ModeHeader->DeviceSpecificParameter = 0;
|
2016-07-25 19:50:09 +00:00
|
|
|
|
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();
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name DeviceRequestReadWrite
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Handle SCSIOP_READ SCSIOP_WRITE OperationCode
|
|
|
|
|
*
|
|
|
|
|
* @param AdapterExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
* @param Cdb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
2016-08-18 18:03:26 +00:00
|
|
|
|
* return STOR status for DeviceRequestReadWrite
|
2016-07-23 22:53:15 +00:00
|
|
|
|
*/
|
2016-08-18 18:03:26 +00:00
|
|
|
|
UCHAR
|
|
|
|
|
DeviceRequestReadWrite (
|
2016-07-23 22:53:15 +00:00
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb,
|
|
|
|
|
__in PCDB Cdb
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
BOOLEAN IsReading;
|
2016-07-25 11:09:25 +00:00
|
|
|
|
ULONG64 StartOffset;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
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];
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
|
|
|
|
|
{
|
|
|
|
|
return AhciATAPICommand(AdapterExtension, Srb, Cdb);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
DataTransferLength = Srb->DataTransferLength;
|
|
|
|
|
BytesPerSector = PortExtension->DeviceParams.BytesPerLogicalSector;
|
|
|
|
|
|
2016-07-24 12:41:07 +00:00
|
|
|
|
NT_ASSERT(BytesPerSector > 0);
|
|
|
|
|
|
2016-07-26 14:15:15 +00:00
|
|
|
|
//ROUND_UP(DataTransferLength, BytesPerSector);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
SectorCount = DataTransferLength / BytesPerSector;
|
2016-07-26 14:15:15 +00:00
|
|
|
|
|
|
|
|
|
Srb->DataTransferLength = SectorCount * BytesPerSector;
|
|
|
|
|
|
2016-07-25 11:09:25 +00:00
|
|
|
|
StartOffset = AhciGetLba(Cdb, Srb->CdbLength);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
IsReading = (Cdb->CDB10.OperationCode == SCSIOP_READ);
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(SectorCount > 0);
|
|
|
|
|
|
|
|
|
|
SrbExtension->AtaFunction = ATA_FUNCTION_ATA_READ;
|
2016-07-24 12:41:07 +00:00
|
|
|
|
SrbExtension->Flags |= ATA_FLAGS_USE_DMA;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
SrbExtension->CompletionRoutine = NULL;
|
|
|
|
|
|
|
|
|
|
if (IsReading)
|
|
|
|
|
{
|
|
|
|
|
SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
|
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_READ_DMA;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SrbExtension->Flags |= ATA_FLAGS_DATA_OUT;
|
2016-07-26 14:15:15 +00:00
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SrbExtension->FeaturesLow = 0;
|
2016-07-25 11:09:25 +00:00
|
|
|
|
SrbExtension->LBA0 = (StartOffset >> 0) & 0xFF;
|
|
|
|
|
SrbExtension->LBA1 = (StartOffset >> 8) & 0xFF;
|
|
|
|
|
SrbExtension->LBA2 = (StartOffset >> 16) & 0xFF;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
SrbExtension->Device = (0xA0 | IDE_LBA_MODE);
|
|
|
|
|
|
|
|
|
|
if (PortExtension->DeviceParams.Lba48BitMode)
|
|
|
|
|
{
|
|
|
|
|
SrbExtension->Flags |= ATA_FLAGS_48BIT_COMMAND;
|
2016-07-26 15:38:14 +00:00
|
|
|
|
|
|
|
|
|
if (IsReading)
|
|
|
|
|
{
|
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_READ_DMA_EXT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_WRITE_DMA_EXT;
|
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
2016-07-25 11:09:25 +00:00
|
|
|
|
SrbExtension->LBA3 = (StartOffset >> 24) & 0xFF;
|
|
|
|
|
SrbExtension->LBA4 = (StartOffset >> 32) & 0xFF;
|
|
|
|
|
SrbExtension->LBA5 = (StartOffset >> 40) & 0xFF;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
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
|
2016-08-18 18:03:26 +00:00
|
|
|
|
* return STOR status for DeviceRequestCapacity
|
2016-07-23 22:53:15 +00:00
|
|
|
|
*/
|
2016-08-18 18:03:26 +00:00
|
|
|
|
UCHAR
|
|
|
|
|
DeviceRequestCapacity (
|
2016-07-23 22:53:15 +00:00
|
|
|
|
__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));
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
|
|
|
|
|
{
|
|
|
|
|
return AhciATAPICommand(AdapterExtension, Srb, Cdb);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
if (Cdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY)
|
|
|
|
|
{
|
|
|
|
|
ReadCapacity = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
|
|
|
|
|
|
|
|
|
|
BytesPerLogicalSector = PortExtension->DeviceParams.BytesPerLogicalSector;
|
2016-07-25 19:50:09 +00:00
|
|
|
|
MaxLba = (ULONG)PortExtension->DeviceParams.MaxLba.QuadPart - 1;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
|
2016-07-25 11:09:25 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name DeviceRequestComplete
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Handle UnHandled Requests
|
|
|
|
|
*
|
|
|
|
|
* @param AdapterExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
* @param Cdb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return STOR status for DeviceRequestComplete
|
|
|
|
|
*/
|
2016-08-18 18:03:26 +00:00
|
|
|
|
UCHAR
|
|
|
|
|
DeviceRequestComplete (
|
2016-07-25 11:09:25 +00:00
|
|
|
|
__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();
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name DeviceReportLuns
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Handle SCSIOP_REPORT_LUNS OperationCode
|
|
|
|
|
*
|
|
|
|
|
* @param AdapterExtension
|
|
|
|
|
* @param Srb
|
|
|
|
|
* @param Cdb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return STOR status for DeviceReportLuns
|
|
|
|
|
*/
|
2016-08-18 18:03:26 +00:00
|
|
|
|
UCHAR
|
|
|
|
|
DeviceReportLuns (
|
2016-07-23 22:53:15 +00:00
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb,
|
|
|
|
|
__in PCDB Cdb
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
PLUN_LIST LunList;
|
2016-08-18 18:03:26 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
AhciDebugPrint("DeviceReportLuns()\n");
|
|
|
|
|
|
|
|
|
|
UNREFERENCED_PARAMETER(Cdb);
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(Srb->DataTransferLength >= sizeof(LUN_LIST));
|
|
|
|
|
NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_REPORT_LUNS);
|
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
|
|
|
|
|
{
|
|
|
|
|
return AhciATAPICommand(AdapterExtension, Srb, Cdb);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
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();
|
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
/**
|
|
|
|
|
* @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
|
|
|
|
|
*/
|
2016-07-04 20:20:25 +00:00
|
|
|
|
UCHAR
|
2016-06-16 17:02:55 +00:00
|
|
|
|
DeviceInquiryRequest (
|
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb,
|
2016-07-23 22:53:15 +00:00
|
|
|
|
__in PCDB Cdb
|
2016-06-16 17:02:55 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
PVOID DataBuffer;
|
2016-06-20 11:49:22 +00:00
|
|
|
|
PAHCI_SRB_EXTENSION SrbExtension;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
PAHCI_PORT_EXTENSION PortExtension;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
PVPD_SUPPORTED_PAGES_PAGE VpdOutputBuffer;
|
|
|
|
|
ULONG DataBufferLength, RequiredDataBufferLength;
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("DeviceInquiryRequest()\n");
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
NT_ASSERT(Cdb->CDB10.OperationCode == SCSIOP_INQUIRY);
|
2016-06-27 12:58:04 +00:00
|
|
|
|
NT_ASSERT(IsPortValid(AdapterExtension, Srb->PathId));
|
|
|
|
|
|
2016-06-22 16:08:45 +00:00
|
|
|
|
SrbExtension = GetSrbExtension(Srb);
|
2016-06-27 12:58:04 +00:00
|
|
|
|
PortExtension = &AdapterExtension->PortExtension[Srb->PathId];
|
2016-06-20 11:49:22 +00:00
|
|
|
|
|
2016-08-18 18:03:26 +00:00
|
|
|
|
if (PortExtension->DeviceParams.DeviceType == AHCI_DEVICE_TYPE_ATAPI)
|
|
|
|
|
{
|
|
|
|
|
return AhciATAPICommand(AdapterExtension, Srb, Cdb);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
if (Srb->Lun != 0)
|
2016-06-16 17:02:55 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
return SRB_STATUS_SELECTION_TIMEOUT;
|
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
else if (Cdb->CDB6INQUIRY3.EnableVitalProductData == 0)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
{
|
|
|
|
|
// 3.6.1
|
|
|
|
|
// If the EVPD bit is set to zero, the device server shall return the standard INQUIRY data
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tEVPD Inquired\n");
|
2016-06-20 11:49:22 +00:00
|
|
|
|
NT_ASSERT(SrbExtension != NULL);
|
|
|
|
|
|
|
|
|
|
SrbExtension->AtaFunction = ATA_FUNCTION_ATA_IDENTIFY;
|
2016-06-27 12:58:04 +00:00
|
|
|
|
SrbExtension->Flags |= ATA_FLAGS_DATA_IN;
|
2016-06-30 16:04:50 +00:00
|
|
|
|
SrbExtension->CompletionRoutine = InquiryCompletion;
|
2016-06-22 16:08:45 +00:00
|
|
|
|
SrbExtension->CommandReg = IDE_COMMAND_NOT_VALID;
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
2016-06-30 16:04:50 +00:00
|
|
|
|
// TODO: Should use AhciZeroMemory
|
2016-06-27 12:58:04 +00:00
|
|
|
|
SrbExtension->FeaturesLow = 0;
|
|
|
|
|
SrbExtension->LBA0 = 0;
|
|
|
|
|
SrbExtension->LBA1 = 0;
|
|
|
|
|
SrbExtension->LBA2 = 0;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
SrbExtension->Device = 0xA0;
|
2016-06-27 12:58:04 +00:00
|
|
|
|
SrbExtension->LBA3 = 0;
|
|
|
|
|
SrbExtension->LBA4 = 0;
|
|
|
|
|
SrbExtension->LBA5 = 0;
|
|
|
|
|
SrbExtension->FeaturesHigh = 0;
|
|
|
|
|
SrbExtension->SectorCountLow = 0;
|
|
|
|
|
SrbExtension->SectorCountHigh = 0;
|
|
|
|
|
|
|
|
|
|
SrbExtension->Sgl.NumberOfElements = 1;
|
|
|
|
|
SrbExtension->Sgl.List[0].PhysicalAddress.LowPart = PortExtension->IdentifyDeviceDataPhysicalAddress.LowPart;
|
|
|
|
|
SrbExtension->Sgl.List[0].PhysicalAddress.HighPart = PortExtension->IdentifyDeviceDataPhysicalAddress.HighPart;
|
|
|
|
|
SrbExtension->Sgl.List[0].Length = sizeof(IDENTIFY_DEVICE_DATA);
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
SrbExtension->pSgl = &SrbExtension->Sgl;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
return SRB_STATUS_PENDING;
|
2016-06-16 17:02:55 +00:00
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
else
|
2016-06-16 17:02:55 +00:00
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tVPD Inquired\n");
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
DataBuffer = Srb->DataBuffer;
|
|
|
|
|
DataBufferLength = Srb->DataTransferLength;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
RequiredDataBufferLength = DataBufferLength; // make the compiler happy :p
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
if (DataBuffer == NULL)
|
|
|
|
|
{
|
|
|
|
|
return SRB_STATUS_INVALID_REQUEST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AhciZeroMemory(DataBuffer, DataBufferLength);
|
2016-06-27 12:58:04 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
switch(Cdb->CDB6INQUIRY3.PageCode)
|
|
|
|
|
{
|
|
|
|
|
case VPD_SUPPORTED_PAGES:
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
VpdOutputBuffer = (PVPD_SUPPORTED_PAGES_PAGE)DataBuffer;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
VpdOutputBuffer->DeviceType = PortExtension->DeviceParams.AccessType;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
VpdOutputBuffer->DeviceTypeQualifier = 0;
|
|
|
|
|
VpdOutputBuffer->PageCode = VPD_SUPPORTED_PAGES;
|
|
|
|
|
VpdOutputBuffer->PageLength = 1;
|
|
|
|
|
VpdOutputBuffer->SupportedPageList[0] = VPD_SUPPORTED_PAGES;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
//VpdOutputBuffer->SupportedPageList[1] = VPD_SERIAL_NUMBER;
|
|
|
|
|
//VpdOutputBuffer->SupportedPageList[2] = VPD_DEVICE_IDENTIFIERS;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
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");
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2016-07-23 22:53:15 +00:00
|
|
|
|
default:
|
|
|
|
|
AhciDebugPrint("\tPageCode: %x\n", Cdb->CDB6INQUIRY3.PageCode);
|
|
|
|
|
return SRB_STATUS_INVALID_REQUEST;
|
2016-07-19 16:50:59 +00:00
|
|
|
|
}
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
Srb->DataTransferLength = RequiredDataBufferLength;
|
|
|
|
|
return SRB_STATUS_SUCCESS;
|
|
|
|
|
}
|
2016-06-16 17:02:55 +00:00
|
|
|
|
}// -- DeviceInquiryRequest();
|
|
|
|
|
|
2016-06-02 14:43:56 +00:00
|
|
|
|
/**
|
|
|
|
|
* @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
|
2016-06-07 11:05:32 +00:00
|
|
|
|
* a hung or locked state.
|
2016-06-02 14:43:56 +00:00
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* @param AdapterExtension
|
2016-06-02 14:43:56 +00:00
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* TRUE in case AHCI Controller RESTARTED successfully. i.e GHC.HR == 0
|
|
|
|
|
*/
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
|
|
|
|
AhciAdapterReset (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-02 14:13:06 +00:00
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ULONG ticks;
|
|
|
|
|
AHCI_GHC ghc;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
PAHCI_MEMORY_REGISTERS abar = NULL;
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("AhciAdapterReset()\n");
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-10 08:27:20 +00:00
|
|
|
|
abar = AdapterExtension->ABAR_Address;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
if (abar == NULL) // basic sanity
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return FALSE;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-04 12:52:38 +00:00
|
|
|
|
// HR -- Very first bit (lowest significant)
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ghc.HR = 1;
|
|
|
|
|
StorPortWriteRegisterUlong(AdapterExtension, &abar->GHC, ghc.Status);
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
for (ticks = 0; ticks < 50; ++ticks)
|
|
|
|
|
{
|
2016-07-19 16:50:59 +00:00
|
|
|
|
ghc.Status = StorPortReadRegisterUlong(AdapterExtension, &abar->GHC);
|
|
|
|
|
if (ghc.HR == 0)
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
StorPortStallExecution(20000);
|
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-09 23:47:19 +00:00
|
|
|
|
if (ticks == 50)// 1 second
|
|
|
|
|
{
|
2016-07-23 22:53:15 +00:00
|
|
|
|
AhciDebugPrint("\tDevice Timeout\n");
|
2016-06-02 14:43:56 +00:00
|
|
|
|
return FALSE;
|
2016-06-04 12:52:38 +00:00
|
|
|
|
}
|
2016-06-02 14:43:56 +00:00
|
|
|
|
|
2016-06-04 12:52:38 +00:00
|
|
|
|
return TRUE;
|
2016-06-02 14:13:06 +00:00
|
|
|
|
}// -- AhciAdapterReset();
|
2016-06-03 15:54:21 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name AhciZeroMemory
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Clear buffer by filling zeros
|
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* @param Buffer
|
|
|
|
|
* @param BufferSize
|
2016-06-03 15:54:21 +00:00
|
|
|
|
*/
|
2016-06-07 11:05:32 +00:00
|
|
|
|
__inline
|
2016-06-09 23:47:19 +00:00
|
|
|
|
VOID
|
|
|
|
|
AhciZeroMemory (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__out PCHAR Buffer,
|
|
|
|
|
__in ULONG BufferSize
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-03 15:54:21 +00:00
|
|
|
|
{
|
|
|
|
|
ULONG i;
|
2016-06-10 08:27:20 +00:00
|
|
|
|
for (i = 0; i < BufferSize; i++)
|
|
|
|
|
{
|
|
|
|
|
Buffer[i] = 0;
|
|
|
|
|
}
|
2016-06-16 17:02:55 +00:00
|
|
|
|
|
|
|
|
|
return;
|
2016-06-03 15:54:21 +00:00
|
|
|
|
}// -- AhciZeroMemory();
|
2016-06-07 11:05:32 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name IsPortValid
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Tells wheather given port is implemented or not
|
|
|
|
|
*
|
2016-06-10 08:27:20 +00:00
|
|
|
|
* @param AdapterExtension
|
2016-06-07 11:05:32 +00:00
|
|
|
|
* @param PathId
|
|
|
|
|
*
|
|
|
|
|
* @return
|
2016-06-07 18:06:51 +00:00
|
|
|
|
* return TRUE if provided port is valid (implemented) or not
|
2016-06-07 11:05:32 +00:00
|
|
|
|
*/
|
|
|
|
|
__inline
|
2016-06-09 23:47:19 +00:00
|
|
|
|
BOOLEAN
|
|
|
|
|
IsPortValid (
|
2016-06-10 08:27:20 +00:00
|
|
|
|
__in PAHCI_ADAPTER_EXTENSION AdapterExtension,
|
2016-07-04 20:20:25 +00:00
|
|
|
|
__in ULONG pathId
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-07 11:05:32 +00:00
|
|
|
|
{
|
2016-07-04 20:20:25 +00:00
|
|
|
|
NT_ASSERT(pathId < MAXIMUM_AHCI_PORT_COUNT);
|
2016-06-09 23:47:19 +00:00
|
|
|
|
|
2016-06-16 21:14:03 +00:00
|
|
|
|
if (pathId >= AdapterExtension->PortCount)
|
2016-06-09 23:47:19 +00:00
|
|
|
|
{
|
2016-06-07 11:05:32 +00:00
|
|
|
|
return FALSE;
|
2016-06-09 23:47:19 +00:00
|
|
|
|
}
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-07-19 16:50:59 +00:00
|
|
|
|
return AdapterExtension->PortExtension[pathId].DeviceParams.IsActive;
|
2016-06-07 11:05:32 +00:00
|
|
|
|
}// -- IsPortValid()
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-15 17:07:26 +00:00
|
|
|
|
/**
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* @name AddQueue
|
|
|
|
|
* @implemented
|
2016-06-15 17:07:26 +00:00
|
|
|
|
*
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* Add Srb to Queue
|
2016-06-15 17:07:26 +00:00
|
|
|
|
*
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* @param Queue
|
2016-06-15 17:07:26 +00:00
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* @return
|
|
|
|
|
* return TRUE if Srb is successfully added to Queue
|
|
|
|
|
*
|
2016-06-15 17:07:26 +00:00
|
|
|
|
*/
|
2016-06-16 17:02:55 +00:00
|
|
|
|
__inline
|
|
|
|
|
BOOLEAN
|
|
|
|
|
AddQueue (
|
|
|
|
|
__inout PAHCI_QUEUE Queue,
|
|
|
|
|
__in PVOID Srb
|
2016-06-15 17:07:26 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
2016-06-16 17:02:55 +00:00
|
|
|
|
NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
|
|
|
|
|
NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
|
2016-06-15 17:07:26 +00:00
|
|
|
|
|
2016-06-22 16:08:45 +00:00
|
|
|
|
if (Queue->Tail == ((Queue->Head + 1) % MAXIMUM_QUEUE_BUFFER_SIZE))
|
2016-06-16 17:02:55 +00:00
|
|
|
|
return FALSE;
|
2016-06-15 17:07:26 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
Queue->Buffer[Queue->Head++] = Srb;
|
|
|
|
|
Queue->Head %= MAXIMUM_QUEUE_BUFFER_SIZE;
|
2016-06-15 17:07:26 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
return TRUE;
|
|
|
|
|
}// -- AddQueue();
|
2016-06-15 17:07:26 +00:00
|
|
|
|
|
2016-06-07 18:06:51 +00:00
|
|
|
|
/**
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* @name RemoveQueue
|
2016-06-07 18:06:51 +00:00
|
|
|
|
* @implemented
|
|
|
|
|
*
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* Remove and return Srb from Queue
|
2016-06-07 18:06:51 +00:00
|
|
|
|
*
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* @param Queue
|
2016-06-07 18:06:51 +00:00
|
|
|
|
*
|
|
|
|
|
* @return
|
2016-06-16 17:02:55 +00:00
|
|
|
|
* return Srb
|
2016-06-07 18:06:51 +00:00
|
|
|
|
*
|
|
|
|
|
*/
|
2016-06-16 17:02:55 +00:00
|
|
|
|
__inline
|
|
|
|
|
PVOID
|
|
|
|
|
RemoveQueue (
|
|
|
|
|
__inout PAHCI_QUEUE Queue
|
2016-06-09 23:47:19 +00:00
|
|
|
|
)
|
2016-06-07 18:06:51 +00:00
|
|
|
|
{
|
2016-06-16 17:02:55 +00:00
|
|
|
|
PVOID Srb;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
NT_ASSERT(Queue->Head < MAXIMUM_QUEUE_BUFFER_SIZE);
|
|
|
|
|
NT_ASSERT(Queue->Tail < MAXIMUM_QUEUE_BUFFER_SIZE);
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
if (Queue->Head == Queue->Tail)
|
|
|
|
|
return NULL;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
Srb = Queue->Buffer[Queue->Tail++];
|
|
|
|
|
Queue->Tail %= MAXIMUM_QUEUE_BUFFER_SIZE;
|
2016-06-07 18:06:51 +00:00
|
|
|
|
|
2016-06-16 17:02:55 +00:00
|
|
|
|
return Srb;
|
|
|
|
|
}// -- RemoveQueue();
|
2016-06-22 16:08:45 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @name GetSrbExtension
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* GetSrbExtension from Srb make sure It is properly aligned
|
|
|
|
|
*
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return SrbExtension
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
__inline
|
|
|
|
|
PAHCI_SRB_EXTENSION
|
|
|
|
|
GetSrbExtension (
|
|
|
|
|
__in PSCSI_REQUEST_BLOCK Srb
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
ULONG Offset;
|
|
|
|
|
ULONG_PTR SrbExtension;
|
|
|
|
|
|
2016-07-04 20:20:25 +00:00
|
|
|
|
SrbExtension = (ULONG_PTR)Srb->SrbExtension;
|
2016-06-22 16:08:45 +00:00
|
|
|
|
Offset = SrbExtension % 128;
|
|
|
|
|
|
|
|
|
|
// CommandTable should be 128 byte aligned
|
|
|
|
|
if (Offset != 0)
|
|
|
|
|
Offset = 128 - Offset;
|
|
|
|
|
|
|
|
|
|
return (PAHCI_SRB_EXTENSION)(SrbExtension + Offset);
|
|
|
|
|
}// -- PAHCI_SRB_EXTENSION();
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
2016-07-25 11:09:25 +00:00
|
|
|
|
/**
|
|
|
|
|
* @name AhciGetLba
|
|
|
|
|
* @implemented
|
|
|
|
|
*
|
|
|
|
|
* Find the logical address of demand block from Cdb
|
|
|
|
|
*
|
|
|
|
|
* @param Srb
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* return Logical Address of the block
|
|
|
|
|
*
|
|
|
|
|
*/
|
2016-07-23 22:53:15 +00:00
|
|
|
|
__inline
|
|
|
|
|
ULONG64
|
|
|
|
|
AhciGetLba (
|
2016-07-25 11:09:25 +00:00
|
|
|
|
__in PCDB Cdb,
|
|
|
|
|
__in ULONG CdbLength
|
2016-07-23 22:53:15 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
ULONG64 lba = 0;
|
|
|
|
|
|
|
|
|
|
NT_ASSERT(Cdb != NULL);
|
2016-07-25 11:09:25 +00:00
|
|
|
|
NT_ASSERT(CdbLength != 0);
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
2016-07-25 11:09:25 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2016-07-23 22:53:15 +00:00
|
|
|
|
|
|
|
|
|
return lba;
|
|
|
|
|
}// -- AhciGetLba();
|