/** @file | |
Collect IDE information from Native EFI Driver | |
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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 ; | |
} |