Update the Get and Set Processor Error Config commands

This change
   1. Converts the commands to the new API
   2. Uses a new settings interface for the data
   3. Gets processor presence from the inventory
   4. Makes the last byte of the Set command optional which BIOS
      expects.

Tested:
ipmitool raw 0x30 0x9a
 00 3f 40 40 c0 c0 00
ipmitool raw 0x30 0x9b 3 0
ipmitool raw 0x30 0x9a
 03 3f 40 40 c0 c0 00

Change-Id: I44519016a6f9e784f6fd9da4ff1a64805f82ebd0
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/include/oemcommands.hpp b/include/oemcommands.hpp
index d2fb116..f4f228f 100644
--- a/include/oemcommands.hpp
+++ b/include/oemcommands.hpp
@@ -197,6 +197,13 @@
     targetOEMEWS = 0x4,
 };
 
+enum class CPUStatus
+{
+    disabled = 0x0,
+    enabled = 0x1,
+    notPresent = 0x3,
+};
+
 #pragma pack(push, 1)
 struct GUIDData
 {
@@ -249,46 +256,6 @@
     uint8_t data[maxBIOSIDLength];
 };
 
-struct SetProcessorErrConfigReq
-{
-    uint8_t resetCfg; // Reset Configuration
-                      //   [0]:   CATERR Reset Enabled
-                      //               0b: Disabled
-                      //               1b: Enabled
-                      //   [1]:   ERR2 Reset Enabled
-                      //               0b: Disabled
-                      //               1b: Enabled
-                      //   [7:2]: Reserved
-    uint8_t reserved; // Reserved
-    uint8_t
-        resetErrorOccurrenceCounts; // Reset Error Occurrence Counts
-                                    //[0]: Reset CPU Error Counts
-                                    //    0b: Keep CPU Error Counts
-                                    //    1b: Reset all CPU Error Counts to zero
-                                    //[7:1]: Reserved
-};
-
-struct GetProcessorErrConfigRes
-{
-    uint8_t resetCfg;             // Reset Configuration
-                                  //   [0]:   CATERR Reset Enabled
-                                  //               0b: Disabled
-                                  //               1b: Enabled
-                                  //   [1]:   ERR2 Reset Enabled
-                                  //               0b: Disabled
-                                  //               1b: Enabled
-                                  //   [7:2]: Reserved
-    uint8_t reserved;             // Reserved
-    char caterrStatus[maxCPUNum]; // for all CPUs including the non-legacy
-                                  // socket CPU CPU CATERR (Core Error)
-                                  // occurrence
-                                  //     [5:0]: Error Occurrence Count
-                                  //     [7:6]: CPU Status
-                                  //                 00b: Disabled
-                                  //                 01b: Enabled
-                                  //                 11b: Not Present
-};
-
 struct GetOEMShutdownPolicyRes
 {
     uint8_t policy;
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index 8a7b443..b612948 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -480,88 +480,133 @@
     return IPMI_CC_OK;
 }
 
-ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
-                                        ipmi_request_t request,
-                                        ipmi_response_t response,
-                                        ipmi_data_len_t dataLen,
-                                        ipmi_context_t context)
+static bool cpuPresent(const std::string& cpuName)
 {
-    GetProcessorErrConfigRes* resp =
-        reinterpret_cast<GetProcessorErrConfigRes*>(response);
-
-    if (*dataLen != 0)
+    static constexpr const char* cpuPresencePathPrefix =
+        "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
+    static constexpr const char* cpuPresenceIntf =
+        "xyz.openbmc_project.Inventory.Item";
+    std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
+    std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
+    try
     {
-        *dataLen = 0;
-        return IPMI_CC_REQ_DATA_LEN_INVALID;
+        auto service =
+            ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
+
+        ipmi::Value result = ipmi::getDbusProperty(
+            *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
+        return std::get<bool>(result);
+    }
+    catch (const std::exception& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            "Cannot find processor presence",
+            phosphor::logging::entry("NAME=%s", cpuName.c_str()));
+        return false;
+    }
+}
+
+ipmi::RspType<bool,    // CATERR Reset Enabled
+              bool,    // ERR2 Reset Enabled
+              uint6_t, // reserved
+              uint8_t, // reserved, returns 0x3F
+              uint6_t, // CPU1 CATERR Count
+              uint2_t, // CPU1 Status
+              uint6_t, // CPU2 CATERR Count
+              uint2_t, // CPU2 Status
+              uint6_t, // CPU3 CATERR Count
+              uint2_t, // CPU3 Status
+              uint6_t, // CPU4 CATERR Count
+              uint2_t, // CPU4 Status
+              uint8_t  // Crashdump Count
+              >
+    ipmiOEMGetProcessorErrConfig()
+{
+    bool resetOnCATERR = false;
+    bool resetOnERR2 = false;
+    uint6_t cpu1CATERRCount = 0;
+    uint6_t cpu2CATERRCount = 0;
+    uint6_t cpu3CATERRCount = 0;
+    uint6_t cpu4CATERRCount = 0;
+    uint8_t crashdumpCount = 0;
+    uint2_t cpu1Status =
+        cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
+    uint2_t cpu2Status =
+        cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
+    uint2_t cpu3Status =
+        cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
+    uint2_t cpu4Status =
+        cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
+
+    std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
+    try
+    {
+        auto service = ipmi::getService(*busp, processorErrConfigIntf,
+                                        processorErrConfigObjPath);
+
+        ipmi::PropertyMap result = ipmi::getAllDbusProperties(
+            *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
+        resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
+        resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
+        cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
+        cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
+        cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
+        cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
+        crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
+    }
+    catch (const std::exception& e)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Failed to fetch processor error config",
+            phosphor::logging::entry("ERROR=%s", e.what()));
+        return ipmi::responseUnspecifiedError();
     }
 
