2647 lines
89 KiB
C
2647 lines
89 KiB
C
/** @file
|
|
Delay UEFI RAID OpROM Driver
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2013 - 2021, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "DelayUefiRaidOprom.h"
|
|
|
|
EFI_HANDLE gDelayUefiRaidOpromDriverImageHandle;
|
|
EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *gDelayUefiRaidOpromPlatformDriverOverride;
|
|
|
|
EFI_EVENT mDelayUefiRaidOpromEvent;
|
|
EFI_EVENT mDelayUefiRaidOpromScsiEvent;
|
|
EFI_EVENT mDelayUefiRaidOpromNvmeEvent;
|
|
EFI_EVENT mDelayUefiRaidOpromScsiIoEvent;
|
|
|
|
DELAY_UEFI_RAID_OPROM_PRIVATE *mDelayUefiRaidOpromPrivate;
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gDelayUefiRaidOpromDriverBinding = {
|
|
DelayUefiRaidOpromDriverBindingSupported,
|
|
DelayUefiRaidOpromDriverBindingStart,
|
|
DelayUefiRaidOpromDriverBindingStop,
|
|
0x10,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
/**
|
|
Try to identify if the controller is a Intel RAID controller
|
|
|
|
@param ControllerHandle Handle to identify
|
|
|
|
@retval TRUE this is an Intel RAID controller
|
|
@retval FALSE this is not an Intel RAID controller
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsIntelRaidController (
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ATA_PASS_THRU_PROTOCOL *AtaDevice;
|
|
EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmeDevice;
|
|
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThruDevice;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
&gEfiAtaPassThruProtocolGuid,
|
|
(VOID **)&AtaDevice
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
&gEfiNvmExpressPassThruProtocolGuid,
|
|
(VOID **)&NvmeDevice
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
(VOID **)&ExtScsiPassThruDevice
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Check any condition to make AhciBus support when UEFI RAID OpROM dispathed.
|
|
Current condition:
|
|
1. HDD Password Support
|
|
2. PUIS Support
|
|
|
|
@retval TRUE Need AhciBus support
|
|
@retval FALSE AhciBus not support
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
AhciBusSupportCheck (
|
|
EFI_PCI_IO_PROTOCOL *PciIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HDD_PASSWORD_SERVICE_PROTOCOL *HddPasswordService;
|
|
KERNEL_CONFIGURATION KernelConfiguration;
|
|
RAID_CONTROLLER_PRIVATE_DATA *RaidControllerPrivateData;
|
|
UINTN Seg;
|
|
UINTN Bus;
|
|
UINTN Device;
|
|
UINTN Function;
|
|
LIST_ENTRY *Link;
|
|
|
|
Status = PciIo->GetLocation (
|
|
PciIo,
|
|
&Seg,
|
|
&Bus,
|
|
&Device,
|
|
&Function
|
|
);
|
|
|
|
for (Link = GetFirstNode (&mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead);
|
|
!IsNull (&mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead, Link);
|
|
Link = GetNextNode (&mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead, Link)) {
|
|
RaidControllerPrivateData = (RAID_CONTROLLER_PRIVATE_DATA *)Link;
|
|
if (RaidControllerPrivateData->PciBus == Bus &&
|
|
RaidControllerPrivateData->PciDevice == Device &&
|
|
RaidControllerPrivateData->PciFunction == Function &&
|
|
RaidControllerPrivateData->Checked != TRUE) {
|
|
RaidControllerPrivateData->Checked = TRUE;
|
|
mDelayUefiRaidOpromPrivate->RaidControllerRemain -= 1;
|
|
|
|
if (mDelayUefiRaidOpromPrivate->RaidControllerRemain == 0) {
|
|
mDelayUefiRaidOpromPrivate->RaidControllerAllConnected = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Condition 1: Check HddPassword
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHddPasswordServiceProtocolGuid,
|
|
NULL,
|
|
(VOID **)&HddPasswordService
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
mDelayUefiRaidOpromPrivate->AhciBusSupport = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Condition 2: Check PUIS
|
|
//
|
|
|
|
Status = GetKernelConfiguration (&KernelConfiguration);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
if (KernelConfiguration.PUISEnable == TRUE) {
|
|
mDelayUefiRaidOpromPrivate->AhciBusSupport = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// No AhciBus support
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Retrieves the image handle of the platform override driver for a controller in the system.
|
|
|
|
@param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_
|
|
PROTOCOL instance.
|
|
@param ControllerHandle The device handle of the controller to check if a driver override
|
|
exists.
|
|
@param DriverImageHandle On input, a pointer to the previous driver image handle returned
|
|
by GetDriver(). On output, a pointer to the next driver
|
|
image handle.
|
|
|
|
@retval EFI_SUCCESS The driver override for ControllerHandle was returned in
|
|
DriverImageHandle.
|
|
@retval EFI_NOT_FOUND A driver override for ControllerHandle was not found.
|
|
@retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is NULL.
|
|
@retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a
|
|
previous call to GetDriver().
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromPlatformDriverOverrideGetDriver (
|
|
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN OUT EFI_HANDLE *DriverImageHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_TYPE00 PciData;
|
|
|
|
if (DriverImageHandle == NULL || ControllerHandle == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (*DriverImageHandle != NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID**) &PciIo
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0,
|
|
sizeof (PciData),
|
|
&PciData
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE &&
|
|
PciData.Hdr.ClassCode[1] == PCI_CLASS_MASS_STORAGE_RAID) {
|
|
|
|
if (mDelayUefiRaidOpromPrivate->RaidControllerInfoGet != TRUE) {
|
|
ScanAllSataController ();
|
|
}
|
|
|
|
*DriverImageHandle = gDelayUefiRaidOpromDriverImageHandle;
|
|
return EFI_SUCCESS;
|
|
}
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Retrieves the device path of the platform override driver for a controller in the system.
|
|
|
|
@param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL instance.
|
|
@param ControllerHandle The device handle of the controller to check if a driver override
|
|
exists.
|
|
@param DriverImagePath On input, a pointer to the previous driver device path returned by
|
|
GetDriverPath(). On output, a pointer to the next driver
|
|
device path. Passing in a pointer to NULL will return the first
|
|
driver device path for ControllerHandle.
|
|
|
|
@retval EFI_SUCCESS The driver override for ControllerHandle was returned in
|
|
DriverImageHandle.
|
|
@retval EFI_UNSUPPORTED The operation is not supported.
|
|
@retval EFI_NOT_FOUND A driver override for ControllerHandle was not found.
|
|
@retval EFI_INVALID_PARAMETER The handle specified by ControllerHandle is NULL.
|
|
@retval EFI_INVALID_PARAMETER DriverImagePath is not a device path that was returned on a
|
|
previous call to GetDriverPath().
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromPlatformDriverOverrideGetDriverPath (
|
|
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **DriverImagePath
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Used to associate a driver image handle with a device path that was returned on a prior call to the
|
|
GetDriverPath() service. This driver image handle will then be available through the
|
|
GetDriver() service.
|
|
|
|
@param This A pointer to the EFI_PLATFORM_DRIVER_OVERRIDE_
|
|
PROTOCOL instance.
|
|
@param ControllerHandle The device handle of the controller.
|
|
@param DriverImagePath A pointer to the driver device path that was returned in a prior
|
|
call to GetDriverPath().
|
|
@param DriverImageHandle The driver image handle that was returned by LoadImage()
|
|
when the driver specified by DriverImagePath was loaded
|
|
into memory.
|
|
|
|
@retval EFI_SUCCESS The association between DriverImagePath and
|
|
DriverImageHandle was established for the controller specified
|
|
by ControllerHandle.
|
|
@retval EFI_UNSUPPORTED The operation is not supported.
|
|
@retval EFI_NOT_FOUND DriverImagePath is not a device path that was returned on a prior
|
|
call to GetDriverPath() for the controller specified by
|
|
ControllerHandle.
|
|
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
|
|
@retval EFI_INVALID_PARAMETER DriverImagePath is not a valid device path.
|
|
@retval EFI_INVALID_PARAMETER DriverImageHandle is not a valid image handle.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromPlatformDriverOverrideGetDriverLoaded (
|
|
IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DriverImagePath,
|
|
IN EFI_HANDLE DriverImageHandle
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Get device data by identify command with AtaPassThru protocol
|
|
|
|
@param AtaPassThruProtocol AtaPassThru protocol on the specific ATA controller
|
|
@param Port The port for device
|
|
@param PortMultiplierPort The PortMultiplierPort for device
|
|
@param IdentifyData The pointer for identify data buffer
|
|
@param IdentifyDataSize The size for identify data buffer
|
|
|
|
@retval EFI_SUCCESS IdentifyData valid
|
|
@retval EFI_INVALID_PARAMETER Parameter invalid
|
|
@retval others return by AtaPassThru Protocol
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IdentifyByAtaPassThru (
|
|
IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThruProtocol,
|
|
IN UINT16 Port,
|
|
IN UINT16 PortMultiplierPort,
|
|
IN OUT VOID *IdentifyData,
|
|
IN OUT UINTN *IdentifyDataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ATA_PASS_THRU_COMMAND_PACKET AtaPassThruCmdPacket;
|
|
EFI_ATA_COMMAND_BLOCK Acb;
|
|
EFI_ATA_STATUS_BLOCK Asb;
|
|
|
|
if (AtaPassThruProtocol == NULL || IdentifyData == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (*IdentifyDataSize < IDENTIFY_TABLE_SIZE) {
|
|
*IdentifyDataSize = IDENTIFY_TABLE_SIZE;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
//
|
|
// Initial Command packet
|
|
//
|
|
ZeroMem (&AtaPassThruCmdPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
|
|
ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
|
|
ZeroMem (&Asb, sizeof (EFI_ATA_STATUS_BLOCK));
|
|
AtaPassThruCmdPacket.Acb = &Acb;
|
|
AtaPassThruCmdPacket.Asb = &Asb;
|
|
|
|
//
|
|
// Fill in command packet
|
|
//
|
|
AtaPassThruCmdPacket.Acb->AtaCommand = ATA_IDENTIFY_CMD;
|
|
AtaPassThruCmdPacket.Acb->AtaDeviceHead |= ((PortMultiplierPort<< 4) | 0xe0);
|
|
AtaPassThruCmdPacket.InDataBuffer = (VOID *)IdentifyData;
|
|
AtaPassThruCmdPacket.InTransferLength = IDENTIFY_TABLE_SIZE;
|
|
AtaPassThruCmdPacket.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;
|
|
AtaPassThruCmdPacket.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
|
|
|
|
//
|
|
// Processing AtaPassThru command
|
|
//
|
|
Status = AtaPassThruProtocol->PassThru (
|
|
AtaPassThruProtocol,
|
|
Port,
|
|
PortMultiplierPort,
|
|
&AtaPassThruCmdPacket,
|
|
0
|
|
);
|
|
if(Status == EFI_SUCCESS) {
|
|
*IdentifyDataSize = IDENTIFY_TABLE_SIZE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Check if the input private data is alreadt exist
|
|
@param ContorllerHandle Controller handle of the device
|
|
@param DiskHandle device handle
|
|
@param Port Port number of the device
|
|
|
|
@retval EFI_SUCCESS the private data for this device is already exist in the linked list
|
|
@retval others the private data for this device is not exist in the linked list
|
|
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
CheckDuplicatedDevicePrivateData (
|
|
EFI_HANDLE ControllerHandle,
|
|
EFI_HANDLE DiskHandle,
|
|
UINT16 Port
|
|
)
|
|
{
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
LIST_ENTRY *CurrentList;
|
|
EFI_STATUS Status;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
|
|
Status = gBS->HandleProtocol (
|
|
DiskHandle,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID**) &DiskInfo
|
|
);
|
|
|
|
if (!EFI_ERROR(Status)) {
|
|
return TRUE;
|
|
}
|
|
//
|
|
// check the controller handle to see if there's any child handle left unremoved
|
|
// before reconnecting the controller handle
|
|
//
|
|
for (CurrentList = GetFirstNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead));
|
|
!IsNull (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), CurrentList);
|
|
CurrentList = GetNextNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), CurrentList)) {
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_LINK (CurrentList);
|
|
if (DevicePrivateData->ControllerHandle == ControllerHandle && DevicePrivateData->Port == Port) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Install DiskInfo protocol interface on disk handle by AtaPassThru protocol
|
|
|
|
@param DiskHandle The handle of Disk
|
|
@param PciDevicePath The DevicePath of Disk
|
|
@param CurrentSataDevicePath The CurrentSataDevicePath of Disk
|
|
|
|
@retval EFI_SUCCESS Install DiskInfo successfully
|
|
@retval others Install failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallDiskInfoProtocolByAta (
|
|
EFI_HANDLE DiskHandle,
|
|
PCI_DEVICE_PATH *PciDevicePath,
|
|
SATA_DEVICE_PATH *CurrentSataDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINT32 HandleIndex;
|
|
EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThruPtr;
|
|
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *AtaPassThruDevPath;
|
|
BOOLEAN IsMatched;
|
|
UINT16 PortMap;
|
|
UINT16 Port;
|
|
UINT16 PortMultiplierPort;
|
|
UINTN IdentifyTableSize;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiAtaPassThruProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (Status != EFI_SUCCESS || HandleBuffer == NULL) {
|
|
return Status;
|
|
}
|
|
|
|
AtaPassThruPtr = NULL;
|
|
AtaPassThruDevPath = NULL;
|
|
|
|
TmpDevicePath = NULL;
|
|
|
|
PortMap = 0;
|
|
Port = 0;
|
|
PortMultiplierPort = 0;
|
|
|
|
DevicePrivateData = NULL;
|
|
|
|
//
|
|
// Find out the handle installed AtaPassthru protocol, and match the SATA controller
|
|
//
|
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
|
Status = gBS->OpenProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &AtaPassThruDevPath,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
IsMatched = FALSE;
|
|
TmpDevicePath = AtaPassThruDevPath;
|
|
while (!IsDevicePathEnd (TmpDevicePath)) {
|
|
if((TmpDevicePath->Type == HARDWARE_DEVICE_PATH) && (TmpDevicePath->SubType == HW_PCI_DP)) {
|
|
if((((PCI_DEVICE_PATH*)TmpDevicePath)->Device == PciDevicePath->Device) &&
|
|
(((PCI_DEVICE_PATH*)TmpDevicePath)->Function) == PciDevicePath->Function) {
|
|
//
|
|
// Controller matched
|
|
//
|
|
IsMatched = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
}
|
|
if(!IsMatched) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiAtaPassThruProtocolGuid,
|
|
(VOID **)&AtaPassThruPtr
|
|
);
|
|
if(Status == EFI_SUCCESS) {
|
|
//
|
|
// Prepare the DiskInfo and install DiskInfo protocol to the Handle
|
|
//
|
|
PortMap = CurrentSataDevicePath->HBAPortNumber;
|
|
for (Port = 0; PortMap != 0; Port++, PortMap >>= 1);
|
|
Port--;
|
|
PortMultiplierPort = 0;
|
|
|
|
if (CheckDuplicatedDevicePrivateData(HandleBuffer[HandleIndex], DiskHandle, Port)) {
|
|
FreePool (HandleBuffer);
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
DevicePrivateData = AllocateZeroPool (sizeof (DEVICE_PRIVATE_DATA));
|
|
if (DevicePrivateData == NULL) {
|
|
FreePool (HandleBuffer);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
DevicePrivateData->Signature = DEVICE_PRIVATE_DATA_SIGNATURE;
|
|
DevicePrivateData->ControllerHandle = HandleBuffer[HandleIndex];
|
|
DevicePrivateData->DeviceHandle = DiskHandle;
|
|
DevicePrivateData->ControllerDevicePath = AtaPassThruDevPath;
|
|
DevicePrivateData->AtaPassThruPtr = AtaPassThruPtr;
|
|
DevicePrivateData->Port = Port;
|
|
DevicePrivateData->PortMultiplierPort = PortMultiplierPort;
|
|
CopyMem (&DevicePrivateData->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid, sizeof (EFI_GUID));
|
|
|
|
//
|
|
// Check the device is HDD or ODD.
|
|
// If the device is ODD, if may be supported by AtaPassThru protocol provided by UEFI RAID OpROM.
|
|
//
|
|
IdentifyTableSize = IDENTIFY_TABLE_SIZE;
|
|
|
|
Status = IdentifyByAtaPassThru (
|
|
AtaPassThruPtr,
|
|
Port,
|
|
PortMultiplierPort,
|
|
&(DevicePrivateData->DeviceIdentifyDataRaw),
|
|
&IdentifyTableSize
|
|
);
|
|
if (Status == EFI_SUCCESS && mDelayUefiRaidOpromPrivate->AhciBusSupport == FALSE) {
|
|
//
|
|
// The device can get identify data from AtaPassThru.
|
|
//
|
|
DevicePrivateData->DiskInfo.Identify = AtaDiskInfoIdentify;
|
|
DevicePrivateData->DiskInfo.Inquiry = AtaDiskInfoInquiry;
|
|
DevicePrivateData->DiskInfo.SenseData = AtaDiskInfoSenseData;
|
|
DevicePrivateData->DiskInfo.WhichIde = AtaDiskInfoWhichIde;
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&DiskHandle,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&(DevicePrivateData->DiskInfo)
|
|
);
|
|
} else {
|
|
//
|
|
// The ODD device can't get identify data from AtaPassThru and may get from ExtScsiPassThru.
|
|
//
|
|
|
|
}
|
|
|
|
|
|
InsertTailList (
|
|
&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead),
|
|
&DevicePrivateData->Link
|
|
);
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
Get device data by inquiry command with ExtScsiPassThru protocol
|
|
|
|
@param DevicePrivateData The device data
|
|
|
|
@retval EFI_SUCCESS Get device data by ExtScsiPassThru protocol successfully.
|
|
@retval others Can not get device data and return error status by ExtScsiPassThru protocol.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InquiryByExtScsiPassThru (
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 Lun;
|
|
UINT8 *TargetId;
|
|
SCSI_TARGET_ID ScsiTargetId;
|
|
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
|
|
EFI_SCSI_CDB_6 Cdb6;
|
|
ATA_IDENTIFY_DATA *IdentifyData;
|
|
EFI_SCSI_SENSE_DATA_EXT SenseDataExt;
|
|
EFI_SCSI_ATA_VPD_PAGE AtaVpdPage;
|
|
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThruProtocol;
|
|
CHAR8 *TempString;
|
|
UINT16 Index;
|
|
CHAR8 Temp8;
|
|
|
|
TempString = NULL;
|
|
|
|
ExtScsiPassThruProtocol = DevicePrivateData->ExtScsiPassThruPtr;
|
|
|
|
TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
|
|
SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
|
|
*TargetId = (UINT8)(DevicePrivateData->Port);
|
|
Lun = 0;
|
|
|
|
//
|
|
// EFI_SCSI_OP_INQUIRY
|
|
//
|
|
ZeroMem (&Packet, sizeof (Packet));
|
|
ZeroMem (&Cdb6, sizeof (Cdb6));
|
|
ZeroMem (&SenseDataExt, sizeof (SenseDataExt));
|
|
ZeroMem (&AtaVpdPage, sizeof (AtaVpdPage));
|
|
|
|
Cdb6.OpCode = EFI_SCSI_OP_INQUIRY;
|
|
Cdb6.AllocationLengthMsb = (UINT8) (sizeof (AtaVpdPage) >> 8);
|
|
Cdb6.AllocationLengthLsb = (UINT8) (sizeof (AtaVpdPage) & 0xFF);
|
|
|
|
Packet.Timeout = EFI_TIMER_PERIOD_SECONDS (1);
|
|
Packet.Cdb = &Cdb6;
|
|
Packet.CdbLength = (UINT8) sizeof (Cdb6);
|
|
Packet.InDataBuffer = &AtaVpdPage;
|
|
Packet.InTransferLength = sizeof (AtaVpdPage);
|
|
Packet.SenseData = &(DevicePrivateData->ScsiSenseDataExt);
|
|
Packet.SenseDataLength = (UINT8) sizeof (SenseDataExt);
|
|
|
|
Status = ExtScsiPassThruProtocol->PassThru (
|
|
ExtScsiPassThruProtocol,
|
|
TargetId,
|
|
Lun,
|
|
&Packet,
|
|
NULL
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
IdentifyData = (ATA_IDENTIFY_DATA *)&(DevicePrivateData->DeviceIdentifyDataRaw);
|
|
|
|
CopyMem (
|
|
&(IdentifyData->ModelName),
|
|
&(AtaVpdPage.SatVendorIdentification),
|
|
24
|
|
);
|
|
|
|
TempString = AllocateZeroPool (0x100);
|
|
if (TempString == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (TempString, IdentifyData->ModelName, 24);
|
|
//
|
|
// Swap the string since Identify Table format is inverted
|
|
//
|
|
Index = 0;
|
|
while (TempString[Index] != 0 || TempString[Index+1] != 0) {
|
|
Temp8 = TempString[Index];
|
|
TempString[Index] = TempString[Index+1];
|
|
TempString[Index+1] = Temp8;
|
|
Index +=2;
|
|
}
|
|
CopyMem (IdentifyData->ModelName, TempString, 24);
|
|
|
|
CopyMem (
|
|
&(IdentifyData->FirmwareVer),
|
|
&(AtaVpdPage.SatProductRevisionLevel),
|
|
4
|
|
);
|
|
|
|
ZeroMem (TempString, 0x100);
|
|
CopyMem (TempString, IdentifyData->FirmwareVer, 4);
|
|
//
|
|
// Swap the string since Identify Table format is inverted
|
|
//
|
|
Index = 0;
|
|
while (TempString[Index] != 0 || TempString[Index+1] != 0) {
|
|
Temp8 = TempString[Index];
|
|
TempString[Index] = TempString[Index+1];
|
|
TempString[Index+1] = Temp8;
|
|
Index +=2;
|
|
}
|
|
CopyMem (IdentifyData->FirmwareVer, TempString, 4);
|
|
|
|
if (AtaVpdPage.PeripheralDeviceType == EFI_SCSI_TYPE_CDROM) {
|
|
IdentifyData->config |= ATAPI_DEVICE_BIT;
|
|
}
|
|
}
|
|
|
|
if (TempString != NULL) {
|
|
FreePool (TempString);
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
Install DiskInfo protocol interface on disk handle by ExtScsiPassThru protocol
|
|
|
|
@param DiskHandle The handle of Disk
|
|
@param PciDevicePath The DevicePath of Disk
|
|
@param DevicePrivateData The davice data
|
|
|
|
@retval EFI_SUCCESS Install DiskInfo successfully
|
|
@retval others Install failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InstallDiskInfoProtocolByScsi (
|
|
EFI_HANDLE DiskHandle,
|
|
PCI_DEVICE_PATH *PciDevicePath,
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINT32 HandleIndex;
|
|
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThruProtocol;
|
|
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *ExtScsiPassThruDevPath;
|
|
BOOLEAN IsMatched;
|
|
SCSI_DEVICE_PATH *CurrentScsiDevicePath;
|
|
|
|
HandleBuffer = NULL;
|
|
HandleCount = 0;
|
|
|
|
ExtScsiPassThruDevPath = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if ((Status != EFI_SUCCESS) || (HandleBuffer == NULL)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find out the handle installed ExtScsiPassThru protocol, and match the RAID controller
|
|
//
|
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
|
Status = gBS->OpenProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &ExtScsiPassThruDevPath,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
|
|
IsMatched = FALSE;
|
|
TmpDevicePath = ExtScsiPassThruDevPath;
|
|
while (!IsDevicePathEnd (TmpDevicePath)) {
|
|
if((TmpDevicePath->Type == HARDWARE_DEVICE_PATH) && (TmpDevicePath->SubType == HW_PCI_DP)) {
|
|
if((((PCI_DEVICE_PATH*)TmpDevicePath)->Device == PciDevicePath->Device) &&
|
|
(((PCI_DEVICE_PATH*)TmpDevicePath)->Function) == PciDevicePath->Function) {
|
|
//
|
|
// Controller matched
|
|
//
|
|
IsMatched = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
}
|
|
if(!IsMatched) {
|
|
continue;
|
|
}
|
|
|
|
TmpDevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *)PciDevicePath);
|
|
|
|
if ((TmpDevicePath->Type == MESSAGING_DEVICE_PATH) &&
|
|
(TmpDevicePath->SubType == MSG_SCSI_DP)) {
|
|
//
|
|
// Set Device port number
|
|
//
|
|
CurrentScsiDevicePath = (SCSI_DEVICE_PATH*) TmpDevicePath;
|
|
DevicePrivateData->Port = CurrentScsiDevicePath->Pun;
|
|
DevicePrivateData->PortMultiplierPort = 0;
|
|
}
|
|
|
|
if (!IsIntelRaidController(HandleBuffer[HandleIndex])) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
(VOID **)&ExtScsiPassThruProtocol
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
//
|
|
// Prepare the DiskInfo and install DiskInfo protocol to the Handle
|
|
//
|
|
|
|
DevicePrivateData->ControllerDevicePath = ExtScsiPassThruDevPath;
|
|
DevicePrivateData->ExtScsiPassThruPtr = ExtScsiPassThruProtocol;
|
|
|
|
DevicePrivateData->DiskInfo.Identify = ScsiDiskInfoIdentify;
|
|
DevicePrivateData->DiskInfo.Inquiry = ScsiDiskInfoInquiry;
|
|
DevicePrivateData->DiskInfo.SenseData = ScsiDiskInfoSenseData;
|
|
DevicePrivateData->DiskInfo.WhichIde = ScsiDiskInfoWhichIde;
|
|
|
|
InquiryByExtScsiPassThru (DevicePrivateData);
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&DiskHandle,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&(DevicePrivateData->DiskInfo)
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
Get identify controller data.
|
|
|
|
@param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
|
|
@param Buffer The buffer used to store the identify controller data.
|
|
|
|
@return EFI_SUCCESS Successfully get the identify controller data.
|
|
@return EFI_DEVICE_ERROR Fail to get the identify controller data.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
NvmeIdentifyController (
|
|
IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassThruProtocol,
|
|
IN UINT32 NamespaceId,
|
|
IN NVME_ADMIN_CONTROLLER_DATA *NvmeAdminControllerData
|
|
)
|
|
{
|
|
EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
|
|
EFI_NVM_EXPRESS_COMMAND Command;
|
|
EFI_NVM_EXPRESS_COMPLETION Completion;
|
|
EFI_STATUS Status;
|
|
|
|
ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
|
|
ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
|
|
ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
|
|
|
|
Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
|
|
|
|
//
|
|
// According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
|
|
// For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
|
|
//
|
|
Command.Nsid = 0;
|
|
|
|
CommandPacket.NvmeCmd = &Command;
|
|
CommandPacket.NvmeCompletion = &Completion;
|
|
CommandPacket.TransferBuffer = NvmeAdminControllerData;
|
|
CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);
|
|
CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);
|
|
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
|
|
//
|
|
// Set bit 0 (Cns bit) to 1 to identify a controller
|
|
//
|
|
Command.Cdw10 = 1;
|
|
Command.Flags = CDW10_VALID;
|
|
|
|
Status = NvmePassThruProtocol->PassThru (
|
|
NvmePassThruProtocol,
|
|
NamespaceId,
|
|
&CommandPacket,
|
|
NULL
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Find out the handle of HDD or ODD and install DiskInfo protocol on it.
|
|
|
|
@retval EFI_SUCCESS Install DiskInfo successfully
|
|
@retval others Install failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SearchHardDiskHandle (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINT32 HandleIndex;
|
|
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
PCI_DEVICE_PATH *PciDevicePath;
|
|
SATA_DEVICE_PATH *CurrentSataDevicePath;
|
|
EFI_HANDLE ControllerHandle;
|
|
|
|
PciDevicePath = NULL;
|
|
CurrentSataDevicePath = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
AllHandles,
|
|
NULL,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get the device paths of all hard disks
|
|
//
|
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
|
Status = gBS->OpenProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &DevicePath,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
//
|
|
// If the controller handle is not Intel RAID which we install gEfiCallerIdGuid
|
|
// during .start()
|
|
//
|
|
ControllerHandle = NULL;
|
|
TmpDevicePath = DevicePath;
|
|
Status = gBS->LocateDevicePath(&gEfiPciIoProtocolGuid, &TmpDevicePath, &ControllerHandle);
|
|
if (!EFI_ERROR(Status) && !IsIntelRaidController(ControllerHandle)) {
|
|
continue;
|
|
}
|
|
|
|
TmpDevicePath = DevicePath;
|
|
while (!IsDevicePathEnd (TmpDevicePath)) {
|
|
if ((DevicePathType (TmpDevicePath) == HARDWARE_DEVICE_PATH) &&
|
|
(DevicePathSubType (TmpDevicePath) == HW_PCI_DP)) {
|
|
PciDevicePath = (PCI_DEVICE_PATH *) TmpDevicePath;
|
|
}
|
|
if ((TmpDevicePath->Type == MESSAGING_DEVICE_PATH) &&
|
|
(TmpDevicePath->SubType == MSG_SATA_DP) &&
|
|
(((SATA_DEVICE_PATH*) TmpDevicePath)->PortMultiplierPortNumber & SATA_HBA_DIRECT_CONNECT_FLAG) &&
|
|
((NextDevicePathNode (TmpDevicePath))->Type == END_DEVICE_PATH_TYPE)) {
|
|
//
|
|
// Store the RAID driver device path and install DiskInfo on it's handle
|
|
//
|
|
CurrentSataDevicePath = (SATA_DEVICE_PATH*) TmpDevicePath;
|
|
|
|
if (PciDevicePath != NULL) {
|
|
InstallDiskInfoProtocolByAta (
|
|
HandleBuffer[HandleIndex],
|
|
PciDevicePath,
|
|
CurrentSataDevicePath
|
|
);
|
|
}
|
|
}
|
|
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
}
|
|
}
|
|
|
|
if (CurrentSataDevicePath == NULL) {
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Check that UEFI RAID driver installs DiskInfo protocol or not.
|
|
|
|
@retval EFI_SUCCESS UEFI RAID driver already installs DiskInfo protocol
|
|
@retval others UEFI RAID driver doesn't support DiskInfo protocol
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
CheckDiskInfoProtocol (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINT32 HandleIndex;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
|
|
HandleBuffer = NULL;
|
|
HandleCount = 0;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS || HandleBuffer == NULL) {
|
|
return Status;
|
|
}
|
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
|
Status = gBS->OpenProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID **) &DiskInfo,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
//
|
|
// filter not HDD
|
|
//
|
|
if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoUsbInterfaceGuid)) {
|
|
continue;
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
FreePool (HandleBuffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (HandleBuffer != NULL) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
After installing AtaPassThru protocol, the callback will check AhciBus support AtaPassThru protocol.
|
|
1. If supporting, the callback installs gUefiRaidOpromReadyGuid to make UEFI RAID OpROM dispatch and run.
|
|
2. If not supporting, the callback checks any DiskInfo protocol on HDD or ODD handle.
|
|
If any one doesn't have DiskInfo Protocol, this driver will install.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event hanlder private data
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DelayUefiRaidOpromAtaPassThruCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (mDelayUefiRaidOpromPrivate->AhciBusSupport) {
|
|
if (mDelayUefiRaidOpromPrivate->RaidControllerAllConnected) {
|
|
//
|
|
// Install this Guid to make UEFI RAID OpROM run
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&(mDelayUefiRaidOpromPrivate->ControllerHandle),
|
|
&gUefiRaidOpromReadyGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&(mDelayUefiRaidOpromPrivate->UefiRaidOpromReadyProtocol)
|
|
);
|
|
}
|
|
} else {
|
|
//
|
|
// AhciBus does not support
|
|
// DiskInfo will be installed due to UEFI RAID OpROM not support.
|
|
//
|
|
Status = CheckDiskInfoProtocol();
|
|
if (Status != EFI_SUCCESS) {
|
|
SearchHardDiskHandle();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
After installing ExtScsiPassThru protocol, the callback will check any device in list.
|
|
If any device in list, the callback tries to install DiskInfo protocol.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event hanlder private data
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DelayUefiRaidOpromExtScsiPassThruCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINT32 HandleIndex;
|
|
EFI_HANDLE QueryHandle;
|
|
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThruProtocol;
|
|
UINT64 Lun;
|
|
UINT8 *TargetId;
|
|
SCSI_TARGET_ID ScsiTargetId;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
PCI_DEVICE_PATH *PciDevicePath;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
LIST_ENTRY *Link;
|
|
|
|
if (IsListEmpty (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead))) {
|
|
//
|
|
// In some platform, no AtaPassThru, and DevicePath is processed after ScsiIo protocol installed
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
|
|
SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
|
|
Lun = 0;
|
|
|
|
HandleCount = 0;
|
|
HandleBuffer = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
|
QueryHandle = HandleBuffer[HandleIndex];
|
|
if (!IsIntelRaidController(QueryHandle)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
QueryHandle,
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
(VOID**) &ExtScsiPassThruProtocol
|
|
);
|
|
|
|
mDelayUefiRaidOpromPrivate->ExtScsiPassThruProtocol = ExtScsiPassThruProtocol;
|
|
|
|
while (Status == EFI_SUCCESS) {
|
|
Status = ExtScsiPassThruProtocol->GetNextTargetLun (
|
|
ExtScsiPassThruProtocol,
|
|
&TargetId,
|
|
&Lun
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
for (Link = GetFirstNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead));
|
|
!IsNull (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), Link);
|
|
Link = GetNextNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), Link)) {
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_LINK (Link);
|
|
if (DevicePrivateData->Port == *TargetId) {
|
|
//
|
|
// Check device type, and check DiskInfo.
|
|
// If no DiskInfo, install DiskInfo
|
|
//
|
|
|
|
Status = gBS->HandleProtocol (
|
|
DevicePrivateData->DeviceHandle,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID**) &DiskInfo
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
break;
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
DevicePrivateData->DeviceHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &DevicePath,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
TmpDevicePath = DevicePath;
|
|
while (!IsDevicePathEnd (TmpDevicePath)) {
|
|
if ( ((DevicePathType (TmpDevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (TmpDevicePath) == HW_PCI_DP))
|
|
&& ( ((NextDevicePathNode (TmpDevicePath))->Type == MESSAGING_DEVICE_PATH) &&
|
|
( ((NextDevicePathNode (TmpDevicePath))->SubType == MSG_SATA_DP) ||
|
|
((NextDevicePathNode (TmpDevicePath))->SubType == MSG_SCSI_DP) ) )
|
|
) {
|
|
PciDevicePath = (PCI_DEVICE_PATH *) TmpDevicePath;
|
|
|
|
InstallDiskInfoProtocolByScsi (
|
|
DevicePrivateData->DeviceHandle,
|
|
PciDevicePath,
|
|
DevicePrivateData
|
|
);
|
|
}
|
|
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
Status = EFI_SUCCESS;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
After installing ScsiIo protocol, the callback will check DiskInfo protocol in device handles.
|
|
The callback tries to install DiskInfo protocol if there is no DiskInfo protocol in device handles.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event hanlder private data
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DelayUefiRaidOpromScsiIoCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
UINT32 HandleIndex;
|
|
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
PCI_DEVICE_PATH *PciDevicePath;
|
|
SCSI_DEVICE_PATH *CurrentScsiDevicePath;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
HandleCount = 0;
|
|
HandleBuffer = NULL;
|
|
|
|
CurrentScsiDevicePath = NULL;
|
|
|
|
DevicePrivateData = NULL;
|
|
|
|
//
|
|
// Find Handle
|
|
//
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiScsiIoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS || HandleBuffer == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (HandleIndex = 0; HandleIndex < HandleCount;HandleIndex++) {
|
|
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID**) &DiskInfo
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
DevicePrivateData = AllocateZeroPool (sizeof (DEVICE_PRIVATE_DATA));
|
|
|
|
if (DevicePrivateData == NULL) {
|
|
FreePool (HandleBuffer);
|
|
return;
|
|
}
|
|
|
|
DevicePrivateData->Signature = DEVICE_PRIVATE_DATA_SIGNATURE;
|
|
DevicePrivateData->DeviceHandle = HandleBuffer[HandleIndex];
|
|
CopyMem (&DevicePrivateData->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid, sizeof (EFI_GUID));
|
|
InsertTailList (
|
|
&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead),
|
|
&DevicePrivateData->Link
|
|
);
|
|
|
|
Status = gBS->HandleProtocol (
|
|
DevicePrivateData->DeviceHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID**) &DevicePath
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
TmpDevicePath = DevicePath;
|
|
while (!IsDevicePathEnd (TmpDevicePath)) {
|
|
if ( (DevicePathType (TmpDevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (TmpDevicePath) == HW_PCI_DP)
|
|
&& ( ((NextDevicePathNode (TmpDevicePath))->Type == MESSAGING_DEVICE_PATH) && ((NextDevicePathNode (TmpDevicePath))->SubType == MSG_SCSI_DP) )
|
|
) {
|
|
PciDevicePath = (PCI_DEVICE_PATH *) TmpDevicePath;
|
|
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
|
|
CurrentScsiDevicePath = (SCSI_DEVICE_PATH*) TmpDevicePath;
|
|
|
|
InstallDiskInfoProtocolByScsi (
|
|
HandleBuffer[HandleIndex],
|
|
PciDevicePath,
|
|
DevicePrivateData
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
After installing AtaPassThru protocol, the callback will check AhciBus support AtaPassThru protocol.
|
|
1. If supporting, the callback installs gUefiRaidOpromReadyGuid to make UEFI RAID OpROM dispatch and run.
|
|
2. If not supporting, the callback checks any DiskInfo protocol on HDD or ODD handle.
|
|
If any one doesn't have DiskInfo Protocol, this driver will install.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event hanlder private data
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
DelayUefiRaidOpromNvmePassThruCallBack (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassThruProtocol;
|
|
NVME_ADMIN_CONTROLLER_DATA *NvmeAdminControllerData;
|
|
UINT32 NamespaceId;
|
|
|
|
LIST_ENTRY *Link;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
|
|
if (IsListEmpty (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead))) {
|
|
if (mDelayUefiRaidOpromPrivate->AhciBusSupport) {
|
|
Status = SearchHardDiskHandle();
|
|
DEBUG ((DEBUG_WARN, "search HardDiskHandle status%r\n", Status));
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
for (Link = GetFirstNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead));
|
|
!IsNull (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), Link);
|
|
Link = GetNextNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), Link)) {
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_LINK (Link);
|
|
if (!IsIntelRaidController(DevicePrivateData->ControllerHandle)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Check device type, and check DiskInfo.
|
|
// If no DiskInfo, install DiskInfo
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
DevicePrivateData->DeviceHandle,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID**) &DiskInfo
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
Status = gBS->HandleProtocol (
|
|
DevicePrivateData->ControllerHandle,
|
|
&gEfiNvmExpressPassThruProtocolGuid,
|
|
(VOID**) &NvmePassThruProtocol
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
NvmeAdminControllerData = NULL;
|
|
|
|
NvmeAdminControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof(NVME_ADMIN_CONTROLLER_DATA));
|
|
|
|
if (NvmeAdminControllerData == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// After remapping, the NamespaceId of remapped NVMe seems port + 1.
|
|
//
|
|
NamespaceId = DevicePrivateData->Port + 1;
|
|
|
|
Status = NvmeIdentifyController (
|
|
NvmePassThruProtocol,
|
|
NamespaceId,
|
|
NvmeAdminControllerData
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
NvmeAdminControllerData->Sn[19] = 0;
|
|
NvmeAdminControllerData->Mn[39] = 0;
|
|
|
|
DevicePrivateData->NvmePassThruProtocol = NvmePassThruProtocol;
|
|
DevicePrivateData->NvmeAdminControllerData = NvmeAdminControllerData;
|
|
CopyMem (&DevicePrivateData->DiskInfo.Interface, &gEfiDiskInfoNvmeInterfaceGuid, sizeof (EFI_GUID));
|
|
|
|
DevicePrivateData->DiskInfo.Identify = NvmeDiskInfoIdentify;
|
|
DevicePrivateData->DiskInfo.Inquiry = NvmeDiskInfoInquiry;
|
|
DevicePrivateData->DiskInfo.SenseData = NvmeDiskInfoSenseData;
|
|
DevicePrivateData->DiskInfo.WhichIde = NvmeDiskInfoWhichIde;
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
&(DevicePrivateData->DeviceHandle),
|
|
&gEfiDiskInfoProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&(DevicePrivateData->DiskInfo)
|
|
);
|
|
} else {
|
|
FreePool (NvmeAdminControllerData);
|
|
} // End of NvmeIdentifyController
|
|
|
|
} // End of checking NvmePassThruProtocol
|
|
|
|
} // End of checking DiskInfo
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UefiRaidOpromReadyInterface (
|
|
IN EFI_UEFI_RAID_OPROM_READY_PROTOCOL *This
|
|
)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Main entry for this driver.
|
|
Only check BOOT type.
|
|
ATA mode will be checked at DelayUefiRaidOpromPlatformDriverOverrideGetDriver().
|
|
|
|
@param ImageHandle Image handle this driver.
|
|
@param SystemTable Pointer to SystemTable.
|
|
|
|
@retval EFI_SUCESS This function always complete successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
|
|
gDelayUefiRaidOpromDriverImageHandle = ImageHandle;
|
|
if (H2OGetBootType () != EFI_BOOT_TYPE) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
gDelayUefiRaidOpromPlatformDriverOverride = AllocatePool(sizeof (EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL));
|
|
if(gDelayUefiRaidOpromPlatformDriverOverride == NULL){
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
gDelayUefiRaidOpromPlatformDriverOverride->GetDriver = DelayUefiRaidOpromPlatformDriverOverrideGetDriver;
|
|
gDelayUefiRaidOpromPlatformDriverOverride->GetDriverPath = DelayUefiRaidOpromPlatformDriverOverrideGetDriverPath;
|
|
gDelayUefiRaidOpromPlatformDriverOverride->DriverLoaded = DelayUefiRaidOpromPlatformDriverOverrideGetDriverLoaded;
|
|
|
|
//
|
|
// Install the PlatformDriverOverride Potocal of DelayUefiRaidOpromPlatformDriverOverride
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&ImageHandle,
|
|
&gEfiPlatformDriverOverrideProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
gDelayUefiRaidOpromPlatformDriverOverride
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Install the PlatformDriverOverride Potocal of DelayUefiRaidOpromPlatformDriverOverride(%r)\n", Status));
|
|
}
|
|
//
|
|
// Install the DriverBindingPotocal of DelayUefiRaidOpromDriverBinding
|
|
//
|
|
Status = EfiLibInstallDriverBinding (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gDelayUefiRaidOpromDriverBinding,
|
|
ImageHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Install the DriverBindingPotocal of DelayUefiRaidOpromDriverBinding(%r)\n", Status));
|
|
}
|
|
|
|
//
|
|
// Store private data
|
|
//
|
|
mDelayUefiRaidOpromPrivate = AllocatePool(sizeof (DELAY_UEFI_RAID_OPROM_PRIVATE));
|
|
if(mDelayUefiRaidOpromPrivate == NULL){
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
mDelayUefiRaidOpromPrivate->Signature = DELAY_UEFI_RAID_OPROM_SIGNATURE;
|
|
mDelayUefiRaidOpromPrivate->DriverBindingProtocol = NULL;
|
|
mDelayUefiRaidOpromPrivate->ControllerHandle = NULL;
|
|
mDelayUefiRaidOpromPrivate->ThisImageHandle = ImageHandle;
|
|
mDelayUefiRaidOpromPrivate->StartFinish = FALSE;
|
|
mDelayUefiRaidOpromPrivate->AhciBusSupport = FALSE;
|
|
mDelayUefiRaidOpromPrivate->RaidControllerInfoGet = FALSE;
|
|
mDelayUefiRaidOpromPrivate->RaidControllerAllConnected = FALSE;
|
|
mDelayUefiRaidOpromPrivate->RaidControllerRemain = 0;
|
|
mDelayUefiRaidOpromPrivate->ExtScsiPassThruProtocol = NULL;
|
|
|
|
mDelayUefiRaidOpromPrivate->UefiRaidOpromReadyProtocol.UefiRaidOpromReadyInterface = UefiRaidOpromReadyInterface;
|
|
InitializeListHead (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead));
|
|
InitializeListHead (&(mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead));
|
|
|
|
mDelayUefiRaidOpromEvent = NULL;
|
|
mDelayUefiRaidOpromScsiEvent = NULL;
|
|
mDelayUefiRaidOpromScsiIoEvent = NULL;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Tests to see if this driver supports a given controller. If a child device is provided,
|
|
it further tests to see if this driver supports creating a handle for the specified child device.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to test. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
|
parameter is ignored by device drivers, and is optional for bus
|
|
drivers. For bus drivers, if this parameter is not NULL, then
|
|
the bus driver must determine if the bus controller specified
|
|
by ControllerHandle and the child controller specified
|
|
by RemainingDevicePath are both supported by this
|
|
bus driver.
|
|
|
|
@retval EFI_SUCCESS The device specified by ControllerHandle and
|
|
RemainingDevicePath is supported by the driver specified by This.
|
|
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
|
|
RemainingDevicePath is already being managed by the driver
|
|
specified by This.
|
|
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
|
|
RemainingDevicePath is already being managed by a different
|
|
driver or an application that requires exclusive access.
|
|
Currently not implemented.
|
|
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
|
|
RemainingDevicePath is not supported by the driver specified by This.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
PCI_TYPE00 PciData;
|
|
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
|
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ControllerHandle,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID**) &PciIo
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0,
|
|
sizeof (PciData),
|
|
&PciData
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (!(PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE &&
|
|
PciData.Hdr.ClassCode[1] == PCI_CLASS_MASS_STORAGE_RAID)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test.
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID*) &ParentDevicePath,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle
|
|
);
|
|
|
|
}
|
|
|
|
if (mDelayUefiRaidOpromPrivate->StartFinish && mDelayUefiRaidOpromPrivate->RaidControllerAllConnected) {
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
mDelayUefiRaidOpromPrivate->AhciBusSupport = AhciBusSupportCheck (PciIo);
|
|
|
|
if (!(mDelayUefiRaidOpromPrivate->AhciBusSupport) && mDelayUefiRaidOpromPrivate->RaidControllerAllConnected) {
|
|
//
|
|
// Install gUefiRaidOpromReadyGuid to make UEFI RAID OpROM run if AhciBusSupport = FALSE
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&ControllerHandle,
|
|
&gUefiRaidOpromReadyGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&(mDelayUefiRaidOpromPrivate->UefiRaidOpromReadyProtocol)
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
Status = gBS->InstallProtocolInterface (
|
|
&(mDelayUefiRaidOpromPrivate->ThisImageHandle),
|
|
&gUefiRaidOpromReadyGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&(mDelayUefiRaidOpromPrivate->UefiRaidOpromReadyProtocol)
|
|
);
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Starts a device controller or a bus controller.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle The handle of the controller to start. This handle
|
|
must support a protocol interface that supplies
|
|
an I/O abstraction to the driver.
|
|
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
|
|
parameter is ignored by device drivers, and is optional for bus
|
|
drivers. For a bus driver, if this parameter is NULL, then handles
|
|
for all the children of Controller are created by this driver.
|
|
If this parameter is not NULL and the first Device Path Node is
|
|
not the End of Device Path Node, then only the handle for the
|
|
child device specified by the first Device Path Node of
|
|
RemainingDevicePath is created by this driver.
|
|
If the first Device Path Node of RemainingDevicePath is
|
|
the End of Device Path Node, no child handle is created by this
|
|
driver.
|
|
|
|
@retval EFI_SUCCESS The device was started.
|
|
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
|
|
@retval Others The driver failded to start the device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *Registration;
|
|
VOID *RegistrationScsi;
|
|
VOID *RegistrationNvme;
|
|
VOID *RegistrationScsiIo;
|
|
VOID *tempPtr;
|
|
UINT8 ID;
|
|
|
|
ID = 2;
|
|
tempPtr = &ID;
|
|
Status = EFI_SUCCESS;
|
|
|
|
mDelayUefiRaidOpromPrivate->DriverBindingProtocol = This;
|
|
mDelayUefiRaidOpromPrivate->ControllerHandle = ControllerHandle;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiCallerIdGuid,
|
|
&tempPtr,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
Status = gBS->InstallProtocolInterface (
|
|
&ControllerHandle,
|
|
&gEfiCallerIdGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
NULL
|
|
);
|
|
Status = gBS->OpenProtocol (
|
|
ControllerHandle,
|
|
&gEfiCallerIdGuid,
|
|
&tempPtr,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
|
|
}
|
|
|
|
|
|
if (!(mDelayUefiRaidOpromPrivate->StartFinish)) {
|
|
//
|
|
// AtaPassThruProtocool Nofity
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
DelayUefiRaidOpromAtaPassThruCallBack,
|
|
NULL,
|
|
&mDelayUefiRaidOpromEvent
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiAtaPassThruProtocolGuid,
|
|
mDelayUefiRaidOpromEvent,
|
|
&Registration
|
|
);
|
|
}
|
|
|
|
if (!(mDelayUefiRaidOpromPrivate->AhciBusSupport)) {
|
|
//
|
|
// if AhciBus did NOT support, EfiExtScsiPassThruProtocol would process the ATA device information.
|
|
//
|
|
|
|
//
|
|
// ExtScsiPassThruProtocol Nofity
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
DelayUefiRaidOpromExtScsiPassThruCallBack,
|
|
NULL,
|
|
&mDelayUefiRaidOpromScsiEvent
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiExtScsiPassThruProtocolGuid,
|
|
mDelayUefiRaidOpromScsiEvent,
|
|
&RegistrationScsi
|
|
);
|
|
}
|
|
|
|
//
|
|
// ScsiIoProtocol Nofity
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
DelayUefiRaidOpromScsiIoCallBack,
|
|
NULL,
|
|
&mDelayUefiRaidOpromScsiIoEvent
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiScsiIoProtocolGuid,
|
|
mDelayUefiRaidOpromScsiIoEvent,
|
|
&RegistrationScsiIo
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// NVmePassThruProtocol Nofity
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
DelayUefiRaidOpromNvmePassThruCallBack,
|
|
NULL,
|
|
&mDelayUefiRaidOpromNvmeEvent
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiNvmExpressPassThruProtocolGuid,
|
|
mDelayUefiRaidOpromNvmeEvent,
|
|
&RegistrationNvme
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
mDelayUefiRaidOpromPrivate->StartFinish = TRUE;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Stops a device controller or a bus controller.
|
|
|
|
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param[in] ControllerHandle A handle to the device being stopped. The handle must
|
|
support a bus specific I/O protocol for the driver
|
|
to use to stop the device.
|
|
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
|
|
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
|
|
if NumberOfChildren is 0.
|
|
|
|
@retval EFI_SUCCESS The device was stopped.
|
|
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DelayUefiRaidOpromDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ControllerHandle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Stop this driver on ControllerHandle by removing Disk IO protocol and closing
|
|
the Block IO protocol on ControllerHandle.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
ControllerHandle - Handle of device to stop driver on.
|
|
NumberOfChildren - Not used.
|
|
ChildHandleBuffer - Not used.
|
|
|
|
Returns:
|
|
EFI_SUCCESS - This driver is removed ControllerHandle.
|
|
other - This driver was not removed from this device.
|
|
EFI_UNSUPPORTED
|
|
|
|
--*/
|
|
{
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
LIST_ENTRY *CurrentList;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *DelList;
|
|
|
|
//
|
|
// check the controller handle to see if there's any child handle left unremoved
|
|
// before reconnecting the controller handle
|
|
//
|
|
for (CurrentList = GetFirstNode (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead));
|
|
!IsNull (&(mDelayUefiRaidOpromPrivate->DeviceInfoListHead), CurrentList); ) {
|
|
DelList = CurrentList;
|
|
CurrentList = CurrentList->ForwardLink;
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_LINK (DelList);
|
|
//
|
|
// Ahci driver would remove diskinfo protocol before reach here
|
|
// but we still need to remove private node
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
DevicePrivateData->DeviceHandle,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID**) &DiskInfo
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->UninstallProtocolInterface (
|
|
(DevicePrivateData->DeviceHandle),
|
|
&gEfiDiskInfoProtocolGuid,
|
|
DiskInfo
|
|
);
|
|
}
|
|
|
|
RemoveEntryList (&DevicePrivateData->Link);
|
|
FreePool(DevicePrivateData);
|
|
}
|
|
|
|
Status = gBS->CloseProtocol (
|
|
ControllerHandle,
|
|
&gEfiCallerIdGuid,
|
|
This->DriverBindingHandle,
|
|
ControllerHandle
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Provides inquiry information for the controller type.
|
|
|
|
This function is used by the IDE bus driver to get inquiry data. Data format
|
|
of Identify data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[in,out] InquiryData Pointer to a buffer for the inquiry data.
|
|
@param[in,out] InquiryDataSize Pointer to the value for the inquiry data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading InquiryData from device
|
|
@retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AtaDiskInfoInquiry (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *InquiryData,
|
|
IN OUT UINT32 *InquiryDataSize
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Provides identify information for the controller type.
|
|
|
|
This function is used by the IDE bus driver to get identify data. Data format
|
|
of Identify data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
|
|
instance.
|
|
@param[in,out] IdentifyData Pointer to a buffer for the identify data.
|
|
@param[in,out] IdentifyDataSize Pointer to the value for the identify data
|
|
size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading IdentifyData from device
|
|
@retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AtaDiskInfoIdentify (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *IdentifyData,
|
|
IN OUT UINT32 *IdentifyDataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ATA_PASS_THRU_COMMAND_PACKET AtaPassThruCmdPacket;
|
|
EFI_ATA_STATUS_BLOCK Asb;
|
|
EFI_ATA_COMMAND_BLOCK Acb;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_DISKINFO (This);
|
|
if (*IdentifyDataSize < IDENTIFY_TABLE_SIZE) {
|
|
*IdentifyDataSize = IDENTIFY_TABLE_SIZE;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
//
|
|
// Initial Command packet
|
|
//
|
|
ZeroMem (&AtaPassThruCmdPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
|
|
ZeroMem (&Asb, sizeof (EFI_ATA_STATUS_BLOCK));
|
|
ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
|
|
AtaPassThruCmdPacket.Asb = &Asb;
|
|
AtaPassThruCmdPacket.Acb = &Acb;
|
|
//
|
|
// Fill in command packet
|
|
//
|
|
AtaPassThruCmdPacket.Acb->AtaCommand = ATA_IDENTIFY_CMD;
|
|
AtaPassThruCmdPacket.Acb->AtaDeviceHead |= (((DevicePrivateData->PortMultiplierPort)<< 4) | 0xe0);
|
|
AtaPassThruCmdPacket.InDataBuffer = (VOID *)IdentifyData;
|
|
AtaPassThruCmdPacket.InTransferLength = ATA_BLOCK_UNIT;
|
|
AtaPassThruCmdPacket.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;
|
|
AtaPassThruCmdPacket.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;
|
|
|
|
//
|
|
// Processing AtaPassThru command
|
|
//
|
|
Status = DevicePrivateData->AtaPassThruPtr->PassThru (
|
|
DevicePrivateData->AtaPassThruPtr,
|
|
DevicePrivateData->Port,
|
|
DevicePrivateData->PortMultiplierPort,
|
|
&AtaPassThruCmdPacket,
|
|
0
|
|
);
|
|
if(Status == EFI_SUCCESS) {
|
|
*IdentifyDataSize = IDENTIFY_TABLE_SIZE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Provides sense data information for the controller type.
|
|
|
|
This function is used by the IDE bus driver to get sense data.
|
|
Data format of Sense data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[in,out] SenseData Pointer to the SenseData.
|
|
@param[in,out] SenseDataSize Size of SenseData in bytes.
|
|
@param[out] SenseDataNumber Pointer to the value for the sense data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class.
|
|
@retval EFI_DEVICE_ERROR Error reading SenseData from device.
|
|
@retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AtaDiskInfoSenseData (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *SenseData,
|
|
IN OUT UINT32 *SenseDataSize,
|
|
OUT UINT8 *SenseDataNumber
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
This function is used by the IDE bus driver to get controller information.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
|
|
@param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
|
|
|
|
@retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
|
|
@retval EFI_UNSUPPORTED This is not an IDE device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AtaDiskInfoWhichIde (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
OUT UINT32 *IdeChannel,
|
|
OUT UINT32 *IdeDevice
|
|
)
|
|
{
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_DISKINFO (This);
|
|
|
|
*IdeChannel = DevicePrivateData->Port;
|
|
*IdeDevice = DevicePrivateData->PortMultiplierPort;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Provides inquiry information for the controller type.
|
|
|
|
This function is used by the IDE bus driver to get inquiry data. Data format
|
|
of Identify data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[in,out] InquiryData Pointer to a buffer for the inquiry data.
|
|
@param[in,out] InquiryDataSize Pointer to the value for the inquiry data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading InquiryData from device
|
|
@retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskInfoInquiry (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *InquiryData,
|
|
IN OUT UINT32 *InquiryDataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
|
|
EFI_SCSI_CDB_6 Cdb6;
|
|
UINT64 Lun;
|
|
UINT8 *TargetId;
|
|
SCSI_TARGET_ID ScsiTargetId;
|
|
|
|
if (This == NULL || InquiryData == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (*InquiryDataSize < sizeof (EFI_SCSI_INQUIRY_DATA)) {
|
|
*InquiryDataSize = sizeof (EFI_SCSI_INQUIRY_DATA);
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_DISKINFO (This);
|
|
|
|
if (DevicePrivateData->ExtScsiPassThruPtr != NULL) {
|
|
TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
|
|
SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
|
|
*TargetId = (UINT8)(DevicePrivateData->Port);
|
|
Lun = 0;
|
|
|
|
ZeroMem (&Packet, sizeof (Packet));
|
|
ZeroMem (&Cdb6, sizeof (Cdb6));
|
|
ZeroMem (&(DevicePrivateData->ScsiSenseDataExt), sizeof (EFI_SCSI_SENSE_DATA_EXT));
|
|
ZeroMem (&(DevicePrivateData->InquiryData), sizeof (EFI_SCSI_INQUIRY_DATA));
|
|
|
|
Cdb6.OpCode = EFI_SCSI_OP_INQUIRY;
|
|
Cdb6.AllocationLengthMsb = (UINT8) (sizeof (EFI_SCSI_INQUIRY_DATA) >> 8);
|
|
Cdb6.AllocationLengthLsb = (UINT8) (sizeof (EFI_SCSI_INQUIRY_DATA) & 0xFF);
|
|
|
|
|
|
Packet.Timeout = EFI_TIMER_PERIOD_SECONDS (1);
|
|
Packet.Cdb = &Cdb6;
|
|
Packet.CdbLength = (UINT8) sizeof (Cdb6);
|
|
Packet.InDataBuffer = &(DevicePrivateData->InquiryData);
|
|
Packet.InTransferLength = sizeof (EFI_SCSI_INQUIRY_DATA);
|
|
|
|
Packet.SenseData = &(DevicePrivateData->ScsiSenseDataExt);
|
|
Packet.SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA_EXT);
|
|
|
|
Status = DevicePrivateData->ExtScsiPassThruPtr->PassThru (
|
|
DevicePrivateData->ExtScsiPassThruPtr,
|
|
TargetId,
|
|
Lun,
|
|
&Packet,
|
|
NULL
|
|
);
|
|
|
|
CopyMem (
|
|
InquiryData,
|
|
&(DevicePrivateData->InquiryData),
|
|
sizeof (EFI_SCSI_INQUIRY_DATA)
|
|
);
|
|
|
|
} else {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Provides identify information for the controller type.
|
|
|
|
This function is used by the IDE bus driver to get identify data. Data format
|
|
of Identify data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
|
|
instance.
|
|
@param[in,out] IdentifyData Pointer to a buffer for the identify data.
|
|
@param[in,out] IdentifyDataSize Pointer to the value for the identify data
|
|
size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading IdentifyData from device
|
|
@retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskInfoIdentify (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *IdentifyData,
|
|
IN OUT UINT32 *IdentifyDataSize
|
|
)
|
|
{
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_DISKINFO (This);
|
|
if (*IdentifyDataSize < IDENTIFY_TABLE_SIZE) {
|
|
*IdentifyDataSize = IDENTIFY_TABLE_SIZE;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
CopyMem (
|
|
IdentifyData,
|
|
&(DevicePrivateData->DeviceIdentifyDataRaw),
|
|
IDENTIFY_TABLE_SIZE
|
|
);
|
|
|
|
*IdentifyDataSize = IDENTIFY_TABLE_SIZE;
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
/**
|
|
Provides sense data information for the controller type.
|
|
|
|
This function is used by the IDE bus driver to get sense data.
|
|
Data format of Sense data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[in,out] SenseData Pointer to the SenseData.
|
|
@param[in,out] SenseDataSize Size of SenseData in bytes.
|
|
@param[out] SenseDataNumber Pointer to the value for the sense data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class.
|
|
@retval EFI_DEVICE_ERROR Error reading SenseData from device.
|
|
@retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskInfoSenseData (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *SenseData,
|
|
IN OUT UINT32 *SenseDataSize,
|
|
OUT UINT8 *SenseDataNumber
|
|
)
|
|
{
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_DISKINFO (This);
|
|
if (*SenseDataSize < sizeof (DevicePrivateData->ScsiSenseDataExt)) {
|
|
*SenseDataSize = sizeof (DevicePrivateData->ScsiSenseDataExt);
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
CopyMem (
|
|
SenseData,
|
|
&(DevicePrivateData->ScsiSenseDataExt),
|
|
sizeof (DevicePrivateData->ScsiSenseDataExt)
|
|
);
|
|
|
|
*SenseDataSize = sizeof (DevicePrivateData->ScsiSenseDataExt);
|
|
*SenseDataNumber = 1;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is used by the IDE bus driver to get controller information.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
|
|
@param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
|
|
|
|
@retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
|
|
@retval EFI_UNSUPPORTED This is not an IDE device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScsiDiskInfoWhichIde (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
OUT UINT32 *IdeChannel,
|
|
OUT UINT32 *IdeDevice
|
|
)
|
|
{
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Provides inquiry information for the controller type.
|
|
|
|
This function is used to get inquiry data. Data format
|
|
of Identify data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[in, out] InquiryData Pointer to a buffer for the inquiry data.
|
|
@param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading InquiryData from device
|
|
@retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
NvmeDiskInfoInquiry (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *InquiryData,
|
|
IN OUT UINT32 *InquiryDataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_PRIVATE_DATA *DevicePrivateData;
|
|
|
|
DevicePrivateData = DEVICE_PRIVATE_FROM_DISKINFO (This);
|
|
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
if (*InquiryDataSize >= sizeof (NVME_ADMIN_CONTROLLER_DATA)) {
|
|
Status = EFI_SUCCESS;
|
|
CopyMem (InquiryData, DevicePrivateData->NvmeAdminControllerData, sizeof (NVME_ADMIN_CONTROLLER_DATA));
|
|
}
|
|
*InquiryDataSize = sizeof (NVME_ADMIN_CONTROLLER_DATA);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Provides identify information for the controller type.
|
|
|
|
This function is used to get identify data. Data format
|
|
of Identify data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
|
|
instance.
|
|
@param[in, out] IdentifyData Pointer to a buffer for the identify data.
|
|
@param[in, out] IdentifyDataSize Pointer to the value for the identify data
|
|
size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading IdentifyData from device
|
|
@retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
NvmeDiskInfoIdentify (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *IdentifyData,
|
|
IN OUT UINT32 *IdentifyDataSize
|
|
)
|
|
{
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Provides sense data information for the controller type.
|
|
|
|
This function is used to get sense data.
|
|
Data format of Sense data is defined by the Interface GUID.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[in, out] SenseData Pointer to the SenseData.
|
|
@param[in, out] SenseDataSize Size of SenseData in bytes.
|
|
@param[out] SenseDataNumber Pointer to the value for the sense data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class.
|
|
@retval EFI_DEVICE_ERROR Error reading SenseData from device.
|
|
@retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
NvmeDiskInfoSenseData (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *SenseData,
|
|
IN OUT UINT32 *SenseDataSize,
|
|
OUT UINT8 *SenseDataNumber
|
|
)
|
|
{
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
|
|
/**
|
|
This function is used to get controller information.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
|
|
@param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
|
|
|
|
@retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
|
|
@retval EFI_UNSUPPORTED This is not an IDE device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
NvmeDiskInfoWhichIde (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
OUT UINT32 *IdeChannel,
|
|
OUT UINT32 *IdeDevice
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
According the Bus, Device, Function to check this controller is in Port Number Map table or not.
|
|
|
|
@param Bus PCI bus number
|
|
@param Device PCI device number
|
|
@param Function PCI function number
|
|
|
|
@return TRUE This is a on board PCI device.
|
|
@return FALSE Not on board device.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsOnBoardPciDevice (
|
|
IN UINT32 Bus,
|
|
IN UINT32 Device,
|
|
IN UINT32 Function
|
|
)
|
|
{
|
|
PORT_NUMBER_MAP *PortMappingTable;
|
|
PORT_NUMBER_MAP EndEntry;
|
|
UINTN NoPorts;
|
|
|
|
ZeroMem (&EndEntry, sizeof (PORT_NUMBER_MAP));
|
|
|
|
PortMappingTable = (PORT_NUMBER_MAP *)PcdGetPtr (PcdPortNumberMapTable);
|
|
|
|
NoPorts = 0;
|
|
while (CompareMem (&EndEntry, &PortMappingTable[NoPorts], sizeof (PORT_NUMBER_MAP)) != 0) {
|
|
if ((PortMappingTable[NoPorts].Bus == Bus) &&
|
|
(PortMappingTable[NoPorts].Device == Device) &&
|
|
(PortMappingTable[NoPorts].Function == Function)) {
|
|
return TRUE;
|
|
}
|
|
NoPorts++;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
check if the controller handle is already exist in current private list.
|
|
|
|
@param Bus PCI bus number
|
|
@param Device PCI device number
|
|
@param Function PCI function number
|
|
|
|
@return TRUE This is a on board PCI device.
|
|
@return FALSE Not on board device.
|
|
**/
|
|
BOOLEAN
|
|
IsControllerAlreadyChecked (
|
|
IN UINT32 Bus,
|
|
IN UINT32 Device,
|
|
IN UINT32 Function
|
|
)
|
|
{
|
|
RAID_CONTROLLER_PRIVATE_DATA *RaidControllerPrivateData;
|
|
LIST_ENTRY *Link;
|
|
|
|
//
|
|
// avoid add the same controller to private data
|
|
//
|
|
for (Link = GetFirstNode (&mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead);
|
|
!IsNull (&mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead, Link);
|
|
Link = GetNextNode (&mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead, Link)) {
|
|
RaidControllerPrivateData = (RAID_CONTROLLER_PRIVATE_DATA *)Link;
|
|
if (RaidControllerPrivateData->PciBus == Bus &&
|
|
RaidControllerPrivateData->PciDevice == Device &&
|
|
RaidControllerPrivateData->PciFunction == Function) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Sacn all SATA controller.
|
|
|
|
@retval EFI_SUCCESS Scan SATA controller successfully.
|
|
@retval Other Scan SATA controller failed.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ScanAllSataController (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleIndex;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINTN Seg;
|
|
UINTN Bus;
|
|
UINTN Device;
|
|
UINTN Function;
|
|
UINT8 SataClassCReg[3];
|
|
RAID_CONTROLLER_PRIVATE_DATA *RaidControllerPrivateData;
|
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiPciIoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[HandleIndex],
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **)&PciIo
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
Status = PciIo->GetLocation (
|
|
PciIo,
|
|
&Seg,
|
|
&Bus,
|
|
&Device,
|
|
&Function
|
|
);
|
|
if (Status != EFI_SUCCESS ||
|
|
(!IsOnBoardPciDevice((UINT32)Bus, (UINT32)Device, (UINT32)Function) && PciIo->RomImage != NULL)) {
|
|
continue;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
PCI_CLASSCODE_OFFSET,
|
|
3,
|
|
SataClassCReg
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Test whether the controller belongs to RAID type
|
|
//
|
|
if (SataClassCReg[2] == PCI_CLASS_MASS_STORAGE && SataClassCReg[1] == PCI_CLASS_MASS_STORAGE_RAID &&
|
|
(!IsControllerAlreadyChecked((UINT32)Bus, (UINT32)Device, (UINT32)Function))) {
|
|
//
|
|
// Current DelayuefiRaidOprom driver will only install gUefiRaidOpromReadyGuid until all RAID controllers to be connected and
|
|
// a correspondant AtaPassthru being installed. However, INTEL Roaming device,
|
|
// despite it has RAID classcode, neither AhciBus driver nor INTEL RST driver will install AtaPassthru for it.
|
|
// Thus cause gUefiRaidOpromReadyGuid never being installed.
|
|
// Current workaround for this special device is to check its BAR, if no BAR exist, which currently only
|
|
// happen on INTEL ROAMING devices, it will not be stored to RaidControllerPrivateData, thus after the real
|
|
// RAID controller connected, gUefiRaidOpromReadyGuid will be installed.
|
|
//
|
|
Status = PciIo->GetBarAttributes (PciIo, EFI_AHCI_BAR_INDEX, NULL, (VOID**) &Resources);
|
|
if (EFI_ERROR(Status)) {
|
|
FreePool (HandleBuffer);
|
|
return Status;
|
|
}
|
|
|
|
RaidControllerPrivateData = AllocateZeroPool (sizeof (RAID_CONTROLLER_PRIVATE_DATA));
|
|
if (RaidControllerPrivateData == NULL) {
|
|
FreePool (HandleBuffer);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
RaidControllerPrivateData->RaidControllerHandle = HandleBuffer[HandleIndex];
|
|
RaidControllerPrivateData->PciBus = Bus;
|
|
RaidControllerPrivateData->PciDevice = Device;
|
|
RaidControllerPrivateData->PciFunction = Function;
|
|
RaidControllerPrivateData->Checked = FALSE;
|
|
|
|
InsertTailList (
|
|
&(mDelayUefiRaidOpromPrivate->RaidControllerInfoListHead),
|
|
&RaidControllerPrivateData->Link
|
|
);
|
|
|
|
mDelayUefiRaidOpromPrivate->RaidControllerRemain += 1;
|
|
}
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
|
|
mDelayUefiRaidOpromPrivate->RaidControllerInfoGet = TRUE;
|
|
|
|
return Status;
|
|
}
|
|
|