Add more SEL commands

Added more sel commands like clear sel, get sel time etc.

Tested: Verified this sending command through ipmitool.

Change-Id: If1478589ed8dcb2976772c05f748a358c9ee8a7b
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
diff --git a/include/storagecommands.hpp b/include/storagecommands.hpp
index 4980433..5307c2d 100644
--- a/include/storagecommands.hpp
+++ b/include/storagecommands.hpp
@@ -143,4 +143,8 @@
     uint8_t recordData[16]; //!< Record Data.
 } __attribute__((packed));
 
+static constexpr auto initiateErase = 0xAA;
+static constexpr auto getEraseStatus = 0x00;
+static constexpr auto eraseComplete = 0x01;
+
 } // namespace fb_oem::ipmi::sel
diff --git a/src/selcommands.cpp b/src/selcommands.cpp
index 0fc33b4..1339b36 100644
--- a/src/selcommands.cpp
+++ b/src/selcommands.cpp
@@ -325,6 +325,84 @@
     return ipmi::responseSuccess((uint16_t)responseID);
 }
 
+ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
+                                           const std::array<uint8_t, 3> &clr,
+                                           uint8_t eraseOperation)
+{
+    if (!checkSELReservation(reservationID))
+    {
+        return ipmi::responseInvalidReservationId();
+    }
+
+    static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
+    if (clr != clrExpected)
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    /* If there is no sel then return erase complete */
+    if (selObj.getCount() == 0)
+    {
+        return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
+    }
+
+    /* Erasure status cannot be fetched, so always return erasure
+     * status as `erase completed`.
+     */
+    if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
+    {
+        return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
+    }
+
+    /* Check that initiate erase is correct */
+    if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    /* Per the IPMI spec, need to cancel any reservation when the
+     * SEL is cleared
+     */
+    cancelSELReservation();
+
+    /* Clear the complete Sel Json object */
+    if (selObj.clear() < 0)
+    {
+        return ipmi::responseUnspecifiedError();
+    }
+
+    return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
+}
+
+ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
+{
+    struct timespec selTime = {};
+
+    if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
+    {
+        return ipmi::responseUnspecifiedError();
+    }
+
+    return ipmi::responseSuccess(selTime.tv_sec);
+}
+
+ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime)
+{
+    // Set SEL Time is not supported
+    return ipmi::responseInvalidCommand();
+}
+
+ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
+{
+    /* TODO: For now, the SEL time stamp is based on UTC time,
+     * so return 0x0000 as offset. Might need to change once
+     * supporting zones in SEL time stamps
+     */
+
+    uint16_t utcOffset = 0x0000;
+    return ipmi::responseSuccess(utcOffset);
+}
+
 void registerSELFunctions()
 {
     // <Get SEL Info>
@@ -342,6 +420,27 @@
                           ipmi::storage::cmdAddSelEntry,
                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
 
+    // <Clear SEL>
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
+                          ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
+                          ipmiStorageClearSEL);
+
+    // <Get SEL Time>
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
+                          ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
+                          ipmiStorageGetSELTime);
+
+    // <Set SEL Time>
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
+                          ipmi::storage::cmdSetSelTime,
+                          ipmi::Privilege::Operator, ipmiStorageSetSELTime);
+
+    // <Get SEL Time UTC Offset>
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
+                          ipmi::storage::cmdGetSelTimeUtcOffset,
+                          ipmi::Privilege::User,
+                          ipmiStorageGetSELTimeUtcOffset);
+
     return;
 }