-    std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
-    std::string service =
-        getService(*dbus, processorErrConfigIntf, processorErrConfigObjPath);
-    Value variant = getDbusProperty(*dbus, service, processorErrConfigObjPath,
-                                    processorErrConfigIntf, "ResetCfg");
-    resp->resetCfg = std::get<uint8_t>(variant);
+    return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
+                                 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
+                                 cpu2Status, cpu3CATERRCount, cpu3Status,
+                                 cpu4CATERRCount, cpu4Status, crashdumpCount);
+}
 
-    std::vector<uint8_t> caterrStatus;
-    sdbusplus::message::variant<std::vector<uint8_t>> message;
-
-    auto method =
-        dbus->new_method_call(service.c_str(), processorErrConfigObjPath,
-                              "org.freedesktop.DBus.Properties", "Get");
-
-    method.append(processorErrConfigIntf, "CATERRStatus");
-    auto reply = dbus->call(method);
+ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
+    bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
+    std::optional<bool> clearCPUErrorCount,
+    std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
+{
+    std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
 
     try
     {
-        reply.read(message);
-        caterrStatus = std::get<std::vector<uint8_t>>(message);
+        auto service = ipmi::getService(*busp, processorErrConfigIntf,
+                                        processorErrConfigObjPath);
+        ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
+                              processorErrConfigIntf, "ResetOnCATERR",
+                              resetOnCATERR);
+        ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
+                              processorErrConfigIntf, "ResetOnERR2",
+                              resetOnERR2);
+        if (clearCPUErrorCount.value_or(false))
+        {
+            ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
+                                  processorErrConfigIntf, "ErrorCountCPU1", 0);
+            ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
+                                  processorErrConfigIntf, "ErrorCountCPU2", 0);
+        }
+        if (clearCrashdumpCount.value_or(false))
+        {
+            ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
+                                  processorErrConfigIntf, "CrashdumpCount", 0);
+        }
     }
-    catch (sdbusplus::exception_t&)
+    catch (std::exception& e)
     {
         phosphor::logging::log<phosphor::logging::level::ERR>(
-            "ipmiOEMGetProcessorErrConfig: error on dbus",
-            phosphor::logging::entry("PRORPERTY=CATERRStatus"),
-            phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
-            phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
-        return IPMI_CC_UNSPECIFIED_ERROR;
+            "Failed to set processor error config",
+            phosphor::logging::entry("EXCEPTION=%s", e.what()));
+        return ipmi::responseUnspecifiedError();
     }
 
-    size_t len =
-        maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
-    caterrStatus.resize(len);
-    std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
-    *dataLen = sizeof(GetProcessorErrConfigRes);
-
-    return IPMI_CC_OK;
-}
-
-ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
-                                        ipmi_request_t request,
-                                        ipmi_response_t response,
-                                        ipmi_data_len_t dataLen,
-                                        ipmi_context_t context)
-{
-    SetProcessorErrConfigReq* req =
-        reinterpret_cast<SetProcessorErrConfigReq*>(request);
-
-    if (*dataLen != sizeof(SetProcessorErrConfigReq))
-    {
-        *dataLen = 0;
-        return IPMI_CC_REQ_DATA_LEN_INVALID;
-    }
-    std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
-    std::string service =
-        getService(*dbus, processorErrConfigIntf, processorErrConfigObjPath);
-    setDbusProperty(*dbus, service, processorErrConfigObjPath,
-                    processorErrConfigIntf, "ResetCfg", req->resetCfg);
-
-    setDbusProperty(*dbus, service, processorErrConfigObjPath,
-                    processorErrConfigIntf, "ResetErrorOccurrenceCounts",
-                    req->resetErrorOccurrenceCounts);
-    *dataLen = 0;
-
-    return IPMI_CC_OK;
+    return ipmi::responseSuccess();
 }
 
 ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
@@ -2135,16 +2180,19 @@
             IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
         ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
 
-    ipmiPrintAndRegister(
-        netfnIntcOEMGeneral,
-        static_cast<ipmi_cmd_t>(
+    // <Get Processor Error Config>
+    ipmi::registerHandler(
+        ipmi::prioOemBase, netfnIntcOEMGeneral,
+        static_cast<ipmi::Cmd>(
             IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
-        NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
-    ipmiPrintAndRegister(
-        netfnIntcOEMGeneral,
-        static_cast<ipmi_cmd_t>(
+        ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig);
+    // <Set Processor Error Config>
+    ipmi::registerHandler(
+        ipmi::prioOemBase, netfnIntcOEMGeneral,
+        static_cast<ipmi::Cmd>(
             IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
-        NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
+        ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig);
+
     ipmiPrintAndRegister(netfnIntcOEMGeneral,
                          static_cast<ipmi_cmd_t>(
                              IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),