mirror of https://github.com/acidanthera/audk.git
318 lines
11 KiB
C
318 lines
11 KiB
C
/** @file
|
|
Collect IDE information from Native EFI Driver
|
|
|
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions
|
|
of the BSD License which accompanies this distribution. The
|
|
full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "LegacyBiosInterface.h"
|
|
|
|
BOOLEAN mIdeDataBuiltFlag = FALSE;
|
|
|
|
/**
|
|
Collect IDE Inquiry data from the IDE disks
|
|
|
|
@param Private Legacy BIOS Instance data
|
|
@param HddInfo Hdd Information
|
|
@param Flag Reconnect IdeController or not
|
|
|
|
@retval EFI_SUCCESS It should always work.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
LegacyBiosBuildIdeData (
|
|
IN LEGACY_BIOS_INSTANCE *Private,
|
|
IN HDD_INFO **HddInfo,
|
|
IN UINT16 Flag
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE IdeController;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN Index;
|
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
|
UINT32 IdeChannel;
|
|
UINT32 IdeDevice;
|
|
UINT32 Size;
|
|
UINT8 *InquiryData;
|
|
UINT32 InquiryDataSize;
|
|
HDD_INFO *LocalHddInfo;
|
|
UINT32 PciIndex;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
|
|
PCI_DEVICE_PATH *PciDevicePath;
|
|
|
|
//
|
|
// Only build data once
|
|
// We have a problem with GetBbsInfo in that it can be invoked two
|
|
// places. Once in BDS, when all EFI drivers are connected and once in
|
|
// LegacyBoot after all EFI drivers are disconnected causing this routine
|
|
// to hang. In LegacyBoot this function is also called before EFI drivers
|
|
// are disconnected.
|
|
// Cases covered
|
|
// GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
|
|
// GetBbsInfo not invoked in BDS. First invocation of this function
|
|
// proceeds normally and second via GetBbsInfo ignored.
|
|
//
|
|
PciDevicePath = NULL;
|
|
LocalHddInfo = *HddInfo;
|
|
Status = Private->LegacyBiosPlatform->GetPlatformHandle (
|
|
Private->LegacyBiosPlatform,
|
|
EfiGetPlatformIdeHandle,
|
|
0,
|
|
&HandleBuffer,
|
|
&HandleCount,
|
|
(VOID *) &LocalHddInfo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
IdeController = HandleBuffer[0];
|
|
//
|
|
// Force IDE drive spin up!
|
|
//
|
|
if (Flag != 0) {
|
|
gBS->DisconnectController (
|
|
IdeController,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
gBS->ConnectController (IdeController, NULL, NULL, FALSE);
|
|
|
|
//
|
|
// Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
|
|
// And GetIdeHandle will switch to Legacy mode, if required.
|
|
//
|
|
Private->LegacyBiosPlatform->GetPlatformHandle (
|
|
Private->LegacyBiosPlatform,
|
|
EfiGetPlatformIdeHandle,
|
|
0,
|
|
&HandleBuffer,
|
|
&HandleCount,
|
|
(VOID *) &LocalHddInfo
|
|
);
|
|
}
|
|
|
|
mIdeDataBuiltFlag = TRUE;
|
|
|
|
//
|
|
// Get Identity command from all drives
|
|
//
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiDiskInfoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
Private->IdeDriveCount = (UINT8) HandleCount;
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiDiskInfoProtocolGuid,
|
|
(VOID **) &DiskInfo
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
|
|
//
|
|
// Locate which PCI device
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID *) &DevicePath
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DevicePathNode = DevicePath;
|
|
while (!IsDevicePathEnd (DevicePathNode)) {
|
|
TempDevicePathNode = NextDevicePathNode (DevicePathNode);
|
|
if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
|
|
( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
|
|
( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
|
|
( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
|
|
PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
|
|
break;
|
|
}
|
|
DevicePathNode = NextDevicePathNode (DevicePathNode);
|
|
}
|
|
|
|
if (PciDevicePath == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Find start of PCI device in HddInfo. The assumption of the data
|
|
// structure is 2 controllers(channels) per PCI device and each
|
|
// controller can have 2 drives(devices).
|
|
// HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
|
|
// HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
|
|
// HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
|
|
// HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
|
|
// @bug eventually need to pass in max number of entries
|
|
// for end of for loop
|
|
//
|
|
for (PciIndex = 0; PciIndex < 8; PciIndex++) {
|
|
if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
|
|
(PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
|
|
) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (PciIndex == 8) {
|
|
continue;
|
|
}
|
|
|
|
Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
|
|
if (!EFI_ERROR (Status)) {
|
|
Size = sizeof (ATAPI_IDENTIFY);
|
|
DiskInfo->Identify (
|
|
DiskInfo,
|
|
&LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
|
|
&Size
|
|
);
|
|
if (IdeChannel == 0) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
|
|
} else if (IdeChannel == 1) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
|
|
}
|
|
|
|
InquiryData = NULL;
|
|
InquiryDataSize = 0;
|
|
Status = DiskInfo->Inquiry (
|
|
DiskInfo,
|
|
NULL,
|
|
&InquiryDataSize
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
InquiryData = (UINT8 *) AllocatePool (
|
|
InquiryDataSize
|
|
);
|
|
if (InquiryData != NULL) {
|
|
Status = DiskInfo->Inquiry (
|
|
DiskInfo,
|
|
InquiryData,
|
|
&InquiryDataSize
|
|
);
|
|
}
|
|
} else {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// If ATAPI device then Inquiry will pass and ATA fail.
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
ASSERT (InquiryData != NULL);
|
|
//
|
|
// If IdeDevice = 0 then set master bit, else slave bit
|
|
//
|
|
if (IdeDevice == 0) {
|
|
if ((InquiryData[0] & 0x1f) == 0x05) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
|
|
} else if ((InquiryData[0] & 0x1f) == 0x00) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
|
|
}
|
|
} else {
|
|
if ((InquiryData[0] & 0x1f) == 0x05) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
|
|
} else if ((InquiryData[0] & 0x1f) == 0x00) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
|
|
}
|
|
}
|
|
FreePool (InquiryData);
|
|
} else {
|
|
if (IdeDevice == 0) {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
|
|
} else {
|
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HandleBuffer != NULL) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
If the IDE channel is in compatibility (legacy) mode, remove all
|
|
PCI I/O BAR addresses from the controller.
|
|
|
|
@param IdeController The handle of target IDE controller
|
|
|
|
|
|
**/
|
|
VOID
|
|
InitLegacyIdeController (
|
|
IN EFI_HANDLE IdeController
|
|
)
|
|
{
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT32 IOBarClear;
|
|
EFI_STATUS Status;
|
|
PCI_TYPE00 PciData;
|
|
|
|
//
|
|
// If the IDE channel is in compatibility (legacy) mode, remove all
|
|
// PCI I/O BAR addresses from the controller. Some software gets
|
|
// confused if an IDE controller is in compatibility (legacy) mode
|
|
// and has PCI I/O resources allocated
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
IdeController,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **)&PciIo
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return ;
|
|
}
|
|
|
|
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData);
|
|
if (EFI_ERROR (Status)) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Check whether this is IDE
|
|
//
|
|
if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) ||
|
|
(PciData.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Clear bar for legacy IDE
|
|
//
|
|
IOBarClear = 0x00;
|
|
if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_PNE) == 0) {
|
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
|
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
|
|
}
|
|
if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_SNE) == 0) {
|
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
|
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
|
|
}
|
|
|
|
return ;
|
|
}
|