responder: add state effecter for system power off

Add a handler to respond to a set effecter meant to request the BMC to
turn the system power off.

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I03c974cd34a18c84a7a9bd81412cc1844b195694
diff --git a/libpldm/states.h b/libpldm/states.h
index a64a7ae..ca20acd 100644
--- a/libpldm/states.h
+++ b/libpldm/states.h
@@ -11,6 +11,7 @@
  */
 enum pldm_state_set_ids {
 	PLDM_BOOT_PROGRESS_STATE = 196,
+	PLDM_SYSTEM_POWER_STATE = 260,
 };
 
 /** @brief PLDM enums for the boot progress state set
@@ -20,6 +21,12 @@
 	PLDM_BOOT_COMPLETED = 2,
 };
 
+/** @brief PLDM enums for system power states
+ */
+enum pldm_system_power_states {
+	PLDM_OFF_SOFT_GRACEFUL = 9,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 9db93ce..ec168f4 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -72,7 +72,9 @@
           {PLDM_BOOT_COMPLETED,
            "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
            "BootComplete"s}}},
-    };
+        {PLDM_SYSTEM_POWER_STATE,
+         {{PLDM_OFF_SOFT_GRACEFUL,
+           "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
     using namespace phosphor::logging;
     using namespace pldm::responder::pdr;
     using namespace pldm::responder::effecter::dbus_mapping;
@@ -168,6 +170,50 @@
                      return PLDM_ERROR;
                  }
                  return PLDM_SUCCESS;
+             }},
+            {PLDM_SYSTEM_POWER_STATE,
+             [&](const std::string& objPath, const uint8_t currState) {
+                 auto stateSet =
+                     stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
+                 if (stateSet == stateNumToDbusProp.end())
+                 {
+                     log<level::ERR>("Couldn't find D-Bus mapping for "
+                                     "PLDM_SYSTEM_POWER_STATE",
+                                     entry("EFFECTER_ID=%d", effecterId));
+                     return PLDM_ERROR;
+                 }
+                 auto iter = stateSet->second.find(
+                     stateField[currState].effecter_state);
+                 if (iter == stateSet->second.end())
+                 {
+                     log<level::ERR>(
+                         "Invalid state field passed or field not "
+                         "found for PLDM_SYSTEM_POWER_STATE",
+                         entry("EFFECTER_ID=%d", effecterId),
+                         entry("FIELD=%d",
+                               stateField[currState].effecter_state),
+                         entry("OBJECT_PATH=%s", objPath.c_str()));
+                     return PLDM_ERROR_INVALID_DATA;
+                 }
+                 auto dbusProp = "RequestedPowerTransition";
+                 std::variant<std::string> value{
+                     std::get<std::string>(iter->second)};
+                 auto dbusInterface = "xyz.openbmc_project.State.Chassis";
+                 try
+                 {
+                     dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
+                                              dbusInterface, value);
+                 }
+                 catch (const std::exception& e)
+                 {
+                     log<level::ERR>("Error setting property",
+                                     entry("ERROR=%s", e.what()),
+                                     entry("PROPERTY=%s", dbusProp),
+                                     entry("INTERFACE=%s", dbusInterface),
+                                     entry("PATH=%s", objPath.c_str()));
+                     return PLDM_ERROR;
+                 }
+                 return PLDM_SUCCESS;
              }}};
 
     int rc = PLDM_SUCCESS;