--- /dev/null
+/** @file\r
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI\r
+ mode at PEI phase.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "AhciPei.h"\r
+\r
+#include <Guid/S3StorageDeviceInitList.h>\r
+\r
+#include <Library/LockBoxLib.h>\r
+\r
+/**\r
+ Collect the ports that need to be enumerated on a controller for S3 phase.\r
+\r
+ @param[in] HcDevicePath Device path of the controller.\r
+ @param[in] HcDevicePathLength Length of the device path specified by\r
+ HcDevicePath.\r
+ @param[out] PortBitMap Bitmap that indicates the ports that need\r
+ to be enumerated on the controller.\r
+\r
+ @retval The number of ports that need to be enumerated.\r
+\r
+**/\r
+UINT8\r
+AhciS3GetEumeratePorts (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *HcDevicePath,\r
+ IN UINTN HcDevicePathLength,\r
+ OUT UINT32 *PortBitMap\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DummyData;\r
+ UINTN S3InitDevicesLength;\r
+ EFI_DEVICE_PATH_PROTOCOL *S3InitDevices;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
+ UINTN DevicePathInstLength;\r
+ BOOLEAN EntireEnd;\r
+ SATA_DEVICE_PATH *SataDeviceNode;\r
+\r
+ *PortBitMap = 0;\r
+\r
+ //\r
+ // From the LockBox, get the list of device paths for devices need to be\r
+ // initialized in S3.\r
+ //\r
+ S3InitDevices = NULL;\r
+ S3InitDevicesLength = sizeof (DummyData);\r
+ EntireEnd = FALSE;\r
+ Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, &DummyData, &S3InitDevicesLength);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return 0;\r
+ } else {\r
+ S3InitDevices = AllocatePool (S3InitDevicesLength);\r
+ if (S3InitDevices == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Status = RestoreLockBox (&gS3StorageDeviceInitListGuid, S3InitDevices, &S3InitDevicesLength);\r
+ if (EFI_ERROR (Status)) {\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ if (S3InitDevices == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Only enumerate the ports that exist in the device list.\r
+ //\r
+ do {\r
+ //\r
+ // Fetch the size of current device path instance.\r
+ //\r
+ Status = GetDevicePathInstanceSize (\r
+ S3InitDevices,\r
+ &DevicePathInstLength,\r
+ &EntireEnd\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ DevicePathInst = S3InitDevices;\r
+ S3InitDevices = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN) S3InitDevices + DevicePathInstLength);\r
+\r
+ if (HcDevicePathLength >= DevicePathInstLength) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Compare the device paths to determine if the device is managed by this\r
+ // controller.\r
+ //\r
+ if (CompareMem (\r
+ DevicePathInst,\r
+ HcDevicePath,\r
+ HcDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)\r
+ ) == 0) {\r
+ //\r
+ // Get the port number.\r
+ //\r
+ while (DevicePathInst->Type != END_DEVICE_PATH_TYPE) {\r
+ if ((DevicePathInst->Type == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathInst->SubType == MSG_SATA_DP)) {\r
+ SataDeviceNode = (SATA_DEVICE_PATH *) DevicePathInst;\r
+ //\r
+ // For now, the driver only support upto AHCI_MAX_PORTS ports and\r
+ // devices directly connected to a HBA.\r
+ //\r
+ if ((SataDeviceNode->HBAPortNumber >= AHCI_MAX_PORTS) ||\r
+ (SataDeviceNode->PortMultiplierPortNumber != 0xFFFF)) {\r
+ break;\r
+ }\r
+ *PortBitMap |= (UINT32)BIT0 << SataDeviceNode->HBAPortNumber;\r
+ break;\r
+ }\r
+ DevicePathInst = NextDevicePathNode (DevicePathInst);\r
+ }\r
+ }\r
+ } while (!EntireEnd);\r
+\r
+ //\r
+ // Return the number of ports need to be enumerated on this controller.\r
+ //\r
+ return AhciGetNumberOfPortsFromMap (*PortBitMap);\r
+}\r