13f7c5e40SJason M. Bills /* 21a2fbddfSJason M. Bills // Copyright (c) 2017-2019 Intel Corporation 33f7c5e40SJason M. Bills // 43f7c5e40SJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License"); 53f7c5e40SJason M. Bills // you may not use this file except in compliance with the License. 63f7c5e40SJason M. Bills // You may obtain a copy of the License at 73f7c5e40SJason M. Bills // 83f7c5e40SJason M. Bills // http://www.apache.org/licenses/LICENSE-2.0 93f7c5e40SJason M. Bills // 103f7c5e40SJason M. Bills // Unless required by applicable law or agreed to in writing, software 113f7c5e40SJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS, 123f7c5e40SJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f7c5e40SJason M. Bills // See the License for the specific language governing permissions and 143f7c5e40SJason M. Bills // limitations under the License. 153f7c5e40SJason M. Bills */ 163f7c5e40SJason M. Bills 171d4d54ddSJason M. Bills #include <boost/algorithm/string.hpp> 183f7c5e40SJason M. Bills #include <boost/container/flat_map.hpp> 19c04e2e70SJason M. Bills #include <boost/process.hpp> 203f7c5e40SJason M. Bills #include <commandutils.hpp> 211d4d54ddSJason M. Bills #include <filesystem> 22e8767d26SPatrick Venture #include <functional> 233f7c5e40SJason M. Bills #include <iostream> 2499b78ec8SJason M. Bills #include <ipmi_to_redfish_hooks.hpp> 252a265d54SJames Feist #include <ipmid/api.hpp> 26c04e2e70SJason M. Bills #include <phosphor-ipmi-host/selutility.hpp> 273f7c5e40SJason M. Bills #include <phosphor-logging/log.hpp> 283f7c5e40SJason M. Bills #include <sdbusplus/message/types.hpp> 293f7c5e40SJason M. Bills #include <sdbusplus/timer.hpp> 30c04e2e70SJason M. Bills #include <sdrutils.hpp> 31c04e2e70SJason M. Bills #include <stdexcept> 323f7c5e40SJason M. Bills #include <storagecommands.hpp> 3352aaa7d5SJason M. Bills #include <string_view> 343f7c5e40SJason M. Bills 35*9ce789fcSPatrick Venture static constexpr bool DEBUG = false; 36*9ce789fcSPatrick Venture 371d4d54ddSJason M. Bills namespace intel_oem::ipmi::sel 381d4d54ddSJason M. Bills { 391d4d54ddSJason M. Bills static const std::filesystem::path selLogDir = "/var/log"; 401d4d54ddSJason M. Bills static const std::string selLogFilename = "ipmi_sel"; 411d4d54ddSJason M. Bills 421d4d54ddSJason M. Bills static int getFileTimestamp(const std::filesystem::path& file) 431d4d54ddSJason M. Bills { 441d4d54ddSJason M. Bills struct stat st; 451d4d54ddSJason M. Bills 461d4d54ddSJason M. Bills if (stat(file.c_str(), &st) >= 0) 471d4d54ddSJason M. Bills { 481d4d54ddSJason M. Bills return st.st_mtime; 491d4d54ddSJason M. Bills } 501d4d54ddSJason M. Bills return ::ipmi::sel::invalidTimeStamp; 511d4d54ddSJason M. Bills } 521d4d54ddSJason M. Bills 531d4d54ddSJason M. Bills namespace erase_time 547944c307SJason M. Bills { 557944c307SJason M. Bills static constexpr const char* selEraseTimestamp = "/var/lib/ipmi/sel_erase_time"; 567944c307SJason M. Bills 577944c307SJason M. Bills void save() 587944c307SJason M. Bills { 597944c307SJason M. Bills // open the file, creating it if necessary 607944c307SJason M. Bills int fd = open(selEraseTimestamp, O_WRONLY | O_CREAT | O_CLOEXEC, 0644); 617944c307SJason M. Bills if (fd < 0) 627944c307SJason M. Bills { 637944c307SJason M. Bills std::cerr << "Failed to open file\n"; 647944c307SJason M. Bills return; 657944c307SJason M. Bills } 667944c307SJason M. Bills 677944c307SJason M. Bills // update the file timestamp to the current time 687944c307SJason M. Bills if (futimens(fd, NULL) < 0) 697944c307SJason M. Bills { 707944c307SJason M. Bills std::cerr << "Failed to update timestamp: " 717944c307SJason M. Bills << std::string(strerror(errno)); 727944c307SJason M. Bills } 737944c307SJason M. Bills close(fd); 747944c307SJason M. Bills } 757944c307SJason M. Bills 767944c307SJason M. Bills int get() 777944c307SJason M. Bills { 781d4d54ddSJason M. Bills return getFileTimestamp(selEraseTimestamp); 797944c307SJason M. Bills } 801d4d54ddSJason M. Bills } // namespace erase_time 811d4d54ddSJason M. Bills } // namespace intel_oem::ipmi::sel 827944c307SJason M. Bills 833f7c5e40SJason M. Bills namespace ipmi 843f7c5e40SJason M. Bills { 853f7c5e40SJason M. Bills 863f7c5e40SJason M. Bills namespace storage 873f7c5e40SJason M. Bills { 883f7c5e40SJason M. Bills 89e2d1aee3SJason M. Bills constexpr static const size_t maxMessageSize = 64; 903f7c5e40SJason M. Bills constexpr static const size_t maxFruSdrNameSize = 16; 913f7c5e40SJason M. Bills using ManagedObjectType = boost::container::flat_map< 923f7c5e40SJason M. Bills sdbusplus::message::object_path, 933f7c5e40SJason M. Bills boost::container::flat_map< 943f7c5e40SJason M. Bills std::string, boost::container::flat_map<std::string, DbusVariant>>>; 953f7c5e40SJason M. Bills using ManagedEntry = std::pair< 963f7c5e40SJason M. Bills sdbusplus::message::object_path, 973f7c5e40SJason M. Bills boost::container::flat_map< 983f7c5e40SJason M. Bills std::string, boost::container::flat_map<std::string, DbusVariant>>>; 993f7c5e40SJason M. Bills 1003bcba457SJames Feist constexpr static const char* fruDeviceServiceName = 1013bcba457SJames Feist "xyz.openbmc_project.FruDevice"; 102*9ce789fcSPatrick Venture constexpr static const char* entityManagerServiceName = 103*9ce789fcSPatrick Venture "xyz.openbmc_project.EntityManager"; 104e2d1aee3SJason M. Bills constexpr static const size_t cacheTimeoutSeconds = 10; 1053f7c5e40SJason M. Bills 1064ed6f2c1SJason M. Bills // event direction is bit[7] of eventType where 1b = Deassertion event 1074ed6f2c1SJason M. Bills constexpr static const uint8_t deassertionEvent = 0x80; 108c04e2e70SJason M. Bills 1093f7c5e40SJason M. Bills static std::vector<uint8_t> fruCache; 1103f7c5e40SJason M. Bills static uint8_t cacheBus = 0xFF; 1113f7c5e40SJason M. Bills static uint8_t cacheAddr = 0XFF; 1123f7c5e40SJason M. Bills 1133f7c5e40SJason M. Bills std::unique_ptr<phosphor::Timer> cacheTimer = nullptr; 1143f7c5e40SJason M. Bills 1153f7c5e40SJason M. Bills // we unfortunately have to build a map of hashes in case there is a 1163f7c5e40SJason M. Bills // collision to verify our dev-id 1173f7c5e40SJason M. Bills boost::container::flat_map<uint8_t, std::pair<uint8_t, uint8_t>> deviceHashes; 1183f7c5e40SJason M. Bills 119e2d1aee3SJason M. Bills void registerStorageFunctions() __attribute__((constructor)); 1203f7c5e40SJason M. Bills 1213f7c5e40SJason M. Bills bool writeFru() 1223f7c5e40SJason M. Bills { 12315419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 12415419dd5SVernon Mauery sdbusplus::message::message writeFru = dbus->new_method_call( 1253f7c5e40SJason M. Bills fruDeviceServiceName, "/xyz/openbmc_project/FruDevice", 1263f7c5e40SJason M. Bills "xyz.openbmc_project.FruDeviceManager", "WriteFru"); 1273f7c5e40SJason M. Bills writeFru.append(cacheBus, cacheAddr, fruCache); 1283f7c5e40SJason M. Bills try 1293f7c5e40SJason M. Bills { 13015419dd5SVernon Mauery sdbusplus::message::message writeFruResp = dbus->call(writeFru); 1313f7c5e40SJason M. Bills } 1323f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 1333f7c5e40SJason M. Bills { 1343f7c5e40SJason M. Bills // todo: log sel? 1353f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 1363f7c5e40SJason M. Bills "error writing fru"); 1373f7c5e40SJason M. Bills return false; 1383f7c5e40SJason M. Bills } 1393f7c5e40SJason M. Bills return true; 1403f7c5e40SJason M. Bills } 1413f7c5e40SJason M. Bills 142e2d1aee3SJason M. Bills void createTimer() 143e2d1aee3SJason M. Bills { 144e2d1aee3SJason M. Bills if (cacheTimer == nullptr) 145e2d1aee3SJason M. Bills { 146e2d1aee3SJason M. Bills cacheTimer = std::make_unique<phosphor::Timer>(writeFru); 147e2d1aee3SJason M. Bills } 148e2d1aee3SJason M. Bills } 149e2d1aee3SJason M. Bills 1503f7c5e40SJason M. Bills ipmi_ret_t replaceCacheFru(uint8_t devId) 1513f7c5e40SJason M. Bills { 1523f7c5e40SJason M. Bills static uint8_t lastDevId = 0xFF; 1533f7c5e40SJason M. Bills 1543f7c5e40SJason M. Bills bool timerRunning = (cacheTimer != nullptr) && !cacheTimer->isExpired(); 1553f7c5e40SJason M. Bills if (lastDevId == devId && timerRunning) 1563f7c5e40SJason M. Bills { 1573f7c5e40SJason M. Bills return IPMI_CC_OK; // cache already up to date 1583f7c5e40SJason M. Bills } 1593f7c5e40SJason M. Bills // if timer is running, stop it and writeFru manually 1603f7c5e40SJason M. Bills else if (timerRunning) 1613f7c5e40SJason M. Bills { 1623f7c5e40SJason M. Bills cacheTimer->stop(); 1633f7c5e40SJason M. Bills writeFru(); 1643f7c5e40SJason M. Bills } 1653f7c5e40SJason M. Bills 16615419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 16715419dd5SVernon Mauery sdbusplus::message::message getObjects = dbus->new_method_call( 1683f7c5e40SJason M. Bills fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager", 1693f7c5e40SJason M. Bills "GetManagedObjects"); 1703f7c5e40SJason M. Bills ManagedObjectType frus; 1713f7c5e40SJason M. Bills try 1723f7c5e40SJason M. Bills { 17315419dd5SVernon Mauery sdbusplus::message::message resp = dbus->call(getObjects); 1743f7c5e40SJason M. Bills resp.read(frus); 1753f7c5e40SJason M. Bills } 1763f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 1773f7c5e40SJason M. Bills { 1783f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 1793f7c5e40SJason M. Bills "replaceCacheFru: error getting managed objects"); 1803f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 1813f7c5e40SJason M. Bills } 1823f7c5e40SJason M. Bills 1833f7c5e40SJason M. Bills deviceHashes.clear(); 1843f7c5e40SJason M. Bills 1853f7c5e40SJason M. Bills // hash the object paths to create unique device id's. increment on 1863f7c5e40SJason M. Bills // collision 1873f7c5e40SJason M. Bills std::hash<std::string> hasher; 1883f7c5e40SJason M. Bills for (const auto& fru : frus) 1893f7c5e40SJason M. Bills { 1903f7c5e40SJason M. Bills auto fruIface = fru.second.find("xyz.openbmc_project.FruDevice"); 1913f7c5e40SJason M. Bills if (fruIface == fru.second.end()) 1923f7c5e40SJason M. Bills { 1933f7c5e40SJason M. Bills continue; 1943f7c5e40SJason M. Bills } 1953f7c5e40SJason M. Bills 1963f7c5e40SJason M. Bills auto busFind = fruIface->second.find("BUS"); 1973f7c5e40SJason M. Bills auto addrFind = fruIface->second.find("ADDRESS"); 1983f7c5e40SJason M. Bills if (busFind == fruIface->second.end() || 1993f7c5e40SJason M. Bills addrFind == fruIface->second.end()) 2003f7c5e40SJason M. Bills { 2013f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::INFO>( 2023f7c5e40SJason M. Bills "fru device missing Bus or Address", 2033f7c5e40SJason M. Bills phosphor::logging::entry("FRU=%s", fru.first.str.c_str())); 2043f7c5e40SJason M. Bills continue; 2053f7c5e40SJason M. Bills } 2063f7c5e40SJason M. Bills 2078166c8d7SVernon Mauery uint8_t fruBus = std::get<uint32_t>(busFind->second); 2088166c8d7SVernon Mauery uint8_t fruAddr = std::get<uint32_t>(addrFind->second); 2093f7c5e40SJason M. Bills 2103f7c5e40SJason M. Bills uint8_t fruHash = 0; 2113f7c5e40SJason M. Bills if (fruBus != 0 || fruAddr != 0) 2123f7c5e40SJason M. Bills { 2133f7c5e40SJason M. Bills fruHash = hasher(fru.first.str); 2143f7c5e40SJason M. Bills // can't be 0xFF based on spec, and 0 is reserved for baseboard 2153f7c5e40SJason M. Bills if (fruHash == 0 || fruHash == 0xFF) 2163f7c5e40SJason M. Bills { 2173f7c5e40SJason M. Bills fruHash = 1; 2183f7c5e40SJason M. Bills } 2193f7c5e40SJason M. Bills } 2203f7c5e40SJason M. Bills std::pair<uint8_t, uint8_t> newDev(fruBus, fruAddr); 2213f7c5e40SJason M. Bills 2223f7c5e40SJason M. Bills bool emplacePassed = false; 2233f7c5e40SJason M. Bills while (!emplacePassed) 2243f7c5e40SJason M. Bills { 2253f7c5e40SJason M. Bills auto resp = deviceHashes.emplace(fruHash, newDev); 2263f7c5e40SJason M. Bills emplacePassed = resp.second; 2273f7c5e40SJason M. Bills if (!emplacePassed) 2283f7c5e40SJason M. Bills { 2293f7c5e40SJason M. Bills fruHash++; 2303f7c5e40SJason M. Bills // can't be 0xFF based on spec, and 0 is reserved for 2313f7c5e40SJason M. Bills // baseboard 2323f7c5e40SJason M. Bills if (fruHash == 0XFF) 2333f7c5e40SJason M. Bills { 2343f7c5e40SJason M. Bills fruHash = 0x1; 2353f7c5e40SJason M. Bills } 2363f7c5e40SJason M. Bills } 2373f7c5e40SJason M. Bills } 2383f7c5e40SJason M. Bills } 2393f7c5e40SJason M. Bills auto deviceFind = deviceHashes.find(devId); 2403f7c5e40SJason M. Bills if (deviceFind == deviceHashes.end()) 2413f7c5e40SJason M. Bills { 2423f7c5e40SJason M. Bills return IPMI_CC_SENSOR_INVALID; 2433f7c5e40SJason M. Bills } 2443f7c5e40SJason M. Bills 2453f7c5e40SJason M. Bills fruCache.clear(); 24615419dd5SVernon Mauery sdbusplus::message::message getRawFru = dbus->new_method_call( 2473f7c5e40SJason M. Bills fruDeviceServiceName, "/xyz/openbmc_project/FruDevice", 2483f7c5e40SJason M. Bills "xyz.openbmc_project.FruDeviceManager", "GetRawFru"); 2493f7c5e40SJason M. Bills cacheBus = deviceFind->second.first; 2503f7c5e40SJason M. Bills cacheAddr = deviceFind->second.second; 2513f7c5e40SJason M. Bills getRawFru.append(cacheBus, cacheAddr); 2523f7c5e40SJason M. Bills try 2533f7c5e40SJason M. Bills { 25415419dd5SVernon Mauery sdbusplus::message::message getRawResp = dbus->call(getRawFru); 2553f7c5e40SJason M. Bills getRawResp.read(fruCache); 2563f7c5e40SJason M. Bills } 2573f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 2583f7c5e40SJason M. Bills { 2593f7c5e40SJason M. Bills lastDevId = 0xFF; 2603f7c5e40SJason M. Bills cacheBus = 0xFF; 2613f7c5e40SJason M. Bills cacheAddr = 0xFF; 2623f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 2633f7c5e40SJason M. Bills } 2643f7c5e40SJason M. Bills 2653f7c5e40SJason M. Bills lastDevId = devId; 2663f7c5e40SJason M. Bills return IPMI_CC_OK; 2673f7c5e40SJason M. Bills } 2683f7c5e40SJason M. Bills 2695f4194eeSjayaprakash Mutyala /** @brief implements the read FRU data command 2705f4194eeSjayaprakash Mutyala * @param fruDeviceId - FRU Device ID 2715f4194eeSjayaprakash Mutyala * @param fruInventoryOffset - FRU Inventory Offset to write 2725f4194eeSjayaprakash Mutyala * @param countToRead - Count to read 2735f4194eeSjayaprakash Mutyala * 2745f4194eeSjayaprakash Mutyala * @returns ipmi completion code plus response data 2755f4194eeSjayaprakash Mutyala * - countWritten - Count written 2765f4194eeSjayaprakash Mutyala */ 2775f4194eeSjayaprakash Mutyala ipmi::RspType<uint8_t, // Count 2785f4194eeSjayaprakash Mutyala std::vector<uint8_t> // Requested data 2795f4194eeSjayaprakash Mutyala > 2805f4194eeSjayaprakash Mutyala ipmiStorageReadFruData(uint8_t fruDeviceId, uint16_t fruInventoryOffset, 2815f4194eeSjayaprakash Mutyala uint8_t countToRead) 282e2d1aee3SJason M. Bills { 2835f4194eeSjayaprakash Mutyala if (fruDeviceId == 0xFF) 284e2d1aee3SJason M. Bills { 2855f4194eeSjayaprakash Mutyala return ipmi::responseInvalidFieldRequest(); 286e2d1aee3SJason M. Bills } 287e2d1aee3SJason M. Bills 2885f4194eeSjayaprakash Mutyala ipmi::Cc status = replaceCacheFru(fruDeviceId); 289e2d1aee3SJason M. Bills 2905f4194eeSjayaprakash Mutyala if (status != ipmi::ccSuccess) 2915f4194eeSjayaprakash Mutyala { 2925f4194eeSjayaprakash Mutyala return ipmi::response(status); 293e2d1aee3SJason M. Bills } 294e2d1aee3SJason M. Bills 2955f4194eeSjayaprakash Mutyala size_t fromFruByteLen = 0; 2965f4194eeSjayaprakash Mutyala if (countToRead + fruInventoryOffset < fruCache.size()) 297e2d1aee3SJason M. Bills { 2985f4194eeSjayaprakash Mutyala fromFruByteLen = countToRead; 2995f4194eeSjayaprakash Mutyala } 3005f4194eeSjayaprakash Mutyala else if (fruCache.size() > fruInventoryOffset) 301e2d1aee3SJason M. Bills { 3025f4194eeSjayaprakash Mutyala fromFruByteLen = fruCache.size() - fruInventoryOffset; 3035f4194eeSjayaprakash Mutyala } 3045f4194eeSjayaprakash Mutyala else 3055f4194eeSjayaprakash Mutyala { 3065f4194eeSjayaprakash Mutyala return ipmi::responseInvalidFieldRequest(); 307e2d1aee3SJason M. Bills } 308e2d1aee3SJason M. Bills 3095f4194eeSjayaprakash Mutyala std::vector<uint8_t> requestedData; 310e2d1aee3SJason M. Bills 3115f4194eeSjayaprakash Mutyala requestedData.insert( 3125f4194eeSjayaprakash Mutyala requestedData.begin(), fruCache.begin() + fruInventoryOffset, 3135f4194eeSjayaprakash Mutyala fruCache.begin() + fruInventoryOffset + fromFruByteLen); 3145f4194eeSjayaprakash Mutyala 3155f4194eeSjayaprakash Mutyala return ipmi::responseSuccess(countToRead, requestedData); 316e2d1aee3SJason M. Bills } 3175f4194eeSjayaprakash Mutyala 3185f4194eeSjayaprakash Mutyala /** @brief implements the write FRU data command 3195f4194eeSjayaprakash Mutyala * @param fruDeviceId - FRU Device ID 3205f4194eeSjayaprakash Mutyala * @param fruInventoryOffset - FRU Inventory Offset to write 3215f4194eeSjayaprakash Mutyala * @param dataToWrite - Data to write 3225f4194eeSjayaprakash Mutyala * 3235f4194eeSjayaprakash Mutyala * @returns ipmi completion code plus response data 3245f4194eeSjayaprakash Mutyala * - countWritten - Count written 3255f4194eeSjayaprakash Mutyala */ 3265f4194eeSjayaprakash Mutyala ipmi::RspType<uint8_t> 3275f4194eeSjayaprakash Mutyala ipmiStorageWriteFruData(uint8_t fruDeviceId, uint16_t fruInventoryOffset, 3285f4194eeSjayaprakash Mutyala std::vector<uint8_t>& dataToWrite) 3295f4194eeSjayaprakash Mutyala { 3305f4194eeSjayaprakash Mutyala if (fruDeviceId == 0xFF) 3315f4194eeSjayaprakash Mutyala { 3325f4194eeSjayaprakash Mutyala return ipmi::responseInvalidFieldRequest(); 3335f4194eeSjayaprakash Mutyala } 3345f4194eeSjayaprakash Mutyala 3355f4194eeSjayaprakash Mutyala size_t writeLen = dataToWrite.size(); 3365f4194eeSjayaprakash Mutyala 3375f4194eeSjayaprakash Mutyala ipmi::Cc status = replaceCacheFru(fruDeviceId); 3385f4194eeSjayaprakash Mutyala if (status != ipmi::ccSuccess) 3395f4194eeSjayaprakash Mutyala { 3405f4194eeSjayaprakash Mutyala return ipmi::response(status); 3415f4194eeSjayaprakash Mutyala } 3425f4194eeSjayaprakash Mutyala int lastWriteAddr = fruInventoryOffset + writeLen; 343e2d1aee3SJason M. Bills if (fruCache.size() < lastWriteAddr) 344e2d1aee3SJason M. Bills { 3455f4194eeSjayaprakash Mutyala fruCache.resize(fruInventoryOffset + writeLen); 346e2d1aee3SJason M. Bills } 347e2d1aee3SJason M. Bills 3485f4194eeSjayaprakash Mutyala std::copy(dataToWrite.begin(), dataToWrite.begin() + writeLen, 3495f4194eeSjayaprakash Mutyala fruCache.begin() + fruInventoryOffset); 350e2d1aee3SJason M. Bills 351e2d1aee3SJason M. Bills bool atEnd = false; 352e2d1aee3SJason M. Bills 353e2d1aee3SJason M. Bills if (fruCache.size() >= sizeof(FRUHeader)) 354e2d1aee3SJason M. Bills { 355e2d1aee3SJason M. Bills FRUHeader* header = reinterpret_cast<FRUHeader*>(fruCache.data()); 356e2d1aee3SJason M. Bills 357e2d1aee3SJason M. Bills int lastRecordStart = std::max( 358e2d1aee3SJason M. Bills header->internalOffset, 359e2d1aee3SJason M. Bills std::max(header->chassisOffset, 360e2d1aee3SJason M. Bills std::max(header->boardOffset, header->productOffset))); 361e2d1aee3SJason M. Bills // TODO: Handle Multi-Record FRUs? 362e2d1aee3SJason M. Bills 363e2d1aee3SJason M. Bills lastRecordStart *= 8; // header starts in are multiples of 8 bytes 364e2d1aee3SJason M. Bills 365e2d1aee3SJason M. Bills // get the length of the area in multiples of 8 bytes 366e2d1aee3SJason M. Bills if (lastWriteAddr > (lastRecordStart + 1)) 367e2d1aee3SJason M. Bills { 368e2d1aee3SJason M. Bills // second byte in record area is the length 369e2d1aee3SJason M. Bills int areaLength(fruCache[lastRecordStart + 1]); 370e2d1aee3SJason M. Bills areaLength *= 8; // it is in multiples of 8 bytes 371e2d1aee3SJason M. Bills 372e2d1aee3SJason M. Bills if (lastWriteAddr >= (areaLength + lastRecordStart)) 373e2d1aee3SJason M. Bills { 374e2d1aee3SJason M. Bills atEnd = true; 375e2d1aee3SJason M. Bills } 376e2d1aee3SJason M. Bills } 377e2d1aee3SJason M. Bills } 3785f4194eeSjayaprakash Mutyala uint8_t countWritten = 0; 379e2d1aee3SJason M. Bills if (atEnd) 380e2d1aee3SJason M. Bills { 381e2d1aee3SJason M. Bills // cancel timer, we're at the end so might as well send it 382e2d1aee3SJason M. Bills cacheTimer->stop(); 383e2d1aee3SJason M. Bills if (!writeFru()) 384e2d1aee3SJason M. Bills { 3855f4194eeSjayaprakash Mutyala return ipmi::responseInvalidFieldRequest(); 386e2d1aee3SJason M. Bills } 3875f4194eeSjayaprakash Mutyala countWritten = std::min(fruCache.size(), static_cast<size_t>(0xFF)); 388e2d1aee3SJason M. Bills } 389e2d1aee3SJason M. Bills else 390e2d1aee3SJason M. Bills { 391e2d1aee3SJason M. Bills // start a timer, if no further data is sent in cacheTimeoutSeconds 392e2d1aee3SJason M. Bills // seconds, check to see if it is valid 393e2d1aee3SJason M. Bills createTimer(); 394e2d1aee3SJason M. Bills cacheTimer->start(std::chrono::duration_cast<std::chrono::microseconds>( 395e2d1aee3SJason M. Bills std::chrono::seconds(cacheTimeoutSeconds))); 3965f4194eeSjayaprakash Mutyala countWritten = 0; 397e2d1aee3SJason M. Bills } 398e2d1aee3SJason M. Bills 3995f4194eeSjayaprakash Mutyala return ipmi::responseSuccess(countWritten); 400e2d1aee3SJason M. Bills } 401e2d1aee3SJason M. Bills 402d33acd6bSjayaprakash Mutyala /** @brief implements the get FRU inventory area info command 403d33acd6bSjayaprakash Mutyala * @param fruDeviceId - FRU Device ID 404d33acd6bSjayaprakash Mutyala * 405d33acd6bSjayaprakash Mutyala * @returns IPMI completion code plus response data 406d33acd6bSjayaprakash Mutyala * - inventorySize - Number of possible allocation units 407d33acd6bSjayaprakash Mutyala * - accessType - Allocation unit size in bytes. 408d33acd6bSjayaprakash Mutyala */ 409d33acd6bSjayaprakash Mutyala ipmi::RspType<uint16_t, // inventorySize 410d33acd6bSjayaprakash Mutyala uint8_t> // accessType 411d33acd6bSjayaprakash Mutyala ipmiStorageGetFruInvAreaInfo(uint8_t fruDeviceId) 412e2d1aee3SJason M. Bills { 413d33acd6bSjayaprakash Mutyala if (fruDeviceId == 0xFF) 414e2d1aee3SJason M. Bills { 415d33acd6bSjayaprakash Mutyala return ipmi::responseInvalidFieldRequest(); 416e2d1aee3SJason M. Bills } 417e2d1aee3SJason M. Bills 418d33acd6bSjayaprakash Mutyala ipmi::Cc status = replaceCacheFru(fruDeviceId); 419e2d1aee3SJason M. Bills 420e2d1aee3SJason M. Bills if (status != IPMI_CC_OK) 421e2d1aee3SJason M. Bills { 422d33acd6bSjayaprakash Mutyala return ipmi::response(status); 423e2d1aee3SJason M. Bills } 424e2d1aee3SJason M. Bills 425d33acd6bSjayaprakash Mutyala constexpr uint8_t accessType = 426d33acd6bSjayaprakash Mutyala static_cast<uint8_t>(GetFRUAreaAccessType::byte); 427e2d1aee3SJason M. Bills 428d33acd6bSjayaprakash Mutyala return ipmi::responseSuccess(fruCache.size(), accessType); 429e2d1aee3SJason M. Bills } 430e2d1aee3SJason M. Bills 4313f7c5e40SJason M. Bills ipmi_ret_t getFruSdrCount(size_t& count) 4323f7c5e40SJason M. Bills { 4333f7c5e40SJason M. Bills ipmi_ret_t ret = replaceCacheFru(0); 4343f7c5e40SJason M. Bills if (ret != IPMI_CC_OK) 4353f7c5e40SJason M. Bills { 4363f7c5e40SJason M. Bills return ret; 4373f7c5e40SJason M. Bills } 4383f7c5e40SJason M. Bills count = deviceHashes.size(); 4393f7c5e40SJason M. Bills return IPMI_CC_OK; 4403f7c5e40SJason M. Bills } 4413f7c5e40SJason M. Bills 4423f7c5e40SJason M. Bills ipmi_ret_t getFruSdrs(size_t index, get_sdr::SensorDataFruRecord& resp) 4433f7c5e40SJason M. Bills { 4443f7c5e40SJason M. Bills ipmi_ret_t ret = replaceCacheFru(0); // this will update the hash list 4453f7c5e40SJason M. Bills if (ret != IPMI_CC_OK) 4463f7c5e40SJason M. Bills { 4473f7c5e40SJason M. Bills return ret; 4483f7c5e40SJason M. Bills } 4493f7c5e40SJason M. Bills if (deviceHashes.size() < index) 4503f7c5e40SJason M. Bills { 4513f7c5e40SJason M. Bills return IPMI_CC_INVALID_FIELD_REQUEST; 4523f7c5e40SJason M. Bills } 4533f7c5e40SJason M. Bills auto device = deviceHashes.begin() + index; 4543f7c5e40SJason M. Bills uint8_t& bus = device->second.first; 4553f7c5e40SJason M. Bills uint8_t& address = device->second.second; 4563f7c5e40SJason M. Bills 4573f7c5e40SJason M. Bills ManagedObjectType frus; 4583f7c5e40SJason M. Bills 45915419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 46015419dd5SVernon Mauery sdbusplus::message::message getObjects = dbus->new_method_call( 4613f7c5e40SJason M. Bills fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager", 4623f7c5e40SJason M. Bills "GetManagedObjects"); 4633f7c5e40SJason M. Bills try 4643f7c5e40SJason M. Bills { 46515419dd5SVernon Mauery sdbusplus::message::message resp = dbus->call(getObjects); 4663f7c5e40SJason M. Bills resp.read(frus); 4673f7c5e40SJason M. Bills } 4683f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 4693f7c5e40SJason M. Bills { 4703f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 4713f7c5e40SJason M. Bills } 4723f7c5e40SJason M. Bills boost::container::flat_map<std::string, DbusVariant>* fruData = nullptr; 4733f7c5e40SJason M. Bills auto fru = 4743f7c5e40SJason M. Bills std::find_if(frus.begin(), frus.end(), 4753f7c5e40SJason M. Bills [bus, address, &fruData](ManagedEntry& entry) { 4763f7c5e40SJason M. Bills auto findFruDevice = 4773f7c5e40SJason M. Bills entry.second.find("xyz.openbmc_project.FruDevice"); 4783f7c5e40SJason M. Bills if (findFruDevice == entry.second.end()) 4793f7c5e40SJason M. Bills { 4803f7c5e40SJason M. Bills return false; 4813f7c5e40SJason M. Bills } 4823f7c5e40SJason M. Bills fruData = &(findFruDevice->second); 4833f7c5e40SJason M. Bills auto findBus = findFruDevice->second.find("BUS"); 4843f7c5e40SJason M. Bills auto findAddress = 4853f7c5e40SJason M. Bills findFruDevice->second.find("ADDRESS"); 4863f7c5e40SJason M. Bills if (findBus == findFruDevice->second.end() || 4873f7c5e40SJason M. Bills findAddress == findFruDevice->second.end()) 4883f7c5e40SJason M. Bills { 4893f7c5e40SJason M. Bills return false; 4903f7c5e40SJason M. Bills } 4918166c8d7SVernon Mauery if (std::get<uint32_t>(findBus->second) != bus) 4923f7c5e40SJason M. Bills { 4933f7c5e40SJason M. Bills return false; 4943f7c5e40SJason M. Bills } 4958166c8d7SVernon Mauery if (std::get<uint32_t>(findAddress->second) != address) 4963f7c5e40SJason M. Bills { 4973f7c5e40SJason M. Bills return false; 4983f7c5e40SJason M. Bills } 4993f7c5e40SJason M. Bills return true; 5003f7c5e40SJason M. Bills }); 5013f7c5e40SJason M. Bills if (fru == frus.end()) 5023f7c5e40SJason M. Bills { 5033f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 5043f7c5e40SJason M. Bills } 505*9ce789fcSPatrick Venture 506*9ce789fcSPatrick Venture boost::container::flat_map<std::string, DbusVariant>* entityData = nullptr; 507*9ce789fcSPatrick Venture ManagedObjectType entities; 508*9ce789fcSPatrick Venture 509*9ce789fcSPatrick Venture try 510*9ce789fcSPatrick Venture { 511*9ce789fcSPatrick Venture std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 512*9ce789fcSPatrick Venture 513*9ce789fcSPatrick Venture sdbusplus::message::message getObjects = dbus->new_method_call( 514*9ce789fcSPatrick Venture entityManagerServiceName, "/", "org.freedesktop.DBus.ObjectManager", 515*9ce789fcSPatrick Venture "GetManagedObjects"); 516*9ce789fcSPatrick Venture 517*9ce789fcSPatrick Venture sdbusplus::message::message resp = dbus->call(getObjects); 518*9ce789fcSPatrick Venture resp.read(entities); 519*9ce789fcSPatrick Venture 520*9ce789fcSPatrick Venture auto entity = std::find_if( 521*9ce789fcSPatrick Venture entities.begin(), entities.end(), 522*9ce789fcSPatrick Venture [bus, address, &entityData](ManagedEntry& entry) { 523*9ce789fcSPatrick Venture auto findFruDevice = entry.second.find( 524*9ce789fcSPatrick Venture "xyz.openbmc_project.Inventory.Decorator.FruDevice"); 525*9ce789fcSPatrick Venture if (findFruDevice == entry.second.end()) 526*9ce789fcSPatrick Venture { 527*9ce789fcSPatrick Venture return false; 528*9ce789fcSPatrick Venture } 529*9ce789fcSPatrick Venture 530*9ce789fcSPatrick Venture // Integer fields added via Entity-Manager json are uint64_ts by 531*9ce789fcSPatrick Venture // default. 532*9ce789fcSPatrick Venture auto findBus = findFruDevice->second.find("Bus"); 533*9ce789fcSPatrick Venture auto findAddress = findFruDevice->second.find("Address"); 534*9ce789fcSPatrick Venture 535*9ce789fcSPatrick Venture if (findBus == findFruDevice->second.end() || 536*9ce789fcSPatrick Venture findAddress == findFruDevice->second.end()) 537*9ce789fcSPatrick Venture { 538*9ce789fcSPatrick Venture return false; 539*9ce789fcSPatrick Venture } 540*9ce789fcSPatrick Venture if ((std::get<uint64_t>(findBus->second) != bus) || 541*9ce789fcSPatrick Venture (std::get<uint64_t>(findAddress->second) != address)) 542*9ce789fcSPatrick Venture { 543*9ce789fcSPatrick Venture return false; 544*9ce789fcSPatrick Venture } 545*9ce789fcSPatrick Venture 546*9ce789fcSPatrick Venture auto findIpmiDevice = entry.second.find( 547*9ce789fcSPatrick Venture "xyz.openbmc_project.Inventory.Decorator.Ipmi"); 548*9ce789fcSPatrick Venture if (findIpmiDevice == entry.second.end()) 549*9ce789fcSPatrick Venture { 550*9ce789fcSPatrick Venture return false; 551*9ce789fcSPatrick Venture } 552*9ce789fcSPatrick Venture 553*9ce789fcSPatrick Venture entityData = &(findIpmiDevice->second); 554*9ce789fcSPatrick Venture return true; 555*9ce789fcSPatrick Venture }); 556*9ce789fcSPatrick Venture 557*9ce789fcSPatrick Venture if (entity == entities.end()) 558*9ce789fcSPatrick Venture { 559*9ce789fcSPatrick Venture if constexpr (DEBUG) 560*9ce789fcSPatrick Venture { 561*9ce789fcSPatrick Venture std::fprintf(stderr, "Ipmi or FruDevice Decorator interface " 562*9ce789fcSPatrick Venture "not found for Fru\n"); 563*9ce789fcSPatrick Venture } 564*9ce789fcSPatrick Venture } 565*9ce789fcSPatrick Venture } 566*9ce789fcSPatrick Venture catch (const std::exception& e) 567*9ce789fcSPatrick Venture { 568*9ce789fcSPatrick Venture std::fprintf( 569*9ce789fcSPatrick Venture stderr, 570*9ce789fcSPatrick Venture "Search for FruDevice+Ipmi Decorator Interface excepted: '%s'\n", 571*9ce789fcSPatrick Venture e.what()); 572*9ce789fcSPatrick Venture } 573*9ce789fcSPatrick Venture 5743f7c5e40SJason M. Bills std::string name; 5753f7c5e40SJason M. Bills auto findProductName = fruData->find("BOARD_PRODUCT_NAME"); 5763f7c5e40SJason M. Bills auto findBoardName = fruData->find("PRODUCT_PRODUCT_NAME"); 5773f7c5e40SJason M. Bills if (findProductName != fruData->end()) 5783f7c5e40SJason M. Bills { 5798166c8d7SVernon Mauery name = std::get<std::string>(findProductName->second); 5803f7c5e40SJason M. Bills } 5813f7c5e40SJason M. Bills else if (findBoardName != fruData->end()) 5823f7c5e40SJason M. Bills { 5838166c8d7SVernon Mauery name = std::get<std::string>(findBoardName->second); 5843f7c5e40SJason M. Bills } 5853f7c5e40SJason M. Bills else 5863f7c5e40SJason M. Bills { 5873f7c5e40SJason M. Bills name = "UNKNOWN"; 5883f7c5e40SJason M. Bills } 5893f7c5e40SJason M. Bills if (name.size() > maxFruSdrNameSize) 5903f7c5e40SJason M. Bills { 5913f7c5e40SJason M. Bills name = name.substr(0, maxFruSdrNameSize); 5923f7c5e40SJason M. Bills } 5933f7c5e40SJason M. Bills size_t sizeDiff = maxFruSdrNameSize - name.size(); 5943f7c5e40SJason M. Bills 5953f7c5e40SJason M. Bills resp.header.record_id_lsb = 0x0; // calling code is to implement these 5963f7c5e40SJason M. Bills resp.header.record_id_msb = 0x0; 5973f7c5e40SJason M. Bills resp.header.sdr_version = ipmiSdrVersion; 59873d0135dSPatrick Venture resp.header.record_type = get_sdr::SENSOR_DATA_FRU_RECORD; 5993f7c5e40SJason M. Bills resp.header.record_length = sizeof(resp.body) + sizeof(resp.key) - sizeDiff; 6003f7c5e40SJason M. Bills resp.key.deviceAddress = 0x20; 6013f7c5e40SJason M. Bills resp.key.fruID = device->first; 6023f7c5e40SJason M. Bills resp.key.accessLun = 0x80; // logical / physical fru device 6033f7c5e40SJason M. Bills resp.key.channelNumber = 0x0; 6043f7c5e40SJason M. Bills resp.body.reserved = 0x0; 6053f7c5e40SJason M. Bills resp.body.deviceType = 0x10; 6064f86d1f2SJames Feist resp.body.deviceTypeModifier = 0x0; 607*9ce789fcSPatrick Venture 608*9ce789fcSPatrick Venture uint8_t entityID = 0; 609*9ce789fcSPatrick Venture uint8_t entityInstance = 0x1; 610*9ce789fcSPatrick Venture 611*9ce789fcSPatrick Venture if (entityData) 612*9ce789fcSPatrick Venture { 613*9ce789fcSPatrick Venture auto entityIdProperty = entityData->find("EntityId"); 614*9ce789fcSPatrick Venture auto entityInstanceProperty = entityData->find("EntityInstance"); 615*9ce789fcSPatrick Venture 616*9ce789fcSPatrick Venture if (entityIdProperty != entityData->end()) 617*9ce789fcSPatrick Venture { 618*9ce789fcSPatrick Venture entityID = static_cast<uint8_t>( 619*9ce789fcSPatrick Venture std::get<uint64_t>(entityIdProperty->second)); 620*9ce789fcSPatrick Venture } 621*9ce789fcSPatrick Venture if (entityInstanceProperty != entityData->end()) 622*9ce789fcSPatrick Venture { 623*9ce789fcSPatrick Venture entityInstance = static_cast<uint8_t>( 624*9ce789fcSPatrick Venture std::get<uint64_t>(entityInstanceProperty->second)); 625*9ce789fcSPatrick Venture } 626*9ce789fcSPatrick Venture } 627*9ce789fcSPatrick Venture 628*9ce789fcSPatrick Venture resp.body.entityID = entityID; 629*9ce789fcSPatrick Venture resp.body.entityInstance = entityInstance; 630*9ce789fcSPatrick Venture 6313f7c5e40SJason M. Bills resp.body.oem = 0x0; 6323f7c5e40SJason M. Bills resp.body.deviceIDLen = name.size(); 6333f7c5e40SJason M. Bills name.copy(resp.body.deviceID, name.size()); 6343f7c5e40SJason M. Bills 6353f7c5e40SJason M. Bills return IPMI_CC_OK; 6363f7c5e40SJason M. Bills } 637e2d1aee3SJason M. Bills 6381d4d54ddSJason M. Bills static bool getSELLogFiles(std::vector<std::filesystem::path>& selLogFiles) 639c04e2e70SJason M. Bills { 6401d4d54ddSJason M. Bills // Loop through the directory looking for ipmi_sel log files 6411d4d54ddSJason M. Bills for (const std::filesystem::directory_entry& dirEnt : 6421d4d54ddSJason M. Bills std::filesystem::directory_iterator(intel_oem::ipmi::sel::selLogDir)) 643c04e2e70SJason M. Bills { 6441d4d54ddSJason M. Bills std::string filename = dirEnt.path().filename(); 6451d4d54ddSJason M. Bills if (boost::starts_with(filename, intel_oem::ipmi::sel::selLogFilename)) 6461d4d54ddSJason M. Bills { 6471d4d54ddSJason M. Bills // If we find an ipmi_sel log file, save the path 6481d4d54ddSJason M. Bills selLogFiles.emplace_back(intel_oem::ipmi::sel::selLogDir / 6491d4d54ddSJason M. Bills filename); 650c04e2e70SJason M. Bills } 651c04e2e70SJason M. Bills } 6521d4d54ddSJason M. Bills // As the log files rotate, they are appended with a ".#" that is higher for 6531d4d54ddSJason M. Bills // the older logs. Since we don't expect more than 10 log files, we 6541d4d54ddSJason M. Bills // can just sort the list to get them in order from newest to oldest 6551d4d54ddSJason M. Bills std::sort(selLogFiles.begin(), selLogFiles.end()); 656c04e2e70SJason M. Bills 6571d4d54ddSJason M. Bills return !selLogFiles.empty(); 658c04e2e70SJason M. Bills } 659c04e2e70SJason M. Bills 6601d4d54ddSJason M. Bills static int countSELEntries() 6611d4d54ddSJason M. Bills { 6621d4d54ddSJason M. Bills // Get the list of ipmi_sel log files 6631d4d54ddSJason M. Bills std::vector<std::filesystem::path> selLogFiles; 6641d4d54ddSJason M. Bills if (!getSELLogFiles(selLogFiles)) 6651d4d54ddSJason M. Bills { 6661d4d54ddSJason M. Bills return 0; 6671d4d54ddSJason M. Bills } 6681d4d54ddSJason M. Bills int numSELEntries = 0; 6691d4d54ddSJason M. Bills // Loop through each log file and count the number of logs 6701d4d54ddSJason M. Bills for (const std::filesystem::path& file : selLogFiles) 6711d4d54ddSJason M. Bills { 6721d4d54ddSJason M. Bills std::ifstream logStream(file); 6731d4d54ddSJason M. Bills if (!logStream.is_open()) 6741d4d54ddSJason M. Bills { 6751d4d54ddSJason M. Bills continue; 6761d4d54ddSJason M. Bills } 6771d4d54ddSJason M. Bills 6781d4d54ddSJason M. Bills std::string line; 6791d4d54ddSJason M. Bills while (std::getline(logStream, line)) 6801d4d54ddSJason M. Bills { 6811d4d54ddSJason M. Bills numSELEntries++; 6821d4d54ddSJason M. Bills } 6831d4d54ddSJason M. Bills } 6841d4d54ddSJason M. Bills return numSELEntries; 6851d4d54ddSJason M. Bills } 6861d4d54ddSJason M. Bills 6871d4d54ddSJason M. Bills static bool findSELEntry(const int recordID, 688ff7e15b2SPatrick Venture const std::vector<std::filesystem::path>& selLogFiles, 6891d4d54ddSJason M. Bills std::string& entry) 6901d4d54ddSJason M. Bills { 6911d4d54ddSJason M. Bills // Record ID is the first entry field following the timestamp. It is 6921d4d54ddSJason M. Bills // preceded by a space and followed by a comma 6931d4d54ddSJason M. Bills std::string search = " " + std::to_string(recordID) + ","; 6941d4d54ddSJason M. Bills 6951d4d54ddSJason M. Bills // Loop through the ipmi_sel log entries 6961d4d54ddSJason M. Bills for (const std::filesystem::path& file : selLogFiles) 6971d4d54ddSJason M. Bills { 6981d4d54ddSJason M. Bills std::ifstream logStream(file); 6991d4d54ddSJason M. Bills if (!logStream.is_open()) 7001d4d54ddSJason M. Bills { 7011d4d54ddSJason M. Bills continue; 7021d4d54ddSJason M. Bills } 7031d4d54ddSJason M. Bills 7041d4d54ddSJason M. Bills while (std::getline(logStream, entry)) 7051d4d54ddSJason M. Bills { 7061d4d54ddSJason M. Bills // Check if the record ID matches 7071d4d54ddSJason M. Bills if (entry.find(search) != std::string::npos) 7081d4d54ddSJason M. Bills { 7091d4d54ddSJason M. Bills return true; 7101d4d54ddSJason M. Bills } 7111d4d54ddSJason M. Bills } 7121d4d54ddSJason M. Bills } 7131d4d54ddSJason M. Bills return false; 7141d4d54ddSJason M. Bills } 7151d4d54ddSJason M. Bills 7161d4d54ddSJason M. Bills static uint16_t 7171d4d54ddSJason M. Bills getNextRecordID(const uint16_t recordID, 718ff7e15b2SPatrick Venture const std::vector<std::filesystem::path>& selLogFiles) 7191d4d54ddSJason M. Bills { 7201d4d54ddSJason M. Bills uint16_t nextRecordID = recordID + 1; 7211d4d54ddSJason M. Bills std::string entry; 7221d4d54ddSJason M. Bills if (findSELEntry(nextRecordID, selLogFiles, entry)) 7231d4d54ddSJason M. Bills { 7241d4d54ddSJason M. Bills return nextRecordID; 7251d4d54ddSJason M. Bills } 7261d4d54ddSJason M. Bills else 7271d4d54ddSJason M. Bills { 7281d4d54ddSJason M. Bills return ipmi::sel::lastEntry; 7291d4d54ddSJason M. Bills } 730c04e2e70SJason M. Bills } 731c04e2e70SJason M. Bills 732ff7e15b2SPatrick Venture static int fromHexStr(const std::string& hexStr, std::vector<uint8_t>& data) 733c04e2e70SJason M. Bills { 734c04e2e70SJason M. Bills for (unsigned int i = 0; i < hexStr.size(); i += 2) 735c04e2e70SJason M. Bills { 736c04e2e70SJason M. Bills try 737c04e2e70SJason M. Bills { 738c04e2e70SJason M. Bills data.push_back(static_cast<uint8_t>( 739c04e2e70SJason M. Bills std::stoul(hexStr.substr(i, 2), nullptr, 16))); 740c04e2e70SJason M. Bills } 741c04e2e70SJason M. Bills catch (std::invalid_argument& e) 742c04e2e70SJason M. Bills { 743c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 744c04e2e70SJason M. Bills return -1; 745c04e2e70SJason M. Bills } 746c04e2e70SJason M. Bills catch (std::out_of_range& e) 747c04e2e70SJason M. Bills { 748c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 749c04e2e70SJason M. Bills return -1; 750c04e2e70SJason M. Bills } 751c04e2e70SJason M. Bills } 752c04e2e70SJason M. Bills return 0; 753c04e2e70SJason M. Bills } 754c04e2e70SJason M. Bills 7551d4d54ddSJason M. Bills ipmi::RspType<uint8_t, // SEL version 7561d4d54ddSJason M. Bills uint16_t, // SEL entry count 7571d4d54ddSJason M. Bills uint16_t, // free space 7581d4d54ddSJason M. Bills uint32_t, // last add timestamp 7591d4d54ddSJason M. Bills uint32_t, // last erase timestamp 7601d4d54ddSJason M. Bills uint8_t> // operation support 7611d4d54ddSJason M. Bills ipmiStorageGetSELInfo() 762c04e2e70SJason M. Bills { 7631d4d54ddSJason M. Bills constexpr uint8_t selVersion = ipmi::sel::selVersion; 7641d4d54ddSJason M. Bills uint16_t entries = countSELEntries(); 7651d4d54ddSJason M. Bills uint32_t addTimeStamp = intel_oem::ipmi::sel::getFileTimestamp( 7661d4d54ddSJason M. Bills intel_oem::ipmi::sel::selLogDir / intel_oem::ipmi::sel::selLogFilename); 7671d4d54ddSJason M. Bills uint32_t eraseTimeStamp = intel_oem::ipmi::sel::erase_time::get(); 7681d4d54ddSJason M. Bills constexpr uint8_t operationSupport = 7691d4d54ddSJason M. Bills intel_oem::ipmi::sel::selOperationSupport; 7701d4d54ddSJason M. Bills constexpr uint16_t freeSpace = 7711d4d54ddSJason M. Bills 0xffff; // Spec indicates that more than 64kB is free 772c04e2e70SJason M. Bills 7731d4d54ddSJason M. Bills return ipmi::responseSuccess(selVersion, entries, freeSpace, addTimeStamp, 7741d4d54ddSJason M. Bills eraseTimeStamp, operationSupport); 775c04e2e70SJason M. Bills } 776c04e2e70SJason M. Bills 7771d4d54ddSJason M. Bills using systemEventType = std::tuple< 7781d4d54ddSJason M. Bills uint32_t, // Timestamp 7791d4d54ddSJason M. Bills uint16_t, // Generator ID 7801d4d54ddSJason M. Bills uint8_t, // EvM Rev 7811d4d54ddSJason M. Bills uint8_t, // Sensor Type 7821d4d54ddSJason M. Bills uint8_t, // Sensor Number 7831d4d54ddSJason M. Bills uint7_t, // Event Type 7841d4d54ddSJason M. Bills bool, // Event Direction 7851d4d54ddSJason M. Bills std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize>>; // Event Data 7861d4d54ddSJason M. Bills using oemTsEventType = std::tuple< 7871d4d54ddSJason M. Bills uint32_t, // Timestamp 7881d4d54ddSJason M. Bills std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize>>; // Event Data 7891d4d54ddSJason M. Bills using oemEventType = 7901d4d54ddSJason M. Bills std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize>; // Event Data 7911d4d54ddSJason M. Bills 7921d4d54ddSJason M. Bills ipmi::RspType<uint16_t, // Next Record ID 7931d4d54ddSJason M. Bills uint16_t, // Record ID 7941d4d54ddSJason M. Bills uint8_t, // Record Type 7951d4d54ddSJason M. Bills std::variant<systemEventType, oemTsEventType, 7961d4d54ddSJason M. Bills oemEventType>> // Record Content 7971d4d54ddSJason M. Bills ipmiStorageGetSELEntry(uint16_t reservationID, uint16_t targetID, 7981d4d54ddSJason M. Bills uint8_t offset, uint8_t size) 799c04e2e70SJason M. Bills { 8001d4d54ddSJason M. Bills // Only support getting the entire SEL record. If a partial size or non-zero 8011d4d54ddSJason M. Bills // offset is requested, return an error 8021d4d54ddSJason M. Bills if (offset != 0 || size != ipmi::sel::entireRecord) 803c04e2e70SJason M. Bills { 8041d4d54ddSJason M. Bills return ipmi::responseRetBytesUnavailable(); 805c04e2e70SJason M. Bills } 806c04e2e70SJason M. Bills 8071d4d54ddSJason M. Bills // Check the reservation ID if one is provided or required (only if the 8081d4d54ddSJason M. Bills // offset is non-zero) 8091d4d54ddSJason M. Bills if (reservationID != 0 || offset != 0) 810c04e2e70SJason M. Bills { 8111d4d54ddSJason M. Bills if (!checkSELReservation(reservationID)) 812c04e2e70SJason M. Bills { 8131d4d54ddSJason M. Bills return ipmi::responseInvalidReservationId(); 814c04e2e70SJason M. Bills } 815c04e2e70SJason M. Bills } 816c04e2e70SJason M. Bills 8171d4d54ddSJason M. Bills // Get the ipmi_sel log files 8181d4d54ddSJason M. Bills std::vector<std::filesystem::path> selLogFiles; 8191d4d54ddSJason M. Bills if (!getSELLogFiles(selLogFiles)) 820c04e2e70SJason M. Bills { 8211d4d54ddSJason M. Bills return ipmi::responseSensorInvalid(); 822c04e2e70SJason M. Bills } 823c04e2e70SJason M. Bills 8241d4d54ddSJason M. Bills std::string targetEntry; 825c04e2e70SJason M. Bills 826c04e2e70SJason M. Bills if (targetID == ipmi::sel::firstEntry) 827c04e2e70SJason M. Bills { 8281d4d54ddSJason M. Bills // The first entry will be at the top of the oldest log file 8291d4d54ddSJason M. Bills std::ifstream logStream(selLogFiles.back()); 8301d4d54ddSJason M. Bills if (!logStream.is_open()) 831c04e2e70SJason M. Bills { 8321d4d54ddSJason M. Bills return ipmi::responseUnspecifiedError(); 833c04e2e70SJason M. Bills } 8341d4d54ddSJason M. Bills 8351d4d54ddSJason M. Bills if (!std::getline(logStream, targetEntry)) 8361d4d54ddSJason M. Bills { 8371d4d54ddSJason M. Bills return ipmi::responseUnspecifiedError(); 838c04e2e70SJason M. Bills } 839c04e2e70SJason M. Bills } 840c04e2e70SJason M. Bills else if (targetID == ipmi::sel::lastEntry) 841c04e2e70SJason M. Bills { 8421d4d54ddSJason M. Bills // The last entry will be at the bottom of the newest log file 8431d4d54ddSJason M. Bills std::ifstream logStream(selLogFiles.front()); 8441d4d54ddSJason M. Bills if (!logStream.is_open()) 845c04e2e70SJason M. Bills { 8461d4d54ddSJason M. Bills return ipmi::responseUnspecifiedError(); 847c04e2e70SJason M. Bills } 848c04e2e70SJason M. Bills 8491d4d54ddSJason M. Bills std::string line; 8501d4d54ddSJason M. Bills while (std::getline(logStream, line)) 851c04e2e70SJason M. Bills { 8521d4d54ddSJason M. Bills targetEntry = line; 853c04e2e70SJason M. Bills } 854c04e2e70SJason M. Bills } 855c04e2e70SJason M. Bills else 856c04e2e70SJason M. Bills { 8571d4d54ddSJason M. Bills if (!findSELEntry(targetID, selLogFiles, targetEntry)) 858c04e2e70SJason M. Bills { 8591d4d54ddSJason M. Bills return ipmi::responseSensorInvalid(); 8601d4d54ddSJason M. Bills } 861c04e2e70SJason M. Bills } 862c04e2e70SJason M. Bills 86352aaa7d5SJason M. Bills // The format of the ipmi_sel message is "<Timestamp> 86452aaa7d5SJason M. Bills // <ID>,<Type>,<EventData>,[<Generator ID>,<Path>,<Direction>]". 86552aaa7d5SJason M. Bills // First get the Timestamp 86652aaa7d5SJason M. Bills size_t space = targetEntry.find_first_of(" "); 86752aaa7d5SJason M. Bills if (space == std::string::npos) 86852aaa7d5SJason M. Bills { 86952aaa7d5SJason M. Bills return ipmi::responseUnspecifiedError(); 87052aaa7d5SJason M. Bills } 87152aaa7d5SJason M. Bills std::string entryTimestamp = targetEntry.substr(0, space); 87252aaa7d5SJason M. Bills // Then get the log contents 87352aaa7d5SJason M. Bills size_t entryStart = targetEntry.find_first_not_of(" ", space); 87452aaa7d5SJason M. Bills if (entryStart == std::string::npos) 87552aaa7d5SJason M. Bills { 87652aaa7d5SJason M. Bills return ipmi::responseUnspecifiedError(); 87752aaa7d5SJason M. Bills } 87852aaa7d5SJason M. Bills std::string_view entry(targetEntry); 87952aaa7d5SJason M. Bills entry.remove_prefix(entryStart); 88052aaa7d5SJason M. Bills // Use split to separate the entry into its fields 8811d4d54ddSJason M. Bills std::vector<std::string> targetEntryFields; 88252aaa7d5SJason M. Bills boost::split(targetEntryFields, entry, boost::is_any_of(","), 8831d4d54ddSJason M. Bills boost::token_compress_on); 88452aaa7d5SJason M. Bills if (targetEntryFields.size() < 3) 8851d4d54ddSJason M. Bills { 8861d4d54ddSJason M. Bills return ipmi::responseUnspecifiedError(); 887c04e2e70SJason M. Bills } 8881a2fbddfSJason M. Bills std::string& recordIDStr = targetEntryFields[0]; 8891a2fbddfSJason M. Bills std::string& recordTypeStr = targetEntryFields[1]; 8901a2fbddfSJason M. Bills std::string& eventDataStr = targetEntryFields[2]; 891c04e2e70SJason M. Bills 8921a2fbddfSJason M. Bills uint16_t recordID; 8931a2fbddfSJason M. Bills uint8_t recordType; 8941a2fbddfSJason M. Bills try 8951a2fbddfSJason M. Bills { 8961a2fbddfSJason M. Bills recordID = std::stoul(recordIDStr); 8971a2fbddfSJason M. Bills recordType = std::stoul(recordTypeStr, nullptr, 16); 8981a2fbddfSJason M. Bills } 8991a2fbddfSJason M. Bills catch (const std::invalid_argument&) 9001a2fbddfSJason M. Bills { 9011a2fbddfSJason M. Bills return ipmi::responseUnspecifiedError(); 9021a2fbddfSJason M. Bills } 9031d4d54ddSJason M. Bills uint16_t nextRecordID = getNextRecordID(recordID, selLogFiles); 9041d4d54ddSJason M. Bills std::vector<uint8_t> eventDataBytes; 9051a2fbddfSJason M. Bills if (fromHexStr(eventDataStr, eventDataBytes) < 0) 9061d4d54ddSJason M. Bills { 9071d4d54ddSJason M. Bills return ipmi::responseUnspecifiedError(); 9081d4d54ddSJason M. Bills } 9091d4d54ddSJason M. Bills 9101d4d54ddSJason M. Bills if (recordType == intel_oem::ipmi::sel::systemEvent) 9111d4d54ddSJason M. Bills { 9121d4d54ddSJason M. Bills // Get the timestamp 9131d4d54ddSJason M. Bills std::tm timeStruct = {}; 91452aaa7d5SJason M. Bills std::istringstream entryStream(entryTimestamp); 9151d4d54ddSJason M. Bills 9161d4d54ddSJason M. Bills uint32_t timestamp = ipmi::sel::invalidTimeStamp; 9171d4d54ddSJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 9181d4d54ddSJason M. Bills { 9191d4d54ddSJason M. Bills timestamp = std::mktime(&timeStruct); 9201d4d54ddSJason M. Bills } 9211d4d54ddSJason M. Bills 9221d4d54ddSJason M. Bills // Set the event message revision 9231d4d54ddSJason M. Bills uint8_t evmRev = intel_oem::ipmi::sel::eventMsgRev; 9241d4d54ddSJason M. Bills 9251a2fbddfSJason M. Bills uint16_t generatorID = 0; 9261a2fbddfSJason M. Bills uint8_t sensorType = 0; 9271a2fbddfSJason M. Bills uint8_t sensorNum = 0xFF; 9281a2fbddfSJason M. Bills uint7_t eventType = 0; 9291a2fbddfSJason M. Bills bool eventDir = 0; 9301a2fbddfSJason M. Bills // System type events should have six fields 9311a2fbddfSJason M. Bills if (targetEntryFields.size() >= 6) 9321a2fbddfSJason M. Bills { 9331a2fbddfSJason M. Bills std::string& generatorIDStr = targetEntryFields[3]; 9341a2fbddfSJason M. Bills std::string& sensorPath = targetEntryFields[4]; 9351a2fbddfSJason M. Bills std::string& eventDirStr = targetEntryFields[5]; 9361a2fbddfSJason M. Bills 9371a2fbddfSJason M. Bills // Get the generator ID 9381a2fbddfSJason M. Bills try 9391a2fbddfSJason M. Bills { 9401a2fbddfSJason M. Bills generatorID = std::stoul(generatorIDStr, nullptr, 16); 9411a2fbddfSJason M. Bills } 9421a2fbddfSJason M. Bills catch (const std::invalid_argument&) 9431a2fbddfSJason M. Bills { 9441a2fbddfSJason M. Bills std::cerr << "Invalid Generator ID\n"; 9451a2fbddfSJason M. Bills } 9461a2fbddfSJason M. Bills 9471d4d54ddSJason M. Bills // Get the sensor type, sensor number, and event type for the sensor 9481a2fbddfSJason M. Bills sensorType = getSensorTypeFromPath(sensorPath); 9491a2fbddfSJason M. Bills sensorNum = getSensorNumberFromPath(sensorPath); 9501a2fbddfSJason M. Bills eventType = getSensorEventTypeFromPath(sensorPath); 9511d4d54ddSJason M. Bills 9521d4d54ddSJason M. Bills // Get the event direction 9531a2fbddfSJason M. Bills try 9541a2fbddfSJason M. Bills { 9551a2fbddfSJason M. Bills eventDir = std::stoul(eventDirStr) ? 0 : 1; 9561a2fbddfSJason M. Bills } 9571a2fbddfSJason M. Bills catch (const std::invalid_argument&) 9581a2fbddfSJason M. Bills { 9591a2fbddfSJason M. Bills std::cerr << "Invalid Event Direction\n"; 9601a2fbddfSJason M. Bills } 9611a2fbddfSJason M. Bills } 9621d4d54ddSJason M. Bills 9631d4d54ddSJason M. Bills // Only keep the eventData bytes that fit in the record 9641d4d54ddSJason M. Bills std::array<uint8_t, intel_oem::ipmi::sel::systemEventSize> eventData{}; 9651d4d54ddSJason M. Bills std::copy_n(eventDataBytes.begin(), 9661d4d54ddSJason M. Bills std::min(eventDataBytes.size(), eventData.size()), 9671d4d54ddSJason M. Bills eventData.begin()); 9681d4d54ddSJason M. Bills 9691d4d54ddSJason M. Bills return ipmi::responseSuccess( 9701d4d54ddSJason M. Bills nextRecordID, recordID, recordType, 9711d4d54ddSJason M. Bills systemEventType{timestamp, generatorID, evmRev, sensorType, 9721d4d54ddSJason M. Bills sensorNum, eventType, eventDir, eventData}); 9731d4d54ddSJason M. Bills } 9741d4d54ddSJason M. Bills else if (recordType >= intel_oem::ipmi::sel::oemTsEventFirst && 9751d4d54ddSJason M. Bills recordType <= intel_oem::ipmi::sel::oemTsEventLast) 9761d4d54ddSJason M. Bills { 9771d4d54ddSJason M. Bills // Get the timestamp 9781d4d54ddSJason M. Bills std::tm timeStruct = {}; 97952aaa7d5SJason M. Bills std::istringstream entryStream(entryTimestamp); 9801d4d54ddSJason M. Bills 9811d4d54ddSJason M. Bills uint32_t timestamp = ipmi::sel::invalidTimeStamp; 9821d4d54ddSJason M. Bills if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S")) 9831d4d54ddSJason M. Bills { 9841d4d54ddSJason M. Bills timestamp = std::mktime(&timeStruct); 9851d4d54ddSJason M. Bills } 9861d4d54ddSJason M. Bills 9871d4d54ddSJason M. Bills // Only keep the bytes that fit in the record 9881d4d54ddSJason M. Bills std::array<uint8_t, intel_oem::ipmi::sel::oemTsEventSize> eventData{}; 9891d4d54ddSJason M. Bills std::copy_n(eventDataBytes.begin(), 9901d4d54ddSJason M. Bills std::min(eventDataBytes.size(), eventData.size()), 9911d4d54ddSJason M. Bills eventData.begin()); 9921d4d54ddSJason M. Bills 9931d4d54ddSJason M. Bills return ipmi::responseSuccess(nextRecordID, recordID, recordType, 9941d4d54ddSJason M. Bills oemTsEventType{timestamp, eventData}); 9951d4d54ddSJason M. Bills } 996c5136aaaSPatrick Venture else if (recordType >= intel_oem::ipmi::sel::oemEventFirst) 9971d4d54ddSJason M. Bills { 9981d4d54ddSJason M. Bills // Only keep the bytes that fit in the record 9991d4d54ddSJason M. Bills std::array<uint8_t, intel_oem::ipmi::sel::oemEventSize> eventData{}; 10001d4d54ddSJason M. Bills std::copy_n(eventDataBytes.begin(), 10011d4d54ddSJason M. Bills std::min(eventDataBytes.size(), eventData.size()), 10021d4d54ddSJason M. Bills eventData.begin()); 10031d4d54ddSJason M. Bills 10041d4d54ddSJason M. Bills return ipmi::responseSuccess(nextRecordID, recordID, recordType, 10051d4d54ddSJason M. Bills eventData); 10061d4d54ddSJason M. Bills } 10071d4d54ddSJason M. Bills 10081d4d54ddSJason M. Bills return ipmi::responseUnspecifiedError(); 1009c04e2e70SJason M. Bills } 1010c04e2e70SJason M. Bills 10116dd8f047SJason M. Bills ipmi::RspType<uint16_t> ipmiStorageAddSELEntry( 10126dd8f047SJason M. Bills uint16_t recordID, uint8_t recordType, uint32_t timestamp, 10136dd8f047SJason M. Bills uint16_t generatorID, uint8_t evmRev, uint8_t sensorType, uint8_t sensorNum, 10146dd8f047SJason M. Bills uint8_t eventType, uint8_t eventData1, uint8_t eventData2, 10156dd8f047SJason M. Bills uint8_t eventData3) 1016c04e2e70SJason M. Bills { 1017c04e2e70SJason M. Bills // Per the IPMI spec, need to cancel any reservation when a SEL entry is 1018c04e2e70SJason M. Bills // added 1019c04e2e70SJason M. Bills cancelSELReservation(); 1020c04e2e70SJason M. Bills 10216dd8f047SJason M. Bills // Send this request to the Redfish hooks to log it as a Redfish message 10226dd8f047SJason M. Bills // instead. There is no need to add it to the SEL, so just return success. 10236dd8f047SJason M. Bills intel_oem::ipmi::sel::checkRedfishHooks( 10246dd8f047SJason M. Bills recordID, recordType, timestamp, generatorID, evmRev, sensorType, 10256dd8f047SJason M. Bills sensorNum, eventType, eventData1, eventData2, eventData3); 102699b78ec8SJason M. Bills 10276dd8f047SJason M. Bills uint16_t responseID = 0xFFFF; 10286dd8f047SJason M. Bills return ipmi::responseSuccess(responseID); 1029c04e2e70SJason M. Bills } 1030c04e2e70SJason M. Bills 10311d4d54ddSJason M. Bills ipmi::RspType<uint8_t> ipmiStorageClearSEL(ipmi::Context::ptr ctx, 10321d4d54ddSJason M. Bills uint16_t reservationID, 10331d4d54ddSJason M. Bills const std::array<uint8_t, 3>& clr, 10341d4d54ddSJason M. Bills uint8_t eraseOperation) 1035c04e2e70SJason M. Bills { 10361d4d54ddSJason M. Bills if (!checkSELReservation(reservationID)) 1037c04e2e70SJason M. Bills { 10381d4d54ddSJason M. Bills return ipmi::responseInvalidReservationId(); 1039c04e2e70SJason M. Bills } 1040c04e2e70SJason M. Bills 10411d4d54ddSJason M. Bills static constexpr std::array<uint8_t, 3> clrExpected = {'C', 'L', 'R'}; 10421d4d54ddSJason M. Bills if (clr != clrExpected) 1043c04e2e70SJason M. Bills { 10441d4d54ddSJason M. Bills return ipmi::responseInvalidFieldRequest(); 1045c04e2e70SJason M. Bills } 1046c04e2e70SJason M. Bills 10471d4d54ddSJason M. Bills // Erasure status cannot be fetched, so always return erasure status as 10481d4d54ddSJason M. Bills // `erase completed`. 10491d4d54ddSJason M. Bills if (eraseOperation == ipmi::sel::getEraseStatus) 1050c04e2e70SJason M. Bills { 10511d4d54ddSJason M. Bills return ipmi::responseSuccess(ipmi::sel::eraseComplete); 1052c04e2e70SJason M. Bills } 1053c04e2e70SJason M. Bills 10541d4d54ddSJason M. Bills // Check that initiate erase is correct 10551d4d54ddSJason M. Bills if (eraseOperation != ipmi::sel::initiateErase) 10561d4d54ddSJason M. Bills { 10571d4d54ddSJason M. Bills return ipmi::responseInvalidFieldRequest(); 10581d4d54ddSJason M. Bills } 10591d4d54ddSJason M. Bills 10601d4d54ddSJason M. Bills // Per the IPMI spec, need to cancel any reservation when the SEL is 10611d4d54ddSJason M. Bills // cleared 1062c04e2e70SJason M. Bills cancelSELReservation(); 1063c04e2e70SJason M. Bills 10647944c307SJason M. Bills // Save the erase time 10657944c307SJason M. Bills intel_oem::ipmi::sel::erase_time::save(); 10667944c307SJason M. Bills 10671d4d54ddSJason M. Bills // Clear the SEL by deleting the log files 10681d4d54ddSJason M. Bills std::vector<std::filesystem::path> selLogFiles; 10691d4d54ddSJason M. Bills if (getSELLogFiles(selLogFiles)) 1070c04e2e70SJason M. Bills { 10711d4d54ddSJason M. Bills for (const std::filesystem::path& file : selLogFiles) 10721d4d54ddSJason M. Bills { 10731d4d54ddSJason M. Bills std::error_code ec; 10741d4d54ddSJason M. Bills std::filesystem::remove(file, ec); 1075c04e2e70SJason M. Bills } 1076c04e2e70SJason M. Bills } 1077c04e2e70SJason M. Bills 10781d4d54ddSJason M. Bills // Reload rsyslog so it knows to start new log files 107915419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 108015419dd5SVernon Mauery sdbusplus::message::message rsyslogReload = dbus->new_method_call( 10811d4d54ddSJason M. Bills "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 10821d4d54ddSJason M. Bills "org.freedesktop.systemd1.Manager", "ReloadUnit"); 10831d4d54ddSJason M. Bills rsyslogReload.append("rsyslog.service", "replace"); 10841d4d54ddSJason M. Bills try 10851d4d54ddSJason M. Bills { 108615419dd5SVernon Mauery sdbusplus::message::message reloadResponse = dbus->call(rsyslogReload); 10871d4d54ddSJason M. Bills } 10881d4d54ddSJason M. Bills catch (sdbusplus::exception_t& e) 10891d4d54ddSJason M. Bills { 10901d4d54ddSJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 1091c04e2e70SJason M. Bills } 1092c04e2e70SJason M. Bills 10931d4d54ddSJason M. Bills return ipmi::responseSuccess(ipmi::sel::eraseComplete); 10941d4d54ddSJason M. Bills } 10951d4d54ddSJason M. Bills 10961a47462eSJason M. Bills ipmi::RspType<uint32_t> ipmiStorageGetSELTime() 10971a47462eSJason M. Bills { 10981a47462eSJason M. Bills struct timespec selTime = {}; 10991a47462eSJason M. Bills 11001a47462eSJason M. Bills if (clock_gettime(CLOCK_REALTIME, &selTime) < 0) 11011a47462eSJason M. Bills { 11021a47462eSJason M. Bills return ipmi::responseUnspecifiedError(); 11031a47462eSJason M. Bills } 11041a47462eSJason M. Bills 11051a47462eSJason M. Bills return ipmi::responseSuccess(selTime.tv_sec); 11061a47462eSJason M. Bills } 11071a47462eSJason M. Bills 11081d4d54ddSJason M. Bills ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime) 1109cac97a53SJason M. Bills { 1110cac97a53SJason M. Bills // Set SEL Time is not supported 11111d4d54ddSJason M. Bills return ipmi::responseInvalidCommand(); 1112cac97a53SJason M. Bills } 1113cac97a53SJason M. Bills 111474c50c64SJames Feist std::vector<uint8_t> getType12SDRs(uint16_t index, uint16_t recordId) 111574c50c64SJames Feist { 111674c50c64SJames Feist std::vector<uint8_t> resp; 111774c50c64SJames Feist if (index == 0) 111874c50c64SJames Feist { 111974c50c64SJames Feist Type12Record bmc = {}; 112074c50c64SJames Feist bmc.header.record_id_lsb = recordId; 112174c50c64SJames Feist bmc.header.record_id_msb = recordId >> 8; 112274c50c64SJames Feist bmc.header.sdr_version = ipmiSdrVersion; 112374c50c64SJames Feist bmc.header.record_type = 0x12; 112474c50c64SJames Feist bmc.header.record_length = 0x1b; 112574c50c64SJames Feist bmc.slaveAddress = 0x20; 112674c50c64SJames Feist bmc.channelNumber = 0; 112774c50c64SJames Feist bmc.powerStateNotification = 0; 112874c50c64SJames Feist bmc.deviceCapabilities = 0xBF; 112974c50c64SJames Feist bmc.reserved = 0; 113074c50c64SJames Feist bmc.entityID = 0x2E; 113174c50c64SJames Feist bmc.entityInstance = 1; 113274c50c64SJames Feist bmc.oem = 0; 113374c50c64SJames Feist bmc.typeLengthCode = 0xD0; 113474c50c64SJames Feist std::string bmcName = "Basbrd Mgmt Ctlr"; 113574c50c64SJames Feist std::copy(bmcName.begin(), bmcName.end(), bmc.name); 113674c50c64SJames Feist uint8_t* bmcPtr = reinterpret_cast<uint8_t*>(&bmc); 113774c50c64SJames Feist resp.insert(resp.end(), bmcPtr, bmcPtr + sizeof(Type12Record)); 113874c50c64SJames Feist } 113974c50c64SJames Feist else if (index == 1) 114074c50c64SJames Feist { 114174c50c64SJames Feist Type12Record me = {}; 114274c50c64SJames Feist me.header.record_id_lsb = recordId; 114374c50c64SJames Feist me.header.record_id_msb = recordId >> 8; 114474c50c64SJames Feist me.header.sdr_version = ipmiSdrVersion; 114574c50c64SJames Feist me.header.record_type = 0x12; 114674c50c64SJames Feist me.header.record_length = 0x16; 114774c50c64SJames Feist me.slaveAddress = 0x2C; 114874c50c64SJames Feist me.channelNumber = 6; 114974c50c64SJames Feist me.powerStateNotification = 0x24; 115074c50c64SJames Feist me.deviceCapabilities = 0x21; 115174c50c64SJames Feist me.reserved = 0; 115274c50c64SJames Feist me.entityID = 0x2E; 115374c50c64SJames Feist me.entityInstance = 2; 115474c50c64SJames Feist me.oem = 0; 115574c50c64SJames Feist me.typeLengthCode = 0xCB; 115674c50c64SJames Feist std::string meName = "Mgmt Engine"; 115774c50c64SJames Feist std::copy(meName.begin(), meName.end(), me.name); 115874c50c64SJames Feist uint8_t* mePtr = reinterpret_cast<uint8_t*>(&me); 115974c50c64SJames Feist resp.insert(resp.end(), mePtr, mePtr + sizeof(Type12Record)); 116074c50c64SJames Feist } 116174c50c64SJames Feist else 116274c50c64SJames Feist { 116374c50c64SJames Feist throw std::runtime_error("getType12SDRs:: Illegal index " + 116474c50c64SJames Feist std::to_string(index)); 116574c50c64SJames Feist } 116674c50c64SJames Feist 116774c50c64SJames Feist return resp; 116874c50c64SJames Feist } 116974c50c64SJames Feist 1170e2d1aee3SJason M. Bills void registerStorageFunctions() 1171e2d1aee3SJason M. Bills { 1172e2d1aee3SJason M. Bills // <Get FRU Inventory Area Info> 1173d33acd6bSjayaprakash Mutyala ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage, 1174d33acd6bSjayaprakash Mutyala ipmi::storage::cmdGetFruInventoryAreaInfo, 1175d33acd6bSjayaprakash Mutyala ipmi::Privilege::User, ipmiStorageGetFruInvAreaInfo); 1176c04e2e70SJason M. Bills // <READ FRU Data> 11775f4194eeSjayaprakash Mutyala ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 11785f4194eeSjayaprakash Mutyala ipmi::storage::cmdReadFruData, ipmi::Privilege::User, 11795f4194eeSjayaprakash Mutyala ipmiStorageReadFruData); 1180e2d1aee3SJason M. Bills 1181c04e2e70SJason M. Bills // <WRITE FRU Data> 11825f4194eeSjayaprakash Mutyala ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 11835f4194eeSjayaprakash Mutyala ipmi::storage::cmdWriteFruData, 11845f4194eeSjayaprakash Mutyala ipmi::Privilege::Operator, ipmiStorageWriteFruData); 1185c04e2e70SJason M. Bills 1186c04e2e70SJason M. Bills // <Get SEL Info> 11871d4d54ddSJason M. Bills ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1188542498e9SJason M. Bills ipmi::storage::cmdGetSelInfo, ipmi::Privilege::User, 1189542498e9SJason M. Bills ipmiStorageGetSELInfo); 1190c04e2e70SJason M. Bills 1191c04e2e70SJason M. Bills // <Get SEL Entry> 11921d4d54ddSJason M. Bills ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1193542498e9SJason M. Bills ipmi::storage::cmdGetSelEntry, ipmi::Privilege::User, 1194542498e9SJason M. Bills ipmiStorageGetSELEntry); 1195c04e2e70SJason M. Bills 1196c04e2e70SJason M. Bills // <Add SEL Entry> 11976dd8f047SJason M. Bills ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 119898bbf69aSVernon Mauery ipmi::storage::cmdAddSelEntry, 11996dd8f047SJason M. Bills ipmi::Privilege::Operator, ipmiStorageAddSELEntry); 1200c04e2e70SJason M. Bills 1201c04e2e70SJason M. Bills // <Clear SEL> 12021d4d54ddSJason M. Bills ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 12031d4d54ddSJason M. Bills ipmi::storage::cmdClearSel, ipmi::Privilege::Operator, 12041d4d54ddSJason M. Bills ipmiStorageClearSEL); 1205cac97a53SJason M. Bills 12061a47462eSJason M. Bills // <Get SEL Time> 12071a47462eSJason M. Bills ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 1208542498e9SJason M. Bills ipmi::storage::cmdGetSelTime, ipmi::Privilege::User, 1209542498e9SJason M. Bills ipmiStorageGetSELTime); 12101a47462eSJason M. Bills 1211cac97a53SJason M. Bills // <Set SEL Time> 12121d4d54ddSJason M. Bills ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage, 12131d4d54ddSJason M. Bills ipmi::storage::cmdSetSelTime, 12141d4d54ddSJason M. Bills ipmi::Privilege::Operator, ipmiStorageSetSELTime); 1215e2d1aee3SJason M. Bills } 12163f7c5e40SJason M. Bills } // namespace storage 12173f7c5e40SJason M. Bills } // namespace ipmi 1218