/** @file Collect IDE information from Native EFI Driver Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
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 ; }