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