Add Port Status information for Fabric Port

This commit is to add status and health information to Fabric Port like
other Redfish resources which implement State/Health and map them to
Present/Functional respectfully. State / Health of the Port is useful
information for inventory on a GUI/Debug/etc

If the `xyz.openbmc_project.Inventory.Item` interface does not exist,
the state status property is set to default "Enabled".

If the `xyz.openbmc_project.State.Decorator.OperationalStatus`
interface does not exist, the health status property is set to
default "OK".

Tested:
  - Redfish Validator passed
  - Check status from GET Port output

```
% curl -k -X GET https://${bmc}:18080/redfish/v1/Systems/system/FabricAdapters/disk_backplane0/Ports/dp0_connector4
{
  "@odata.id": "/redfish/v1/Systems/system/FabricAdapters/disk_backplane0/Ports/dp0_connector4",
  "@odata.type": "#Port.v1_7_0.Port",
  "Id": "dp0_connector4",
  "Location": {
    "PartLocation": {
      "ServiceLabel": "U78DA.ND0.WZS003T-P1-T4"
    }
  },
  "Name": "dp0_connector4",
  "Status": {
    "Health": "OK",
    "State": "Enabled"
  }
}
```

Change-Id: Ibb625f2ef1378f77c9520426d2687e305b4f8be5
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
diff --git a/docs/Redfish.md b/docs/Redfish.md
index b73ceb1..41a6b9d 100644
--- a/docs/Redfish.md
+++ b/docs/Redfish.md
@@ -866,6 +866,7 @@
 #### Port
 
 - Location
+- Status
 
 ### /redfish/v1/Systems/system/LogServices/
 
diff --git a/redfish-core/lib/fabric_ports.hpp b/redfish-core/lib/fabric_ports.hpp
index 854b398..ad6b75e 100644
--- a/redfish-core/lib/fabric_ports.hpp
+++ b/redfish-core/lib/fabric_ports.hpp
@@ -9,6 +9,7 @@
 #include "dbus_singleton.hpp"
 #include "dbus_utility.hpp"
 #include "error_messages.hpp"
+#include "generated/enums/resource.hpp"
 #include "http_request.hpp"
 #include "human_sort.hpp"
 #include "logging.hpp"
@@ -67,6 +68,69 @@
         std::bind_front(afterGetFabricPortLocation, asyncResp));
 }
 
+inline void afterGetFabricPortState(
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+    const boost::system::error_code& ec, bool present)
+{
+    if (ec)
+    {
+        if (ec.value() != EBADR)
+        {
+            BMCWEB_LOG_ERROR("DBUS response error for State, ec {}",
+                             ec.value());
+            messages::internalError(asyncResp->res);
+        }
+        return;
+    }
+    if (!present)
+    {
+        asyncResp->res.jsonValue["Status"]["State"] = resource::State::Absent;
+    }
+}
+
+inline void getFabricPortState(
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+    const std::string& portPath, const std::string& serviceName)
+{
+    asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
+    dbus::utility::getProperty<bool>(
+        serviceName, portPath, "xyz.openbmc_project.Inventory.Item", "Present",
+        std::bind_front(afterGetFabricPortState, asyncResp));
+}
+
+inline void afterGetFabricPortHealth(
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+    const boost::system::error_code& ec, bool functional)
+{
+    if (ec)
+    {
+        if (ec.value() != EBADR)
+        {
+            BMCWEB_LOG_ERROR("DBUS response error for Health, ec {}",
+                             ec.value());
+            messages::internalError(asyncResp->res);
+        }
+        return;
+    }
+
+    if (!functional)
+    {
+        asyncResp->res.jsonValue["Status"]["Health"] =
+            resource::Health::Critical;
+    }
+}
+
+inline void getFabricPortHealth(
+    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+    const std::string& portPath, const std::string& serviceName)
+{
+    asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
+    dbus::utility::getProperty<bool>(
+        serviceName, portPath,
+        "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
+        std::bind_front(afterGetFabricPortHealth, asyncResp));
+}
+
 inline void getFabricPortProperties(
     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
     const std::string& systemName, const std::string& adapterId,
@@ -90,7 +154,10 @@
                             systemName, adapterId, portId);
     asyncResp->res.jsonValue["Id"] = portId;
     asyncResp->res.jsonValue["Name"] = "Fabric Port";
+
     getFabricPortLocation(asyncResp, portPath, serviceName);
+    getFabricPortState(asyncResp, portPath, serviceName);
+    getFabricPortHealth(asyncResp, portPath, serviceName);
 }
 
 inline void afterGetValidFabricPortPath(