Implement chassis set power restore policy command

Implement the IPMI set power restore policy command 0x06.
This command can be used to configure the power restore policy.
This configuration parameter is kept in nonvolatile storage.
The power restore policy determines how the system or chassis
behaves when AC power returns after an AC power loss

Tested:
Run the below command to check the current Power Restore Policy:
ipmitool -H <IP> -P 0penBmc -I lanplus chassis status

Run the below command to change it:
ipmitool -H <IP> -P 0penBmc -I lanplus chassis policy always-off

Change-Id: I224912890f9a9e8b4dc98f840cd6f223c9f7dfe5
Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
diff --git a/chassishandler.cpp b/chassishandler.cpp
index 6002e7a..bfc079d 100644
--- a/chassishandler.cpp
+++ b/chassishandler.cpp
@@ -775,6 +775,10 @@
     {RestorePolicy::Policy::Restore, 0x01},
     {RestorePolicy::Policy::AlwaysOn, 0x02}};
 
+static constexpr uint8_t noChange = 0x03;
+static constexpr uint8_t allSupport = 0x01 | 0x02 | 0x04;
+static constexpr uint8_t policyBitMask = 0x07;
+static constexpr uint8_t setPolicyReqLen = 1;
 } // namespace power_policy
 
 //----------------------------------------------------------------------
@@ -1616,6 +1620,88 @@
     return rc;
 }
 
+ipmi_ret_t ipmi_chassis_set_power_restore_policy(
+    ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
+    ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
+{
+    auto* reqptr = reinterpret_cast<uint8_t*>(request);
+    auto* resptr = reinterpret_cast<uint8_t*>(response);
+    uint8_t reqPolicy = 0;
+
+    power_policy::DbusValue value =
+        power_policy::RestorePolicy::Policy::AlwaysOff;
+
+    if (*data_len != power_policy::setPolicyReqLen)
+    {
+        phosphor::logging::log<level::ERR>("Unsupported request length",
+                                           entry("LEN=0x%x", *data_len));
+        *data_len = 0;
+        return IPMI_CC_REQ_DATA_LEN_INVALID;
+    }
+
+    reqPolicy = *reqptr & power_policy::policyBitMask;
+    if (reqPolicy > power_policy::noChange)
+    {
+        phosphor::logging::log<level::ERR>("Reserved request parameter",
+                                           entry("REQ=0x%x", reqPolicy));
+        *data_len = 0;
+        return IPMI_CC_PARM_NOT_SUPPORTED;
+    }
+
+    if (reqPolicy == power_policy::noChange)
+    {
+        // just return the supported policy
+        *resptr = power_policy::allSupport;
+        *data_len = power_policy::setPolicyReqLen;
+        return IPMI_CC_OK;
+    }
+
+    for (auto const& it : power_policy::dbusToIpmi)
+    {
+        if (it.second == reqPolicy)
+        {
+            value = it.first;
+            break;
+        }
+    }
+
+    try
+    {
+        const settings::Path& powerRestoreSetting =
+            chassis::internal::cache::objects.map
+                .at(chassis::internal::powerRestoreIntf)
+                .front();
+        sdbusplus::message::variant<std::string> property =
+            convertForMessage(value);
+
+        auto method = chassis::internal::dbus.new_method_call(
+            chassis::internal::cache::objects
+                .service(powerRestoreSetting,
+                         chassis::internal::powerRestoreIntf)
+                .c_str(),
+            powerRestoreSetting.c_str(), ipmi::PROP_INTF, "Set");
+
+        method.append(chassis::internal::powerRestoreIntf, "PowerRestorePolicy",
+                      property);
+        auto reply = chassis::internal::dbus.call(method);
+        if (reply.is_method_error())
+        {
+            phosphor::logging::log<level::ERR>("Unspecified Error");
+            *data_len = 0;
+            return IPMI_CC_UNSPECIFIED_ERROR;
+        }
+    }
+    catch (InternalFailure& e)
+    {
+        report<InternalFailure>();
+        *data_len = 0;
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+
+    *data_len = power_policy::setPolicyReqLen;
+    return IPMI_CC_OK;
+}
+
 void register_netfn_chassis_functions()
 {
     createIdentifyTimer();
@@ -1652,4 +1738,9 @@
     // <Get POH Counter>
     ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_POH_COUNTER, NULL,
                            ipmiGetPOHCounter, PRIVILEGE_USER);
+
+    // <Set Power Restore Policy>
+    ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_RESTORE_POLICY, NULL,
+                           ipmi_chassis_set_power_restore_policy,
+                           PRIVILEGE_OPERATOR);
 }