xref: /openbmc/fb-ipmi-oem/src/selcommands.cpp (revision c1921c637bb124538638bb99510771da3e497df8)
111b9c3b1SVijay Khemka /*
211b9c3b1SVijay Khemka  * Copyright (c)  2018 Intel Corporation.
311b9c3b1SVijay Khemka  * Copyright (c)  2018-present Facebook.
411b9c3b1SVijay Khemka  *
511b9c3b1SVijay Khemka  * Licensed under the Apache License, Version 2.0 (the "License");
611b9c3b1SVijay Khemka  * you may not use this file except in compliance with the License.
711b9c3b1SVijay Khemka  * You may obtain a copy of the License at
811b9c3b1SVijay Khemka  *
911b9c3b1SVijay Khemka  *      http://www.apache.org/licenses/LICENSE-2.0
1011b9c3b1SVijay Khemka  *
1111b9c3b1SVijay Khemka  * Unless required by applicable law or agreed to in writing, software
1211b9c3b1SVijay Khemka  * distributed under the License is distributed on an "AS IS" BASIS,
1311b9c3b1SVijay Khemka  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1411b9c3b1SVijay Khemka  * See the License for the specific language governing permissions and
1511b9c3b1SVijay Khemka  * limitations under the License.
1611b9c3b1SVijay Khemka  */
1711b9c3b1SVijay Khemka 
1811b9c3b1SVijay Khemka #include <ipmid/api.hpp>
1911b9c3b1SVijay Khemka 
2011b9c3b1SVijay Khemka #include <boost/algorithm/string/join.hpp>
2111b9c3b1SVijay Khemka #include <nlohmann/json.hpp>
2211b9c3b1SVijay Khemka #include <iostream>
2311b9c3b1SVijay Khemka #include <sstream>
2411b9c3b1SVijay Khemka #include <fstream>
2511b9c3b1SVijay Khemka #include <phosphor-logging/log.hpp>
2611b9c3b1SVijay Khemka #include <sdbusplus/message/types.hpp>
2711b9c3b1SVijay Khemka #include <sdbusplus/timer.hpp>
2811b9c3b1SVijay Khemka #include <storagecommands.hpp>
2911b9c3b1SVijay Khemka 
3011b9c3b1SVijay Khemka //----------------------------------------------------------------------
3111b9c3b1SVijay Khemka // Platform specific functions for storing app data
3211b9c3b1SVijay Khemka //----------------------------------------------------------------------
3311b9c3b1SVijay Khemka 
3411b9c3b1SVijay Khemka static void toHexStr(std::vector<uint8_t> &bytes, std::string &hexStr)
3511b9c3b1SVijay Khemka {
3611b9c3b1SVijay Khemka     std::stringstream stream;
3711b9c3b1SVijay Khemka     stream << std::hex << std::uppercase << std::setfill('0');
3811b9c3b1SVijay Khemka     for (const uint8_t byte : bytes)
3911b9c3b1SVijay Khemka     {
4011b9c3b1SVijay Khemka         stream << std::setw(2) << static_cast<int>(byte);
4111b9c3b1SVijay Khemka     }
4211b9c3b1SVijay Khemka     hexStr = stream.str();
4311b9c3b1SVijay Khemka }
4411b9c3b1SVijay Khemka 
4511b9c3b1SVijay Khemka static int fromHexStr(const std::string hexStr, std::vector<uint8_t> &data)
4611b9c3b1SVijay Khemka {
4711b9c3b1SVijay Khemka     for (unsigned int i = 0; i < hexStr.size(); i += 2)
4811b9c3b1SVijay Khemka     {
4911b9c3b1SVijay Khemka         try
5011b9c3b1SVijay Khemka         {
5111b9c3b1SVijay Khemka             data.push_back(static_cast<uint8_t>(
5211b9c3b1SVijay Khemka                 std::stoul(hexStr.substr(i, 2), nullptr, 16)));
5311b9c3b1SVijay Khemka         }
5411b9c3b1SVijay Khemka         catch (std::invalid_argument &e)
5511b9c3b1SVijay Khemka         {
5611b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
5711b9c3b1SVijay Khemka             return -1;
5811b9c3b1SVijay Khemka         }
5911b9c3b1SVijay Khemka         catch (std::out_of_range &e)
6011b9c3b1SVijay Khemka         {
6111b9c3b1SVijay Khemka             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
6211b9c3b1SVijay Khemka             return -1;
6311b9c3b1SVijay Khemka         }
6411b9c3b1SVijay Khemka     }
6511b9c3b1SVijay Khemka     return 0;
6611b9c3b1SVijay Khemka }
6711b9c3b1SVijay Khemka 
6811b9c3b1SVijay Khemka namespace fb_oem::ipmi::sel
6911b9c3b1SVijay Khemka {
7011b9c3b1SVijay Khemka 
7111b9c3b1SVijay Khemka class SELData
7211b9c3b1SVijay Khemka {
7311b9c3b1SVijay Khemka   private:
7411b9c3b1SVijay Khemka     nlohmann::json selDataObj;
7511b9c3b1SVijay Khemka 
7611b9c3b1SVijay Khemka     void flush()
7711b9c3b1SVijay Khemka     {
7811b9c3b1SVijay Khemka         std::ofstream file(SEL_JSON_DATA_FILE);
7911b9c3b1SVijay Khemka         file << selDataObj;
8011b9c3b1SVijay Khemka         file.close();
8111b9c3b1SVijay Khemka     }
8211b9c3b1SVijay Khemka 
8311b9c3b1SVijay Khemka     void init()
8411b9c3b1SVijay Khemka     {
8511b9c3b1SVijay Khemka         selDataObj[KEY_SEL_VER] = 0x51;
8611b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = 0;
8711b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = 0xFFFFFFFF;
8811b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = 0xFFFFFFFF;
8911b9c3b1SVijay Khemka         selDataObj[KEY_OPER_SUPP] = 0x02;
9011b9c3b1SVijay Khemka         /* Spec indicates that more than 64kB is free */
9111b9c3b1SVijay Khemka         selDataObj[KEY_FREE_SPACE] = 0xFFFF;
9211b9c3b1SVijay Khemka     }
9311b9c3b1SVijay Khemka 
9411b9c3b1SVijay Khemka   public:
9511b9c3b1SVijay Khemka     SELData()
9611b9c3b1SVijay Khemka     {
9711b9c3b1SVijay Khemka         /* Get App data stored in json file */
9811b9c3b1SVijay Khemka         std::ifstream file(SEL_JSON_DATA_FILE);
9911b9c3b1SVijay Khemka         if (file)
10011b9c3b1SVijay Khemka         {
10111b9c3b1SVijay Khemka             file >> selDataObj;
10211b9c3b1SVijay Khemka             file.close();
10311b9c3b1SVijay Khemka         }
10411b9c3b1SVijay Khemka 
10511b9c3b1SVijay Khemka         /* Initialize SelData object if no entries. */
10611b9c3b1SVijay Khemka         if (selDataObj.find(KEY_SEL_COUNT) == selDataObj.end())
10711b9c3b1SVijay Khemka         {
10811b9c3b1SVijay Khemka             init();
10911b9c3b1SVijay Khemka         }
11011b9c3b1SVijay Khemka     }
11111b9c3b1SVijay Khemka 
11211b9c3b1SVijay Khemka     int clear()
11311b9c3b1SVijay Khemka     {
11411b9c3b1SVijay Khemka         /* Clear the complete Sel Json object */
11511b9c3b1SVijay Khemka         selDataObj.clear();
11611b9c3b1SVijay Khemka         /* Reinitialize it with basic data */
11711b9c3b1SVijay Khemka         init();
11811b9c3b1SVijay Khemka         /* Save the erase time */
11911b9c3b1SVijay Khemka         struct timespec selTime = {};
12011b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
12111b9c3b1SVijay Khemka         {
12211b9c3b1SVijay Khemka             return -1;
12311b9c3b1SVijay Khemka         }
12411b9c3b1SVijay Khemka         selDataObj[KEY_ERASE_TIME] = selTime.tv_sec;
12511b9c3b1SVijay Khemka         flush();
12611b9c3b1SVijay Khemka         return 0;
12711b9c3b1SVijay Khemka     }
12811b9c3b1SVijay Khemka 
12911b9c3b1SVijay Khemka     uint32_t getCount()
13011b9c3b1SVijay Khemka     {
13111b9c3b1SVijay Khemka         return selDataObj[KEY_SEL_COUNT];
13211b9c3b1SVijay Khemka     }
13311b9c3b1SVijay Khemka 
13411b9c3b1SVijay Khemka     void getInfo(GetSELInfoData &info)
13511b9c3b1SVijay Khemka     {
13611b9c3b1SVijay Khemka         info.selVersion = selDataObj[KEY_SEL_VER];
13711b9c3b1SVijay Khemka         info.entries = selDataObj[KEY_SEL_COUNT];
13811b9c3b1SVijay Khemka         info.freeSpace = selDataObj[KEY_FREE_SPACE];
13911b9c3b1SVijay Khemka         info.addTimeStamp = selDataObj[KEY_ADD_TIME];
14011b9c3b1SVijay Khemka         info.eraseTimeStamp = selDataObj[KEY_ERASE_TIME];
14111b9c3b1SVijay Khemka         info.operationSupport = selDataObj[KEY_OPER_SUPP];
14211b9c3b1SVijay Khemka     }
14311b9c3b1SVijay Khemka 
14411b9c3b1SVijay Khemka     int getEntry(uint32_t index, std::string &rawStr)
14511b9c3b1SVijay Khemka     {
14611b9c3b1SVijay Khemka         std::stringstream ss;
14711b9c3b1SVijay Khemka         ss << std::hex;
14811b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << index;
14911b9c3b1SVijay Khemka 
15011b9c3b1SVijay Khemka         /* Check or the requested SEL Entry, if record is available */
15111b9c3b1SVijay Khemka         if (selDataObj.find(ss.str()) == selDataObj.end())
15211b9c3b1SVijay Khemka         {
15311b9c3b1SVijay Khemka             return -1;
15411b9c3b1SVijay Khemka         }
15511b9c3b1SVijay Khemka 
15611b9c3b1SVijay Khemka         rawStr = selDataObj[ss.str()][KEY_SEL_ENTRY_RAW];
15711b9c3b1SVijay Khemka         return 0;
15811b9c3b1SVijay Khemka     }
15911b9c3b1SVijay Khemka 
16011b9c3b1SVijay Khemka     int addEntry(std::string keyStr)
16111b9c3b1SVijay Khemka     {
16211b9c3b1SVijay Khemka         struct timespec selTime = {};
16311b9c3b1SVijay Khemka 
16411b9c3b1SVijay Khemka         if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
16511b9c3b1SVijay Khemka         {
16611b9c3b1SVijay Khemka             return -1;
16711b9c3b1SVijay Khemka         }
16811b9c3b1SVijay Khemka 
16911b9c3b1SVijay Khemka         selDataObj[KEY_ADD_TIME] = selTime.tv_sec;
17011b9c3b1SVijay Khemka 
17111b9c3b1SVijay Khemka         int selCount = selDataObj[KEY_SEL_COUNT];
17211b9c3b1SVijay Khemka         selDataObj[KEY_SEL_COUNT] = ++selCount;
17311b9c3b1SVijay Khemka 
17411b9c3b1SVijay Khemka         std::stringstream ss;
17511b9c3b1SVijay Khemka         ss << std::hex;
17611b9c3b1SVijay Khemka         ss << std::setw(2) << std::setfill('0') << selCount;
17711b9c3b1SVijay Khemka 
17811b9c3b1SVijay Khemka         selDataObj[ss.str()][KEY_SEL_ENTRY_RAW] = keyStr;
17911b9c3b1SVijay Khemka         flush();
18011b9c3b1SVijay Khemka         return selCount;
18111b9c3b1SVijay Khemka     }
18211b9c3b1SVijay Khemka };
18311b9c3b1SVijay Khemka 
18411b9c3b1SVijay Khemka } // namespace fb_oem::ipmi::sel
18511b9c3b1SVijay Khemka 
18611b9c3b1SVijay Khemka namespace ipmi
18711b9c3b1SVijay Khemka {
18811b9c3b1SVijay Khemka 
18911b9c3b1SVijay Khemka namespace storage
19011b9c3b1SVijay Khemka {
19111b9c3b1SVijay Khemka 
19211b9c3b1SVijay Khemka static void registerSELFunctions() __attribute__((constructor));
19311b9c3b1SVijay Khemka static fb_oem::ipmi::sel::SELData selObj __attribute__((init_priority(101)));
19411b9c3b1SVijay Khemka 
19511b9c3b1SVijay Khemka ipmi::RspType<uint8_t,  // SEL version
19611b9c3b1SVijay Khemka               uint16_t, // SEL entry count
19711b9c3b1SVijay Khemka               uint16_t, // free space
19811b9c3b1SVijay Khemka               uint32_t, // last add timestamp
19911b9c3b1SVijay Khemka               uint32_t, // last erase timestamp
20011b9c3b1SVijay Khemka               uint8_t>  // operation support
20111b9c3b1SVijay Khemka     ipmiStorageGetSELInfo()
20211b9c3b1SVijay Khemka {
20311b9c3b1SVijay Khemka 
20411b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELInfoData info;
20511b9c3b1SVijay Khemka 
20611b9c3b1SVijay Khemka     selObj.getInfo(info);
20711b9c3b1SVijay Khemka     return ipmi::responseSuccess(info.selVersion, info.entries, info.freeSpace,
20811b9c3b1SVijay Khemka                                  info.addTimeStamp, info.eraseTimeStamp,
20911b9c3b1SVijay Khemka                                  info.operationSupport);
21011b9c3b1SVijay Khemka }
21111b9c3b1SVijay Khemka 
21211b9c3b1SVijay Khemka ipmi::RspType<uint16_t, std::vector<uint8_t>>
21311b9c3b1SVijay Khemka     ipmiStorageGetSELEntry(std::vector<uint8_t> data)
21411b9c3b1SVijay Khemka {
21511b9c3b1SVijay Khemka 
21611b9c3b1SVijay Khemka     if (data.size() != sizeof(fb_oem::ipmi::sel::GetSELEntryRequest))
21711b9c3b1SVijay Khemka     {
21811b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
21911b9c3b1SVijay Khemka     }
22011b9c3b1SVijay Khemka 
22111b9c3b1SVijay Khemka     fb_oem::ipmi::sel::GetSELEntryRequest *reqData =
22211b9c3b1SVijay Khemka         reinterpret_cast<fb_oem::ipmi::sel::GetSELEntryRequest *>(&data[0]);
22311b9c3b1SVijay Khemka 
22411b9c3b1SVijay Khemka     if (reqData->reservID != 0)
22511b9c3b1SVijay Khemka     {
22611b9c3b1SVijay Khemka         if (!checkSELReservation(reqData->reservID))
22711b9c3b1SVijay Khemka         {
22811b9c3b1SVijay Khemka             return ipmi::responseInvalidReservationId();
22911b9c3b1SVijay Khemka         }
23011b9c3b1SVijay Khemka     }
23111b9c3b1SVijay Khemka 
23211b9c3b1SVijay Khemka     uint16_t selCnt = selObj.getCount();
23311b9c3b1SVijay Khemka     if (selCnt == 0)
23411b9c3b1SVijay Khemka     {
23511b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
23611b9c3b1SVijay Khemka     }
23711b9c3b1SVijay Khemka 
23811b9c3b1SVijay Khemka     /* If it is asked for first entry */
23911b9c3b1SVijay Khemka     if (reqData->recordID == fb_oem::ipmi::sel::firstEntry)
24011b9c3b1SVijay Khemka     {
24111b9c3b1SVijay Khemka         /* First Entry (0x0000) as per Spec */
24211b9c3b1SVijay Khemka         reqData->recordID = 1;
24311b9c3b1SVijay Khemka     }
24411b9c3b1SVijay Khemka     else if (reqData->recordID == fb_oem::ipmi::sel::lastEntry)
24511b9c3b1SVijay Khemka     {
24611b9c3b1SVijay Khemka         /* Last entry (0xFFFF) as per Spec */
24711b9c3b1SVijay Khemka         reqData->recordID = selCnt;
24811b9c3b1SVijay Khemka     }
24911b9c3b1SVijay Khemka 
25011b9c3b1SVijay Khemka     std::string ipmiRaw;
25111b9c3b1SVijay Khemka 
25211b9c3b1SVijay Khemka     if (selObj.getEntry(reqData->recordID, ipmiRaw) < 0)
25311b9c3b1SVijay Khemka     {
25411b9c3b1SVijay Khemka         return ipmi::responseSensorInvalid();
25511b9c3b1SVijay Khemka     }
25611b9c3b1SVijay Khemka 
25711b9c3b1SVijay Khemka     std::vector<uint8_t> recDataBytes;
25811b9c3b1SVijay Khemka     if (fromHexStr(ipmiRaw, recDataBytes) < 0)
25911b9c3b1SVijay Khemka     {
26011b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
26111b9c3b1SVijay Khemka     }
26211b9c3b1SVijay Khemka 
26311b9c3b1SVijay Khemka     /* Identify the next SEL record ID. If recordID is same as
26411b9c3b1SVijay Khemka      * total SeL count then next id should be last entry else
26511b9c3b1SVijay Khemka      * it should be incremented by 1 to current RecordID
26611b9c3b1SVijay Khemka      */
26711b9c3b1SVijay Khemka     uint16_t nextRecord;
26811b9c3b1SVijay Khemka     if (reqData->recordID == selCnt)
26911b9c3b1SVijay Khemka     {
27011b9c3b1SVijay Khemka         nextRecord = fb_oem::ipmi::sel::lastEntry;
27111b9c3b1SVijay Khemka     }
27211b9c3b1SVijay Khemka     else
27311b9c3b1SVijay Khemka     {
27411b9c3b1SVijay Khemka         nextRecord = reqData->recordID + 1;
27511b9c3b1SVijay Khemka     }
27611b9c3b1SVijay Khemka 
27711b9c3b1SVijay Khemka     if (reqData->readLen == fb_oem::ipmi::sel::entireRecord)
27811b9c3b1SVijay Khemka     {
27911b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recDataBytes);
28011b9c3b1SVijay Khemka     }
28111b9c3b1SVijay Khemka     else
28211b9c3b1SVijay Khemka     {
28311b9c3b1SVijay Khemka         if (reqData->offset >= fb_oem::ipmi::sel::selRecordSize ||
28411b9c3b1SVijay Khemka             reqData->readLen > fb_oem::ipmi::sel::selRecordSize)
28511b9c3b1SVijay Khemka         {
28611b9c3b1SVijay Khemka             return ipmi::responseUnspecifiedError();
28711b9c3b1SVijay Khemka         }
28811b9c3b1SVijay Khemka         std::vector<uint8_t> recPartData;
28911b9c3b1SVijay Khemka 
29011b9c3b1SVijay Khemka         auto diff = fb_oem::ipmi::sel::selRecordSize - reqData->offset;
29111b9c3b1SVijay Khemka         auto readLength = std::min(diff, static_cast<int>(reqData->readLen));
29211b9c3b1SVijay Khemka 
29311b9c3b1SVijay Khemka         for (int i = 0; i < readLength; i++)
29411b9c3b1SVijay Khemka         {
29511b9c3b1SVijay Khemka             recPartData.push_back(recDataBytes[i + reqData->offset]);
29611b9c3b1SVijay Khemka         }
29711b9c3b1SVijay Khemka         return ipmi::responseSuccess(nextRecord, recPartData);
29811b9c3b1SVijay Khemka     }
29911b9c3b1SVijay Khemka }
30011b9c3b1SVijay Khemka 
30111b9c3b1SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageAddSELEntry(std::vector<uint8_t> data)
30211b9c3b1SVijay Khemka {
30311b9c3b1SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when a
30411b9c3b1SVijay Khemka      * SEL entry is added
30511b9c3b1SVijay Khemka      */
30611b9c3b1SVijay Khemka     cancelSELReservation();
30711b9c3b1SVijay Khemka 
30811b9c3b1SVijay Khemka     if (data.size() != fb_oem::ipmi::sel::selRecordSize)
30911b9c3b1SVijay Khemka     {
31011b9c3b1SVijay Khemka         return ipmi::responseReqDataLenInvalid();
31111b9c3b1SVijay Khemka     }
31211b9c3b1SVijay Khemka 
31311b9c3b1SVijay Khemka     std::string ipmiRaw, logErr;
31411b9c3b1SVijay Khemka     toHexStr(data, ipmiRaw);
31511b9c3b1SVijay Khemka 
31611b9c3b1SVijay Khemka     /* Log the Raw SEL message to the journal */
31711b9c3b1SVijay Khemka     std::string journalMsg = "SEL Entry Added: " + ipmiRaw;
31811b9c3b1SVijay Khemka     phosphor::logging::log<phosphor::logging::level::INFO>(journalMsg.c_str());
31911b9c3b1SVijay Khemka 
32011b9c3b1SVijay Khemka     int responseID = selObj.addEntry(ipmiRaw.c_str());
32111b9c3b1SVijay Khemka     if (responseID < 0)
32211b9c3b1SVijay Khemka     {
32311b9c3b1SVijay Khemka         return ipmi::responseUnspecifiedError();
32411b9c3b1SVijay Khemka     }
32511b9c3b1SVijay Khemka     return ipmi::responseSuccess((uint16_t)responseID);
32611b9c3b1SVijay Khemka }
32711b9c3b1SVijay Khemka 
328*c1921c63SVijay Khemka ipmi::RspType<uint8_t> ipmiStorageClearSEL(uint16_t reservationID,
329*c1921c63SVijay Khemka                                            const std::array<uint8_t, 3> &clr,
330*c1921c63SVijay Khemka                                            uint8_t eraseOperation)
331*c1921c63SVijay Khemka {
332*c1921c63SVijay Khemka     if (!checkSELReservation(reservationID))
333*c1921c63SVijay Khemka     {
334*c1921c63SVijay Khemka         return ipmi::responseInvalidReservationId();
335*c1921c63SVijay Khemka     }
336*c1921c63SVijay Khemka 
337*c1921c63SVijay Khemka     static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'};
338*c1921c63SVijay Khemka     if (clr != clrExpected)
339*c1921c63SVijay Khemka     {
340*c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
341*c1921c63SVijay Khemka     }
342*c1921c63SVijay Khemka 
343*c1921c63SVijay Khemka     /* If there is no sel then return erase complete */
344*c1921c63SVijay Khemka     if (selObj.getCount() == 0)
345*c1921c63SVijay Khemka     {
346*c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
347*c1921c63SVijay Khemka     }
348*c1921c63SVijay Khemka 
349*c1921c63SVijay Khemka     /* Erasure status cannot be fetched, so always return erasure
350*c1921c63SVijay Khemka      * status as `erase completed`.
351*c1921c63SVijay Khemka      */
352*c1921c63SVijay Khemka     if (eraseOperation == fb_oem::ipmi::sel::getEraseStatus)
353*c1921c63SVijay Khemka     {
354*c1921c63SVijay Khemka         return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
355*c1921c63SVijay Khemka     }
356*c1921c63SVijay Khemka 
357*c1921c63SVijay Khemka     /* Check that initiate erase is correct */
358*c1921c63SVijay Khemka     if (eraseOperation != fb_oem::ipmi::sel::initiateErase)
359*c1921c63SVijay Khemka     {
360*c1921c63SVijay Khemka         return ipmi::responseInvalidFieldRequest();
361*c1921c63SVijay Khemka     }
362*c1921c63SVijay Khemka 
363*c1921c63SVijay Khemka     /* Per the IPMI spec, need to cancel any reservation when the
364*c1921c63SVijay Khemka      * SEL is cleared
365*c1921c63SVijay Khemka      */
366*c1921c63SVijay Khemka     cancelSELReservation();
367*c1921c63SVijay Khemka 
368*c1921c63SVijay Khemka     /* Clear the complete Sel Json object */
369*c1921c63SVijay Khemka     if (selObj.clear() < 0)
370*c1921c63SVijay Khemka     {
371*c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
372*c1921c63SVijay Khemka     }
373*c1921c63SVijay Khemka 
374*c1921c63SVijay Khemka     return ipmi::responseSuccess(fb_oem::ipmi::sel::eraseComplete);
375*c1921c63SVijay Khemka }
376*c1921c63SVijay Khemka 
377*c1921c63SVijay Khemka ipmi::RspType<uint32_t> ipmiStorageGetSELTime()
378*c1921c63SVijay Khemka {
379*c1921c63SVijay Khemka     struct timespec selTime = {};
380*c1921c63SVijay Khemka 
381*c1921c63SVijay Khemka     if (clock_gettime(CLOCK_REALTIME, &selTime) < 0)
382*c1921c63SVijay Khemka     {
383*c1921c63SVijay Khemka         return ipmi::responseUnspecifiedError();
384*c1921c63SVijay Khemka     }
385*c1921c63SVijay Khemka 
386*c1921c63SVijay Khemka     return ipmi::responseSuccess(selTime.tv_sec);
387*c1921c63SVijay Khemka }
388*c1921c63SVijay Khemka 
389*c1921c63SVijay Khemka ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime)
390*c1921c63SVijay Khemka {
391*c1921c63SVijay Khemka     // Set SEL Time is not supported
392*c1921c63SVijay Khemka     return ipmi::responseInvalidCommand();
393*c1921c63SVijay Khemka }
394*c1921c63SVijay Khemka 
395*c1921c63SVijay Khemka ipmi::RspType<uint16_t> ipmiStorageGetSELTimeUtcOffset()
396*c1921c63SVijay Khemka {
397*c1921c63SVijay Khemka     /* TODO: For now, the SEL time stamp is based on UTC time,
398*c1921c63SVijay Khemka      * so return 0x0000 as offset. Might need to change once
399*c1921c63SVijay Khemka      * supporting zones in SEL time stamps
400*c1921c63SVijay Khemka      */
401*c1921c63SVijay Khemka 
402*c1921c63SVijay Khemka     uint16_t utcOffset = 0x0000;
403*c1921c63SVijay Khemka     return ipmi::responseSuccess(utcOffset);
404*c1921c63SVijay Khemka }
405*c1921c63SVijay Khemka 
40611b9c3b1SVijay Khemka void registerSELFunctions()
40711b9c3b1SVijay Khemka {
40811b9c3b1SVijay Khemka     // <Get SEL Info>
40911b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
41011b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User,
41111b9c3b1SVijay Khemka                           ipmiStorageGetSELInfo);
41211b9c3b1SVijay Khemka 
41311b9c3b1SVijay Khemka     // <Get SEL Entry>
41411b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
41511b9c3b1SVijay Khemka                           ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User,
41611b9c3b1SVijay Khemka                           ipmiStorageGetSELEntry);
41711b9c3b1SVijay Khemka 
41811b9c3b1SVijay Khemka     // <Add SEL Entry>
41911b9c3b1SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
42011b9c3b1SVijay Khemka                           ipmi::storage::cmdAddSelEntry,
42111b9c3b1SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageAddSELEntry);
42211b9c3b1SVijay Khemka 
423*c1921c63SVijay Khemka     // <Clear SEL>
424*c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
425*c1921c63SVijay Khemka                           ipmi::storage::cmdClearSel, ipmi::Privilege::Operator,
426*c1921c63SVijay Khemka                           ipmiStorageClearSEL);
427*c1921c63SVijay Khemka 
428*c1921c63SVijay Khemka     // <Get SEL Time>
429*c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
430*c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTime, ipmi::Privilege::User,
431*c1921c63SVijay Khemka                           ipmiStorageGetSELTime);
432*c1921c63SVijay Khemka 
433*c1921c63SVijay Khemka     // <Set SEL Time>
434*c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
435*c1921c63SVijay Khemka                           ipmi::storage::cmdSetSelTime,
436*c1921c63SVijay Khemka                           ipmi::Privilege::Operator, ipmiStorageSetSELTime);
437*c1921c63SVijay Khemka 
438*c1921c63SVijay Khemka     // <Get SEL Time UTC Offset>
439*c1921c63SVijay Khemka     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
440*c1921c63SVijay Khemka                           ipmi::storage::cmdGetSelTimeUtcOffset,
441*c1921c63SVijay Khemka                           ipmi::Privilege::User,
442*c1921c63SVijay Khemka                           ipmiStorageGetSELTimeUtcOffset);
443*c1921c63SVijay Khemka 
44411b9c3b1SVijay Khemka     return;
44511b9c3b1SVijay Khemka }
44611b9c3b1SVijay Khemka 
44711b9c3b1SVijay Khemka } // namespace storage
44811b9c3b1SVijay Khemka } // namespace ipmi
449