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