13f7c5e40SJason M. Bills /* 23f7c5e40SJason M. Bills // Copyright (c) 2017 2018 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 176d9c83fdSJason M. Bills #include <ipmid/api.h> 183f7c5e40SJason M. Bills 193f7c5e40SJason M. Bills #include <boost/container/flat_map.hpp> 20c04e2e70SJason M. Bills #include <boost/process.hpp> 213f7c5e40SJason M. Bills #include <commandutils.hpp> 223f7c5e40SJason M. Bills #include <iostream> 23c04e2e70SJason M. Bills #include <phosphor-ipmi-host/selutility.hpp> 243f7c5e40SJason M. Bills #include <phosphor-logging/log.hpp> 253f7c5e40SJason M. Bills #include <sdbusplus/message/types.hpp> 263f7c5e40SJason M. Bills #include <sdbusplus/timer.hpp> 27c04e2e70SJason M. Bills #include <sdrutils.hpp> 28c04e2e70SJason M. Bills #include <stdexcept> 293f7c5e40SJason M. Bills #include <storagecommands.hpp> 30c04e2e70SJason M. Bills #include <string_view> 313f7c5e40SJason M. Bills 32*7944c307SJason M. Bills namespace intel_oem::ipmi::sel::erase_time 33*7944c307SJason M. Bills { 34*7944c307SJason M. Bills static constexpr const char* selEraseTimestamp = "/var/lib/ipmi/sel_erase_time"; 35*7944c307SJason M. Bills 36*7944c307SJason M. Bills void save() 37*7944c307SJason M. Bills { 38*7944c307SJason M. Bills // open the file, creating it if necessary 39*7944c307SJason M. Bills int fd = open(selEraseTimestamp, O_WRONLY | O_CREAT | O_CLOEXEC, 0644); 40*7944c307SJason M. Bills if (fd < 0) 41*7944c307SJason M. Bills { 42*7944c307SJason M. Bills std::cerr << "Failed to open file\n"; 43*7944c307SJason M. Bills return; 44*7944c307SJason M. Bills } 45*7944c307SJason M. Bills 46*7944c307SJason M. Bills // update the file timestamp to the current time 47*7944c307SJason M. Bills if (futimens(fd, NULL) < 0) 48*7944c307SJason M. Bills { 49*7944c307SJason M. Bills std::cerr << "Failed to update timestamp: " 50*7944c307SJason M. Bills << std::string(strerror(errno)); 51*7944c307SJason M. Bills } 52*7944c307SJason M. Bills close(fd); 53*7944c307SJason M. Bills } 54*7944c307SJason M. Bills 55*7944c307SJason M. Bills int get() 56*7944c307SJason M. Bills { 57*7944c307SJason M. Bills struct stat st; 58*7944c307SJason M. Bills // default to an invalid timestamp 59*7944c307SJason M. Bills int timestamp = ::ipmi::sel::invalidTimeStamp; 60*7944c307SJason M. Bills 61*7944c307SJason M. Bills int fd = open(selEraseTimestamp, O_RDWR | O_CLOEXEC, 0644); 62*7944c307SJason M. Bills if (fd < 0) 63*7944c307SJason M. Bills { 64*7944c307SJason M. Bills return timestamp; 65*7944c307SJason M. Bills } 66*7944c307SJason M. Bills 67*7944c307SJason M. Bills if (fstat(fd, &st) >= 0) 68*7944c307SJason M. Bills { 69*7944c307SJason M. Bills timestamp = st.st_mtime; 70*7944c307SJason M. Bills } 71*7944c307SJason M. Bills 72*7944c307SJason M. Bills return timestamp; 73*7944c307SJason M. Bills } 74*7944c307SJason M. Bills } // namespace intel_oem::ipmi::sel::erase_time 75*7944c307SJason M. Bills 763f7c5e40SJason M. Bills namespace ipmi 773f7c5e40SJason M. Bills { 783f7c5e40SJason M. Bills 793f7c5e40SJason M. Bills namespace storage 803f7c5e40SJason M. Bills { 813f7c5e40SJason M. Bills 82e2d1aee3SJason M. Bills constexpr static const size_t maxMessageSize = 64; 833f7c5e40SJason M. Bills constexpr static const size_t maxFruSdrNameSize = 16; 843f7c5e40SJason M. Bills using ManagedObjectType = boost::container::flat_map< 853f7c5e40SJason M. Bills sdbusplus::message::object_path, 863f7c5e40SJason M. Bills boost::container::flat_map< 873f7c5e40SJason M. Bills std::string, boost::container::flat_map<std::string, DbusVariant>>>; 883f7c5e40SJason M. Bills using ManagedEntry = std::pair< 893f7c5e40SJason M. Bills sdbusplus::message::object_path, 903f7c5e40SJason M. Bills boost::container::flat_map< 913f7c5e40SJason M. Bills std::string, boost::container::flat_map<std::string, DbusVariant>>>; 923f7c5e40SJason M. Bills 933bcba457SJames Feist constexpr static const char* fruDeviceServiceName = 943bcba457SJames Feist "xyz.openbmc_project.FruDevice"; 95e2d1aee3SJason M. Bills constexpr static const size_t cacheTimeoutSeconds = 10; 963f7c5e40SJason M. Bills 97c04e2e70SJason M. Bills constexpr static const uint8_t deassertionEvent = 1; 98c04e2e70SJason M. Bills 993f7c5e40SJason M. Bills static std::vector<uint8_t> fruCache; 1003f7c5e40SJason M. Bills static uint8_t cacheBus = 0xFF; 1013f7c5e40SJason M. Bills static uint8_t cacheAddr = 0XFF; 1023f7c5e40SJason M. Bills 1033f7c5e40SJason M. Bills std::unique_ptr<phosphor::Timer> cacheTimer = nullptr; 1043f7c5e40SJason M. Bills 1053f7c5e40SJason M. Bills // we unfortunately have to build a map of hashes in case there is a 1063f7c5e40SJason M. Bills // collision to verify our dev-id 1073f7c5e40SJason M. Bills boost::container::flat_map<uint8_t, std::pair<uint8_t, uint8_t>> deviceHashes; 1083f7c5e40SJason M. Bills 109e2d1aee3SJason M. Bills void registerStorageFunctions() __attribute__((constructor)); 1103f7c5e40SJason M. Bills static sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); 1113f7c5e40SJason M. Bills 1123f7c5e40SJason M. Bills bool writeFru() 1133f7c5e40SJason M. Bills { 1143f7c5e40SJason M. Bills sdbusplus::message::message writeFru = dbus.new_method_call( 1153f7c5e40SJason M. Bills fruDeviceServiceName, "/xyz/openbmc_project/FruDevice", 1163f7c5e40SJason M. Bills "xyz.openbmc_project.FruDeviceManager", "WriteFru"); 1173f7c5e40SJason M. Bills writeFru.append(cacheBus, cacheAddr, fruCache); 1183f7c5e40SJason M. Bills try 1193f7c5e40SJason M. Bills { 1203f7c5e40SJason M. Bills sdbusplus::message::message writeFruResp = dbus.call(writeFru); 1213f7c5e40SJason M. Bills } 1223f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 1233f7c5e40SJason M. Bills { 1243f7c5e40SJason M. Bills // todo: log sel? 1253f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 1263f7c5e40SJason M. Bills "error writing fru"); 1273f7c5e40SJason M. Bills return false; 1283f7c5e40SJason M. Bills } 1293f7c5e40SJason M. Bills return true; 1303f7c5e40SJason M. Bills } 1313f7c5e40SJason M. Bills 132e2d1aee3SJason M. Bills void createTimer() 133e2d1aee3SJason M. Bills { 134e2d1aee3SJason M. Bills if (cacheTimer == nullptr) 135e2d1aee3SJason M. Bills { 136e2d1aee3SJason M. Bills cacheTimer = std::make_unique<phosphor::Timer>(writeFru); 137e2d1aee3SJason M. Bills } 138e2d1aee3SJason M. Bills } 139e2d1aee3SJason M. Bills 1403f7c5e40SJason M. Bills ipmi_ret_t replaceCacheFru(uint8_t devId) 1413f7c5e40SJason M. Bills { 1423f7c5e40SJason M. Bills static uint8_t lastDevId = 0xFF; 1433f7c5e40SJason M. Bills 1443f7c5e40SJason M. Bills bool timerRunning = (cacheTimer != nullptr) && !cacheTimer->isExpired(); 1453f7c5e40SJason M. Bills if (lastDevId == devId && timerRunning) 1463f7c5e40SJason M. Bills { 1473f7c5e40SJason M. Bills return IPMI_CC_OK; // cache already up to date 1483f7c5e40SJason M. Bills } 1493f7c5e40SJason M. Bills // if timer is running, stop it and writeFru manually 1503f7c5e40SJason M. Bills else if (timerRunning) 1513f7c5e40SJason M. Bills { 1523f7c5e40SJason M. Bills cacheTimer->stop(); 1533f7c5e40SJason M. Bills writeFru(); 1543f7c5e40SJason M. Bills } 1553f7c5e40SJason M. Bills 1563f7c5e40SJason M. Bills sdbusplus::message::message getObjects = dbus.new_method_call( 1573f7c5e40SJason M. Bills fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager", 1583f7c5e40SJason M. Bills "GetManagedObjects"); 1593f7c5e40SJason M. Bills ManagedObjectType frus; 1603f7c5e40SJason M. Bills try 1613f7c5e40SJason M. Bills { 1623f7c5e40SJason M. Bills sdbusplus::message::message resp = dbus.call(getObjects); 1633f7c5e40SJason M. Bills resp.read(frus); 1643f7c5e40SJason M. Bills } 1653f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 1663f7c5e40SJason M. Bills { 1673f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 1683f7c5e40SJason M. Bills "replaceCacheFru: error getting managed objects"); 1693f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 1703f7c5e40SJason M. Bills } 1713f7c5e40SJason M. Bills 1723f7c5e40SJason M. Bills deviceHashes.clear(); 1733f7c5e40SJason M. Bills 1743f7c5e40SJason M. Bills // hash the object paths to create unique device id's. increment on 1753f7c5e40SJason M. Bills // collision 1763f7c5e40SJason M. Bills std::hash<std::string> hasher; 1773f7c5e40SJason M. Bills for (const auto& fru : frus) 1783f7c5e40SJason M. Bills { 1793f7c5e40SJason M. Bills auto fruIface = fru.second.find("xyz.openbmc_project.FruDevice"); 1803f7c5e40SJason M. Bills if (fruIface == fru.second.end()) 1813f7c5e40SJason M. Bills { 1823f7c5e40SJason M. Bills continue; 1833f7c5e40SJason M. Bills } 1843f7c5e40SJason M. Bills 1853f7c5e40SJason M. Bills auto busFind = fruIface->second.find("BUS"); 1863f7c5e40SJason M. Bills auto addrFind = fruIface->second.find("ADDRESS"); 1873f7c5e40SJason M. Bills if (busFind == fruIface->second.end() || 1883f7c5e40SJason M. Bills addrFind == fruIface->second.end()) 1893f7c5e40SJason M. Bills { 1903f7c5e40SJason M. Bills phosphor::logging::log<phosphor::logging::level::INFO>( 1913f7c5e40SJason M. Bills "fru device missing Bus or Address", 1923f7c5e40SJason M. Bills phosphor::logging::entry("FRU=%s", fru.first.str.c_str())); 1933f7c5e40SJason M. Bills continue; 1943f7c5e40SJason M. Bills } 1953f7c5e40SJason M. Bills 1963f7c5e40SJason M. Bills uint8_t fruBus = 1973f7c5e40SJason M. Bills sdbusplus::message::variant_ns::get<uint32_t>(busFind->second); 1983f7c5e40SJason M. Bills uint8_t fruAddr = 1993f7c5e40SJason M. Bills sdbusplus::message::variant_ns::get<uint32_t>(addrFind->second); 2003f7c5e40SJason M. Bills 2013f7c5e40SJason M. Bills uint8_t fruHash = 0; 2023f7c5e40SJason M. Bills if (fruBus != 0 || fruAddr != 0) 2033f7c5e40SJason M. Bills { 2043f7c5e40SJason M. Bills fruHash = hasher(fru.first.str); 2053f7c5e40SJason M. Bills // can't be 0xFF based on spec, and 0 is reserved for baseboard 2063f7c5e40SJason M. Bills if (fruHash == 0 || fruHash == 0xFF) 2073f7c5e40SJason M. Bills { 2083f7c5e40SJason M. Bills fruHash = 1; 2093f7c5e40SJason M. Bills } 2103f7c5e40SJason M. Bills } 2113f7c5e40SJason M. Bills std::pair<uint8_t, uint8_t> newDev(fruBus, fruAddr); 2123f7c5e40SJason M. Bills 2133f7c5e40SJason M. Bills bool emplacePassed = false; 2143f7c5e40SJason M. Bills while (!emplacePassed) 2153f7c5e40SJason M. Bills { 2163f7c5e40SJason M. Bills auto resp = deviceHashes.emplace(fruHash, newDev); 2173f7c5e40SJason M. Bills emplacePassed = resp.second; 2183f7c5e40SJason M. Bills if (!emplacePassed) 2193f7c5e40SJason M. Bills { 2203f7c5e40SJason M. Bills fruHash++; 2213f7c5e40SJason M. Bills // can't be 0xFF based on spec, and 0 is reserved for 2223f7c5e40SJason M. Bills // baseboard 2233f7c5e40SJason M. Bills if (fruHash == 0XFF) 2243f7c5e40SJason M. Bills { 2253f7c5e40SJason M. Bills fruHash = 0x1; 2263f7c5e40SJason M. Bills } 2273f7c5e40SJason M. Bills } 2283f7c5e40SJason M. Bills } 2293f7c5e40SJason M. Bills } 2303f7c5e40SJason M. Bills auto deviceFind = deviceHashes.find(devId); 2313f7c5e40SJason M. Bills if (deviceFind == deviceHashes.end()) 2323f7c5e40SJason M. Bills { 2333f7c5e40SJason M. Bills return IPMI_CC_SENSOR_INVALID; 2343f7c5e40SJason M. Bills } 2353f7c5e40SJason M. Bills 2363f7c5e40SJason M. Bills fruCache.clear(); 2373f7c5e40SJason M. Bills sdbusplus::message::message getRawFru = dbus.new_method_call( 2383f7c5e40SJason M. Bills fruDeviceServiceName, "/xyz/openbmc_project/FruDevice", 2393f7c5e40SJason M. Bills "xyz.openbmc_project.FruDeviceManager", "GetRawFru"); 2403f7c5e40SJason M. Bills cacheBus = deviceFind->second.first; 2413f7c5e40SJason M. Bills cacheAddr = deviceFind->second.second; 2423f7c5e40SJason M. Bills getRawFru.append(cacheBus, cacheAddr); 2433f7c5e40SJason M. Bills try 2443f7c5e40SJason M. Bills { 2453f7c5e40SJason M. Bills sdbusplus::message::message getRawResp = dbus.call(getRawFru); 2463f7c5e40SJason M. Bills getRawResp.read(fruCache); 2473f7c5e40SJason M. Bills } 2483f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 2493f7c5e40SJason M. Bills { 2503f7c5e40SJason M. Bills lastDevId = 0xFF; 2513f7c5e40SJason M. Bills cacheBus = 0xFF; 2523f7c5e40SJason M. Bills cacheAddr = 0xFF; 2533f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 2543f7c5e40SJason M. Bills } 2553f7c5e40SJason M. Bills 2563f7c5e40SJason M. Bills lastDevId = devId; 2573f7c5e40SJason M. Bills return IPMI_CC_OK; 2583f7c5e40SJason M. Bills } 2593f7c5e40SJason M. Bills 260e2d1aee3SJason M. Bills ipmi_ret_t ipmiStorageReadFRUData(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 261e2d1aee3SJason M. Bills ipmi_request_t request, 262e2d1aee3SJason M. Bills ipmi_response_t response, 263e2d1aee3SJason M. Bills ipmi_data_len_t dataLen, 264e2d1aee3SJason M. Bills ipmi_context_t context) 265e2d1aee3SJason M. Bills { 266e2d1aee3SJason M. Bills if (*dataLen != 4) 267e2d1aee3SJason M. Bills { 268e2d1aee3SJason M. Bills *dataLen = 0; 269e2d1aee3SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 270e2d1aee3SJason M. Bills } 271e2d1aee3SJason M. Bills *dataLen = 0; // default to 0 in case of an error 272e2d1aee3SJason M. Bills 273e2d1aee3SJason M. Bills auto req = static_cast<GetFRUAreaReq*>(request); 274e2d1aee3SJason M. Bills 275e2d1aee3SJason M. Bills if (req->countToRead > maxMessageSize - 1) 276e2d1aee3SJason M. Bills { 277e2d1aee3SJason M. Bills return IPMI_CC_INVALID_FIELD_REQUEST; 278e2d1aee3SJason M. Bills } 279e2d1aee3SJason M. Bills ipmi_ret_t status = replaceCacheFru(req->fruDeviceID); 280e2d1aee3SJason M. Bills 281e2d1aee3SJason M. Bills if (status != IPMI_CC_OK) 282e2d1aee3SJason M. Bills { 283e2d1aee3SJason M. Bills return status; 284e2d1aee3SJason M. Bills } 285e2d1aee3SJason M. Bills 286e2d1aee3SJason M. Bills size_t fromFRUByteLen = 0; 287e2d1aee3SJason M. Bills if (req->countToRead + req->fruInventoryOffset < fruCache.size()) 288e2d1aee3SJason M. Bills { 289e2d1aee3SJason M. Bills fromFRUByteLen = req->countToRead; 290e2d1aee3SJason M. Bills } 291e2d1aee3SJason M. Bills else if (fruCache.size() > req->fruInventoryOffset) 292e2d1aee3SJason M. Bills { 293e2d1aee3SJason M. Bills fromFRUByteLen = fruCache.size() - req->fruInventoryOffset; 294e2d1aee3SJason M. Bills } 295e2d1aee3SJason M. Bills size_t padByteLen = req->countToRead - fromFRUByteLen; 296e2d1aee3SJason M. Bills uint8_t* respPtr = static_cast<uint8_t*>(response); 297e2d1aee3SJason M. Bills *respPtr = req->countToRead; 298e2d1aee3SJason M. Bills std::copy(fruCache.begin() + req->fruInventoryOffset, 299e2d1aee3SJason M. Bills fruCache.begin() + req->fruInventoryOffset + fromFRUByteLen, 300e2d1aee3SJason M. Bills ++respPtr); 301e2d1aee3SJason M. Bills // if longer than the fru is requested, fill with 0xFF 302e2d1aee3SJason M. Bills if (padByteLen) 303e2d1aee3SJason M. Bills { 304e2d1aee3SJason M. Bills respPtr += fromFRUByteLen; 305e2d1aee3SJason M. Bills std::fill(respPtr, respPtr + padByteLen, 0xFF); 306e2d1aee3SJason M. Bills } 307e2d1aee3SJason M. Bills *dataLen = fromFRUByteLen + 1; 308e2d1aee3SJason M. Bills 309e2d1aee3SJason M. Bills return IPMI_CC_OK; 310e2d1aee3SJason M. Bills } 311e2d1aee3SJason M. Bills 312e2d1aee3SJason M. Bills ipmi_ret_t ipmiStorageWriteFRUData(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 313e2d1aee3SJason M. Bills ipmi_request_t request, 314e2d1aee3SJason M. Bills ipmi_response_t response, 315e2d1aee3SJason M. Bills ipmi_data_len_t dataLen, 316e2d1aee3SJason M. Bills ipmi_context_t context) 317e2d1aee3SJason M. Bills { 318e2d1aee3SJason M. Bills if (*dataLen < 4 || 319e2d1aee3SJason M. Bills *dataLen >= 320e2d1aee3SJason M. Bills 0xFF + 3) // count written return is one byte, so limit to one byte 321e2d1aee3SJason M. Bills // of data after the three request data bytes 322e2d1aee3SJason M. Bills { 323e2d1aee3SJason M. Bills *dataLen = 0; 324e2d1aee3SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 325e2d1aee3SJason M. Bills } 326e2d1aee3SJason M. Bills 327e2d1aee3SJason M. Bills auto req = static_cast<WriteFRUDataReq*>(request); 328e2d1aee3SJason M. Bills size_t writeLen = *dataLen - 3; 329e2d1aee3SJason M. Bills *dataLen = 0; // default to 0 in case of an error 330e2d1aee3SJason M. Bills 331e2d1aee3SJason M. Bills ipmi_ret_t status = replaceCacheFru(req->fruDeviceID); 332e2d1aee3SJason M. Bills if (status != IPMI_CC_OK) 333e2d1aee3SJason M. Bills { 334e2d1aee3SJason M. Bills return status; 335e2d1aee3SJason M. Bills } 336e2d1aee3SJason M. Bills int lastWriteAddr = req->fruInventoryOffset + writeLen; 337e2d1aee3SJason M. Bills if (fruCache.size() < lastWriteAddr) 338e2d1aee3SJason M. Bills { 339e2d1aee3SJason M. Bills fruCache.resize(req->fruInventoryOffset + writeLen); 340e2d1aee3SJason M. Bills } 341e2d1aee3SJason M. Bills 342e2d1aee3SJason M. Bills std::copy(req->data, req->data + writeLen, 343e2d1aee3SJason M. Bills fruCache.begin() + req->fruInventoryOffset); 344e2d1aee3SJason M. Bills 345e2d1aee3SJason M. Bills bool atEnd = false; 346e2d1aee3SJason M. Bills 347e2d1aee3SJason M. Bills if (fruCache.size() >= sizeof(FRUHeader)) 348e2d1aee3SJason M. Bills { 349e2d1aee3SJason M. Bills 350e2d1aee3SJason M. Bills FRUHeader* header = reinterpret_cast<FRUHeader*>(fruCache.data()); 351e2d1aee3SJason M. Bills 352e2d1aee3SJason M. Bills int lastRecordStart = std::max( 353e2d1aee3SJason M. Bills header->internalOffset, 354e2d1aee3SJason M. Bills std::max(header->chassisOffset, 355e2d1aee3SJason M. Bills std::max(header->boardOffset, header->productOffset))); 356e2d1aee3SJason M. Bills // TODO: Handle Multi-Record FRUs? 357e2d1aee3SJason M. Bills 358e2d1aee3SJason M. Bills lastRecordStart *= 8; // header starts in are multiples of 8 bytes 359e2d1aee3SJason M. Bills 360e2d1aee3SJason M. Bills // get the length of the area in multiples of 8 bytes 361e2d1aee3SJason M. Bills if (lastWriteAddr > (lastRecordStart + 1)) 362e2d1aee3SJason M. Bills { 363e2d1aee3SJason M. Bills // second byte in record area is the length 364e2d1aee3SJason M. Bills int areaLength(fruCache[lastRecordStart + 1]); 365e2d1aee3SJason M. Bills areaLength *= 8; // it is in multiples of 8 bytes 366e2d1aee3SJason M. Bills 367e2d1aee3SJason M. Bills if (lastWriteAddr >= (areaLength + lastRecordStart)) 368e2d1aee3SJason M. Bills { 369e2d1aee3SJason M. Bills atEnd = true; 370e2d1aee3SJason M. Bills } 371e2d1aee3SJason M. Bills } 372e2d1aee3SJason M. Bills } 373e2d1aee3SJason M. Bills uint8_t* respPtr = static_cast<uint8_t*>(response); 374e2d1aee3SJason M. Bills if (atEnd) 375e2d1aee3SJason M. Bills { 376e2d1aee3SJason M. Bills // cancel timer, we're at the end so might as well send it 377e2d1aee3SJason M. Bills cacheTimer->stop(); 378e2d1aee3SJason M. Bills if (!writeFru()) 379e2d1aee3SJason M. Bills { 380e2d1aee3SJason M. Bills return IPMI_CC_INVALID_FIELD_REQUEST; 381e2d1aee3SJason M. Bills } 382e2d1aee3SJason M. Bills *respPtr = std::min(fruCache.size(), static_cast<size_t>(0xFF)); 383e2d1aee3SJason M. Bills } 384e2d1aee3SJason M. Bills else 385e2d1aee3SJason M. Bills { 386e2d1aee3SJason M. Bills // start a timer, if no further data is sent in cacheTimeoutSeconds 387e2d1aee3SJason M. Bills // seconds, check to see if it is valid 388e2d1aee3SJason M. Bills createTimer(); 389e2d1aee3SJason M. Bills cacheTimer->start(std::chrono::duration_cast<std::chrono::microseconds>( 390e2d1aee3SJason M. Bills std::chrono::seconds(cacheTimeoutSeconds))); 391e2d1aee3SJason M. Bills *respPtr = 0; 392e2d1aee3SJason M. Bills } 393e2d1aee3SJason M. Bills 394e2d1aee3SJason M. Bills *dataLen = 1; 395e2d1aee3SJason M. Bills 396e2d1aee3SJason M. Bills return IPMI_CC_OK; 397e2d1aee3SJason M. Bills } 398e2d1aee3SJason M. Bills 399e2d1aee3SJason M. Bills ipmi_ret_t ipmiStorageGetFRUInvAreaInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 400e2d1aee3SJason M. Bills ipmi_request_t request, 401e2d1aee3SJason M. Bills ipmi_response_t response, 402e2d1aee3SJason M. Bills ipmi_data_len_t dataLen, 403e2d1aee3SJason M. Bills ipmi_context_t context) 404e2d1aee3SJason M. Bills { 405e2d1aee3SJason M. Bills if (*dataLen != 1) 406e2d1aee3SJason M. Bills { 407e2d1aee3SJason M. Bills *dataLen = 0; 408e2d1aee3SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 409e2d1aee3SJason M. Bills } 410e2d1aee3SJason M. Bills *dataLen = 0; // default to 0 in case of an error 411e2d1aee3SJason M. Bills 412e2d1aee3SJason M. Bills uint8_t reqDev = *(static_cast<uint8_t*>(request)); 413e2d1aee3SJason M. Bills if (reqDev == 0xFF) 414e2d1aee3SJason M. Bills { 415e2d1aee3SJason M. Bills return IPMI_CC_INVALID_FIELD_REQUEST; 416e2d1aee3SJason M. Bills } 417e2d1aee3SJason M. Bills ipmi_ret_t status = replaceCacheFru(reqDev); 418e2d1aee3SJason M. Bills 419e2d1aee3SJason M. Bills if (status != IPMI_CC_OK) 420e2d1aee3SJason M. Bills { 421e2d1aee3SJason M. Bills return status; 422e2d1aee3SJason M. Bills } 423e2d1aee3SJason M. Bills 424e2d1aee3SJason M. Bills GetFRUAreaResp* respPtr = static_cast<GetFRUAreaResp*>(response); 425e2d1aee3SJason M. Bills respPtr->inventorySizeLSB = fruCache.size() & 0xFF; 426e2d1aee3SJason M. Bills respPtr->inventorySizeMSB = fruCache.size() >> 8; 427e2d1aee3SJason M. Bills respPtr->accessType = static_cast<uint8_t>(GetFRUAreaAccessType::byte); 428e2d1aee3SJason M. Bills 429e2d1aee3SJason M. Bills *dataLen = sizeof(GetFRUAreaResp); 430e2d1aee3SJason M. Bills return IPMI_CC_OK; 431e2d1aee3SJason M. Bills } 432e2d1aee3SJason M. Bills 4333f7c5e40SJason M. Bills ipmi_ret_t getFruSdrCount(size_t& count) 4343f7c5e40SJason M. Bills { 4353f7c5e40SJason M. Bills ipmi_ret_t ret = replaceCacheFru(0); 4363f7c5e40SJason M. Bills if (ret != IPMI_CC_OK) 4373f7c5e40SJason M. Bills { 4383f7c5e40SJason M. Bills return ret; 4393f7c5e40SJason M. Bills } 4403f7c5e40SJason M. Bills count = deviceHashes.size(); 4413f7c5e40SJason M. Bills return IPMI_CC_OK; 4423f7c5e40SJason M. Bills } 4433f7c5e40SJason M. Bills 4443f7c5e40SJason M. Bills ipmi_ret_t getFruSdrs(size_t index, get_sdr::SensorDataFruRecord& resp) 4453f7c5e40SJason M. Bills { 4463f7c5e40SJason M. Bills ipmi_ret_t ret = replaceCacheFru(0); // this will update the hash list 4473f7c5e40SJason M. Bills if (ret != IPMI_CC_OK) 4483f7c5e40SJason M. Bills { 4493f7c5e40SJason M. Bills return ret; 4503f7c5e40SJason M. Bills } 4513f7c5e40SJason M. Bills if (deviceHashes.size() < index) 4523f7c5e40SJason M. Bills { 4533f7c5e40SJason M. Bills return IPMI_CC_INVALID_FIELD_REQUEST; 4543f7c5e40SJason M. Bills } 4553f7c5e40SJason M. Bills auto device = deviceHashes.begin() + index; 4563f7c5e40SJason M. Bills uint8_t& bus = device->second.first; 4573f7c5e40SJason M. Bills uint8_t& address = device->second.second; 4583f7c5e40SJason M. Bills 4593f7c5e40SJason M. Bills ManagedObjectType frus; 4603f7c5e40SJason M. Bills 4613f7c5e40SJason M. Bills sdbusplus::message::message getObjects = dbus.new_method_call( 4623f7c5e40SJason M. Bills fruDeviceServiceName, "/", "org.freedesktop.DBus.ObjectManager", 4633f7c5e40SJason M. Bills "GetManagedObjects"); 4643f7c5e40SJason M. Bills try 4653f7c5e40SJason M. Bills { 4663f7c5e40SJason M. Bills sdbusplus::message::message resp = dbus.call(getObjects); 4673f7c5e40SJason M. Bills resp.read(frus); 4683f7c5e40SJason M. Bills } 4693f7c5e40SJason M. Bills catch (sdbusplus::exception_t&) 4703f7c5e40SJason M. Bills { 4713f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 4723f7c5e40SJason M. Bills } 4733f7c5e40SJason M. Bills boost::container::flat_map<std::string, DbusVariant>* fruData = nullptr; 4743f7c5e40SJason M. Bills auto fru = 4753f7c5e40SJason M. Bills std::find_if(frus.begin(), frus.end(), 4763f7c5e40SJason M. Bills [bus, address, &fruData](ManagedEntry& entry) { 4773f7c5e40SJason M. Bills auto findFruDevice = 4783f7c5e40SJason M. Bills entry.second.find("xyz.openbmc_project.FruDevice"); 4793f7c5e40SJason M. Bills if (findFruDevice == entry.second.end()) 4803f7c5e40SJason M. Bills { 4813f7c5e40SJason M. Bills return false; 4823f7c5e40SJason M. Bills } 4833f7c5e40SJason M. Bills fruData = &(findFruDevice->second); 4843f7c5e40SJason M. Bills auto findBus = findFruDevice->second.find("BUS"); 4853f7c5e40SJason M. Bills auto findAddress = 4863f7c5e40SJason M. Bills findFruDevice->second.find("ADDRESS"); 4873f7c5e40SJason M. Bills if (findBus == findFruDevice->second.end() || 4883f7c5e40SJason M. Bills findAddress == findFruDevice->second.end()) 4893f7c5e40SJason M. Bills { 4903f7c5e40SJason M. Bills return false; 4913f7c5e40SJason M. Bills } 4923f7c5e40SJason M. Bills if (sdbusplus::message::variant_ns::get<uint32_t>( 4933f7c5e40SJason M. Bills findBus->second) != bus) 4943f7c5e40SJason M. Bills { 4953f7c5e40SJason M. Bills return false; 4963f7c5e40SJason M. Bills } 4973f7c5e40SJason M. Bills if (sdbusplus::message::variant_ns::get<uint32_t>( 4983f7c5e40SJason M. Bills findAddress->second) != address) 4993f7c5e40SJason M. Bills { 5003f7c5e40SJason M. Bills return false; 5013f7c5e40SJason M. Bills } 5023f7c5e40SJason M. Bills return true; 5033f7c5e40SJason M. Bills }); 5043f7c5e40SJason M. Bills if (fru == frus.end()) 5053f7c5e40SJason M. Bills { 5063f7c5e40SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 5073f7c5e40SJason M. Bills } 5083f7c5e40SJason M. Bills std::string name; 5093f7c5e40SJason M. Bills auto findProductName = fruData->find("BOARD_PRODUCT_NAME"); 5103f7c5e40SJason M. Bills auto findBoardName = fruData->find("PRODUCT_PRODUCT_NAME"); 5113f7c5e40SJason M. Bills if (findProductName != fruData->end()) 5123f7c5e40SJason M. Bills { 5133f7c5e40SJason M. Bills name = sdbusplus::message::variant_ns::get<std::string>( 5143f7c5e40SJason M. Bills findProductName->second); 5153f7c5e40SJason M. Bills } 5163f7c5e40SJason M. Bills else if (findBoardName != fruData->end()) 5173f7c5e40SJason M. Bills { 5183f7c5e40SJason M. Bills name = sdbusplus::message::variant_ns::get<std::string>( 5193f7c5e40SJason M. Bills findBoardName->second); 5203f7c5e40SJason M. Bills } 5213f7c5e40SJason M. Bills else 5223f7c5e40SJason M. Bills { 5233f7c5e40SJason M. Bills name = "UNKNOWN"; 5243f7c5e40SJason M. Bills } 5253f7c5e40SJason M. Bills if (name.size() > maxFruSdrNameSize) 5263f7c5e40SJason M. Bills { 5273f7c5e40SJason M. Bills name = name.substr(0, maxFruSdrNameSize); 5283f7c5e40SJason M. Bills } 5293f7c5e40SJason M. Bills size_t sizeDiff = maxFruSdrNameSize - name.size(); 5303f7c5e40SJason M. Bills 5313f7c5e40SJason M. Bills resp.header.record_id_lsb = 0x0; // calling code is to implement these 5323f7c5e40SJason M. Bills resp.header.record_id_msb = 0x0; 5333f7c5e40SJason M. Bills resp.header.sdr_version = ipmiSdrVersion; 5343f7c5e40SJason M. Bills resp.header.record_type = 0x11; // FRU Device Locator 5353f7c5e40SJason M. Bills resp.header.record_length = sizeof(resp.body) + sizeof(resp.key) - sizeDiff; 5363f7c5e40SJason M. Bills resp.key.deviceAddress = 0x20; 5373f7c5e40SJason M. Bills resp.key.fruID = device->first; 5383f7c5e40SJason M. Bills resp.key.accessLun = 0x80; // logical / physical fru device 5393f7c5e40SJason M. Bills resp.key.channelNumber = 0x0; 5403f7c5e40SJason M. Bills resp.body.reserved = 0x0; 5413f7c5e40SJason M. Bills resp.body.deviceType = 0x10; 5423f7c5e40SJason M. Bills resp.body.entityID = 0x0; 5433f7c5e40SJason M. Bills resp.body.entityInstance = 0x1; 5443f7c5e40SJason M. Bills resp.body.oem = 0x0; 5453f7c5e40SJason M. Bills resp.body.deviceIDLen = name.size(); 5463f7c5e40SJason M. Bills name.copy(resp.body.deviceID, name.size()); 5473f7c5e40SJason M. Bills 5483f7c5e40SJason M. Bills return IPMI_CC_OK; 5493f7c5e40SJason M. Bills } 550e2d1aee3SJason M. Bills 551c04e2e70SJason M. Bills ipmi_ret_t ipmiStorageGetSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 552c04e2e70SJason M. Bills ipmi_request_t request, 553c04e2e70SJason M. Bills ipmi_response_t response, 554c04e2e70SJason M. Bills ipmi_data_len_t data_len, 555c04e2e70SJason M. Bills ipmi_context_t context) 556c04e2e70SJason M. Bills { 557c04e2e70SJason M. Bills if (*data_len != 0) 558c04e2e70SJason M. Bills { 559c04e2e70SJason M. Bills *data_len = 0; 560c04e2e70SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 561c04e2e70SJason M. Bills } 562c04e2e70SJason M. Bills ipmi::sel::GetSELInfoResponse* responseData = 563c04e2e70SJason M. Bills static_cast<ipmi::sel::GetSELInfoResponse*>(response); 564c04e2e70SJason M. Bills 565c04e2e70SJason M. Bills responseData->selVersion = ipmi::sel::selVersion; 566c04e2e70SJason M. Bills responseData->addTimeStamp = ipmi::sel::invalidTimeStamp; 567c04e2e70SJason M. Bills responseData->operationSupport = intel_oem::ipmi::sel::selOperationSupport; 568c04e2e70SJason M. Bills responseData->entries = 0; 569c04e2e70SJason M. Bills 570*7944c307SJason M. Bills // Fill in the last erase time 571*7944c307SJason M. Bills responseData->eraseTimeStamp = intel_oem::ipmi::sel::erase_time::get(); 572*7944c307SJason M. Bills 573c04e2e70SJason M. Bills // Open the journal 574c04e2e70SJason M. Bills sd_journal* journalTmp = nullptr; 575c04e2e70SJason M. Bills if (int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); ret < 0) 576c04e2e70SJason M. Bills { 577c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 578c04e2e70SJason M. Bills "Failed to open journal: ", 579c04e2e70SJason M. Bills phosphor::logging::entry("ERRNO=%s", strerror(-ret))); 580c04e2e70SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 581c04e2e70SJason M. Bills } 582c04e2e70SJason M. Bills std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 583c04e2e70SJason M. Bills journalTmp, sd_journal_close); 584c04e2e70SJason M. Bills journalTmp = nullptr; 585c04e2e70SJason M. Bills 586c04e2e70SJason M. Bills // Filter the journal based on the SEL MESSAGE_ID 587c04e2e70SJason M. Bills std::string match = 588c04e2e70SJason M. Bills "MESSAGE_ID=" + std::string(intel_oem::ipmi::sel::selMessageId); 589c04e2e70SJason M. Bills sd_journal_add_match(journal.get(), match.c_str(), 0); 590c04e2e70SJason M. Bills 591c04e2e70SJason M. Bills // Count the number of SEL Entries in the journal and get the timestamp of 592c04e2e70SJason M. Bills // the newest entry 593c04e2e70SJason M. Bills bool timestampRecorded = false; 594c04e2e70SJason M. Bills SD_JOURNAL_FOREACH_BACKWARDS(journal.get()) 595c04e2e70SJason M. Bills { 596c04e2e70SJason M. Bills if (!timestampRecorded) 597c04e2e70SJason M. Bills { 598c04e2e70SJason M. Bills uint64_t timestamp; 599c04e2e70SJason M. Bills if (int ret = 600c04e2e70SJason M. Bills sd_journal_get_realtime_usec(journal.get(), ×tamp); 601c04e2e70SJason M. Bills ret < 0) 602c04e2e70SJason M. Bills { 603c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 604c04e2e70SJason M. Bills "Failed to read timestamp: ", 605c04e2e70SJason M. Bills phosphor::logging::entry("ERRNO=%s", strerror(-ret))); 606c04e2e70SJason M. Bills return IPMI_CC_RESPONSE_ERROR; 607c04e2e70SJason M. Bills } 608c04e2e70SJason M. Bills timestamp /= (1000 * 1000); // convert from us to s 609c04e2e70SJason M. Bills responseData->addTimeStamp = static_cast<uint32_t>(timestamp); 610c04e2e70SJason M. Bills timestampRecorded = true; 611c04e2e70SJason M. Bills } 612c04e2e70SJason M. Bills responseData->entries++; 613c04e2e70SJason M. Bills } 614c04e2e70SJason M. Bills 615c04e2e70SJason M. Bills *data_len = sizeof(ipmi::sel::GetSELInfoResponse); 616c04e2e70SJason M. Bills return IPMI_CC_OK; 617c04e2e70SJason M. Bills } 618c04e2e70SJason M. Bills 619c04e2e70SJason M. Bills static int fromHexStr(const std::string hexStr, std::vector<uint8_t>& data) 620c04e2e70SJason M. Bills { 621c04e2e70SJason M. Bills for (unsigned int i = 0; i < hexStr.size(); i += 2) 622c04e2e70SJason M. Bills { 623c04e2e70SJason M. Bills try 624c04e2e70SJason M. Bills { 625c04e2e70SJason M. Bills data.push_back(static_cast<uint8_t>( 626c04e2e70SJason M. Bills std::stoul(hexStr.substr(i, 2), nullptr, 16))); 627c04e2e70SJason M. Bills } 628c04e2e70SJason M. Bills catch (std::invalid_argument& e) 629c04e2e70SJason M. Bills { 630c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 631c04e2e70SJason M. Bills return -1; 632c04e2e70SJason M. Bills } 633c04e2e70SJason M. Bills catch (std::out_of_range& e) 634c04e2e70SJason M. Bills { 635c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 636c04e2e70SJason M. Bills return -1; 637c04e2e70SJason M. Bills } 638c04e2e70SJason M. Bills } 639c04e2e70SJason M. Bills return 0; 640c04e2e70SJason M. Bills } 641c04e2e70SJason M. Bills 642c04e2e70SJason M. Bills static int getJournalMetadata(sd_journal* journal, 643c04e2e70SJason M. Bills const std::string_view& field, 644c04e2e70SJason M. Bills std::string& contents) 645c04e2e70SJason M. Bills { 646c04e2e70SJason M. Bills const char* data = nullptr; 647c04e2e70SJason M. Bills size_t length = 0; 648c04e2e70SJason M. Bills 649c04e2e70SJason M. Bills // Get the metadata from the requested field of the journal entry 650c04e2e70SJason M. Bills if (int ret = sd_journal_get_data(journal, field.data(), 651c04e2e70SJason M. Bills (const void**)&data, &length); 652c04e2e70SJason M. Bills ret < 0) 653c04e2e70SJason M. Bills { 654c04e2e70SJason M. Bills return ret; 655c04e2e70SJason M. Bills } 656c04e2e70SJason M. Bills std::string_view metadata(data, length); 657c04e2e70SJason M. Bills // Only use the content after the "=" character. 658c04e2e70SJason M. Bills metadata.remove_prefix(std::min(metadata.find("=") + 1, metadata.size())); 659c04e2e70SJason M. Bills contents = std::string(metadata); 660c04e2e70SJason M. Bills return 0; 661c04e2e70SJason M. Bills } 662c04e2e70SJason M. Bills 663c04e2e70SJason M. Bills static int getJournalMetadata(sd_journal* journal, 664c04e2e70SJason M. Bills const std::string_view& field, const int& base, 665c04e2e70SJason M. Bills int& contents) 666c04e2e70SJason M. Bills { 667c04e2e70SJason M. Bills std::string metadata; 668c04e2e70SJason M. Bills // Get the metadata from the requested field of the journal entry 669c04e2e70SJason M. Bills if (int ret = getJournalMetadata(journal, field, metadata); ret < 0) 670c04e2e70SJason M. Bills { 671c04e2e70SJason M. Bills return ret; 672c04e2e70SJason M. Bills } 673c04e2e70SJason M. Bills try 674c04e2e70SJason M. Bills { 675c04e2e70SJason M. Bills contents = static_cast<int>(std::stoul(metadata, nullptr, base)); 676c04e2e70SJason M. Bills } 677c04e2e70SJason M. Bills catch (std::invalid_argument& e) 678c04e2e70SJason M. Bills { 679c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 680c04e2e70SJason M. Bills return -1; 681c04e2e70SJason M. Bills } 682c04e2e70SJason M. Bills catch (std::out_of_range& e) 683c04e2e70SJason M. Bills { 684c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 685c04e2e70SJason M. Bills return -1; 686c04e2e70SJason M. Bills } 687c04e2e70SJason M. Bills return 0; 688c04e2e70SJason M. Bills } 689c04e2e70SJason M. Bills 690c04e2e70SJason M. Bills static int getJournalSelData(sd_journal* journal, std::vector<uint8_t>& evtData) 691c04e2e70SJason M. Bills { 692c04e2e70SJason M. Bills std::string evtDataStr; 693c04e2e70SJason M. Bills // Get the OEM data from the IPMI_SEL_DATA field 694c04e2e70SJason M. Bills if (int ret = getJournalMetadata(journal, "IPMI_SEL_DATA", evtDataStr); 695c04e2e70SJason M. Bills ret < 0) 696c04e2e70SJason M. Bills { 697c04e2e70SJason M. Bills return ret; 698c04e2e70SJason M. Bills } 699c04e2e70SJason M. Bills return fromHexStr(evtDataStr, evtData); 700c04e2e70SJason M. Bills } 701c04e2e70SJason M. Bills 702c04e2e70SJason M. Bills ipmi_ret_t ipmiStorageGetSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 703c04e2e70SJason M. Bills ipmi_request_t request, 704c04e2e70SJason M. Bills ipmi_response_t response, 705c04e2e70SJason M. Bills ipmi_data_len_t data_len, 706c04e2e70SJason M. Bills ipmi_context_t context) 707c04e2e70SJason M. Bills { 708c04e2e70SJason M. Bills if (*data_len != sizeof(ipmi::sel::GetSELEntryRequest)) 709c04e2e70SJason M. Bills { 710c04e2e70SJason M. Bills *data_len = 0; 711c04e2e70SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 712c04e2e70SJason M. Bills } 713c04e2e70SJason M. Bills *data_len = 0; // Default to 0 in case of errors 714c04e2e70SJason M. Bills auto requestData = 715c04e2e70SJason M. Bills static_cast<const ipmi::sel::GetSELEntryRequest*>(request); 716c04e2e70SJason M. Bills 717c04e2e70SJason M. Bills if (requestData->reservationID != 0 || requestData->offset != 0) 718c04e2e70SJason M. Bills { 719c04e2e70SJason M. Bills if (!checkSELReservation(requestData->reservationID)) 720c04e2e70SJason M. Bills { 721c04e2e70SJason M. Bills return IPMI_CC_INVALID_RESERVATION_ID; 722c04e2e70SJason M. Bills } 723c04e2e70SJason M. Bills } 724c04e2e70SJason M. Bills 725c04e2e70SJason M. Bills GetSELEntryResponse record{}; 726c04e2e70SJason M. Bills // Default as the last entry 727c04e2e70SJason M. Bills record.nextRecordID = ipmi::sel::lastEntry; 728c04e2e70SJason M. Bills 729c04e2e70SJason M. Bills // Check for the requested SEL Entry. 730c04e2e70SJason M. Bills sd_journal* journalTmp; 731c04e2e70SJason M. Bills if (int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY); ret < 0) 732c04e2e70SJason M. Bills { 733c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 734c04e2e70SJason M. Bills "Failed to open journal: ", 735c04e2e70SJason M. Bills phosphor::logging::entry("ERRNO=%s", strerror(-ret))); 736c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 737c04e2e70SJason M. Bills } 738c04e2e70SJason M. Bills std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal( 739c04e2e70SJason M. Bills journalTmp, sd_journal_close); 740c04e2e70SJason M. Bills journalTmp = nullptr; 741c04e2e70SJason M. Bills 742c04e2e70SJason M. Bills std::string match = 743c04e2e70SJason M. Bills "MESSAGE_ID=" + std::string(intel_oem::ipmi::sel::selMessageId); 744c04e2e70SJason M. Bills sd_journal_add_match(journal.get(), match.c_str(), 0); 745c04e2e70SJason M. Bills 746c04e2e70SJason M. Bills // Get the requested target SEL record ID if first or last is requested. 747c04e2e70SJason M. Bills int targetID = requestData->selRecordID; 748c04e2e70SJason M. Bills if (targetID == ipmi::sel::firstEntry) 749c04e2e70SJason M. Bills { 750c04e2e70SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 751c04e2e70SJason M. Bills { 752c04e2e70SJason M. Bills // Get the record ID from the IPMI_SEL_RECORD_ID field of the first 753c04e2e70SJason M. Bills // entry 754c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_RECORD_ID", 10, 755c04e2e70SJason M. Bills targetID) < 0) 756c04e2e70SJason M. Bills { 757c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 758c04e2e70SJason M. Bills } 759c04e2e70SJason M. Bills break; 760c04e2e70SJason M. Bills } 761c04e2e70SJason M. Bills } 762c04e2e70SJason M. Bills else if (targetID == ipmi::sel::lastEntry) 763c04e2e70SJason M. Bills { 764c04e2e70SJason M. Bills SD_JOURNAL_FOREACH_BACKWARDS(journal.get()) 765c04e2e70SJason M. Bills { 766c04e2e70SJason M. Bills // Get the record ID from the IPMI_SEL_RECORD_ID field of the first 767c04e2e70SJason M. Bills // entry 768c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_RECORD_ID", 10, 769c04e2e70SJason M. Bills targetID) < 0) 770c04e2e70SJason M. Bills { 771c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 772c04e2e70SJason M. Bills } 773c04e2e70SJason M. Bills break; 774c04e2e70SJason M. Bills } 775c04e2e70SJason M. Bills } 776c04e2e70SJason M. Bills // Find the requested ID 777c04e2e70SJason M. Bills match = "IPMI_SEL_RECORD_ID=" + std::to_string(targetID); 778c04e2e70SJason M. Bills sd_journal_add_match(journal.get(), match.c_str(), 0); 779c04e2e70SJason M. Bills // And find the next ID (wrapping to Record ID 1 when necessary) 780c04e2e70SJason M. Bills int nextID = targetID + 1; 781c04e2e70SJason M. Bills if (nextID == ipmi::sel::lastEntry) 782c04e2e70SJason M. Bills { 783c04e2e70SJason M. Bills nextID = 1; 784c04e2e70SJason M. Bills } 785c04e2e70SJason M. Bills match = "IPMI_SEL_RECORD_ID=" + std::to_string(nextID); 786c04e2e70SJason M. Bills sd_journal_add_match(journal.get(), match.c_str(), 0); 787c04e2e70SJason M. Bills SD_JOURNAL_FOREACH(journal.get()) 788c04e2e70SJason M. Bills { 789c04e2e70SJason M. Bills // Get the record ID from the IPMI_SEL_RECORD_ID field 790c04e2e70SJason M. Bills int id = 0; 791c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_RECORD_ID", 10, id) < 0) 792c04e2e70SJason M. Bills { 793c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 794c04e2e70SJason M. Bills } 795c04e2e70SJason M. Bills if (id == targetID) 796c04e2e70SJason M. Bills { 797c04e2e70SJason M. Bills // Found the desired record, so fill in the data 798c04e2e70SJason M. Bills record.recordID = id; 799c04e2e70SJason M. Bills 800c04e2e70SJason M. Bills int recordType = 0; 801c04e2e70SJason M. Bills // Get the record type from the IPMI_SEL_RECORD_TYPE field 802c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_RECORD_TYPE", 16, 803c04e2e70SJason M. Bills recordType) < 0) 804c04e2e70SJason M. Bills { 805c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 806c04e2e70SJason M. Bills } 807c04e2e70SJason M. Bills record.recordType = recordType; 808c04e2e70SJason M. Bills // The rest of the record depends on the record type 809c04e2e70SJason M. Bills if (record.recordType == intel_oem::ipmi::sel::systemEvent) 810c04e2e70SJason M. Bills { 811c04e2e70SJason M. Bills // Get the timestamp 812c04e2e70SJason M. Bills uint64_t ts = 0; 813c04e2e70SJason M. Bills if (sd_journal_get_realtime_usec(journal.get(), &ts) < 0) 814c04e2e70SJason M. Bills { 815c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 816c04e2e70SJason M. Bills } 817c04e2e70SJason M. Bills record.record.system.timestamp = static_cast<uint32_t>( 818c04e2e70SJason M. Bills ts / 1000 / 1000); // Convert from us to s 819c04e2e70SJason M. Bills 820c04e2e70SJason M. Bills int generatorID = 0; 821c04e2e70SJason M. Bills // Get the generator ID from the IPMI_SEL_GENERATOR_ID field 822c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_GENERATOR_ID", 823c04e2e70SJason M. Bills 16, generatorID) < 0) 824c04e2e70SJason M. Bills { 825c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 826c04e2e70SJason M. Bills } 827c04e2e70SJason M. Bills record.record.system.generatorID = generatorID; 828c04e2e70SJason M. Bills 829c04e2e70SJason M. Bills // Set the event message revision 830c04e2e70SJason M. Bills record.record.system.eventMsgRevision = 831c04e2e70SJason M. Bills intel_oem::ipmi::sel::eventMsgRev; 832c04e2e70SJason M. Bills 833c04e2e70SJason M. Bills std::string path; 834c04e2e70SJason M. Bills // Get the IPMI_SEL_SENSOR_PATH field 835c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_SENSOR_PATH", 836c04e2e70SJason M. Bills path) < 0) 837c04e2e70SJason M. Bills { 838c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 839c04e2e70SJason M. Bills } 840c04e2e70SJason M. Bills record.record.system.sensorType = getSensorTypeFromPath(path); 841c04e2e70SJason M. Bills record.record.system.sensorNum = getSensorNumberFromPath(path); 842c04e2e70SJason M. Bills record.record.system.eventType = 843c04e2e70SJason M. Bills getSensorEventTypeFromPath(path); 844c04e2e70SJason M. Bills 845c04e2e70SJason M. Bills int eventDir = 0; 846c04e2e70SJason M. Bills // Get the event direction from the IPMI_SEL_EVENT_DIR field 847c04e2e70SJason M. Bills if (getJournalMetadata(journal.get(), "IPMI_SEL_EVENT_DIR", 16, 848c04e2e70SJason M. Bills eventDir) < 0) 849c04e2e70SJason M. Bills { 850c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 851c04e2e70SJason M. Bills } 852c04e2e70SJason M. Bills // Set the event direction 853c04e2e70SJason M. Bills if (eventDir == 0) 854c04e2e70SJason M. Bills { 855c04e2e70SJason M. Bills record.record.system.eventDir = deassertionEvent; 856c04e2e70SJason M. Bills } 857c04e2e70SJason M. Bills 858c04e2e70SJason M. Bills std::vector<uint8_t> evtData; 859c04e2e70SJason M. Bills // Get the event data from the IPMI_SEL_DATA field 860c04e2e70SJason M. Bills if (getJournalSelData(journal.get(), evtData) < 0) 861c04e2e70SJason M. Bills { 862c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 863c04e2e70SJason M. Bills } 864c04e2e70SJason M. Bills record.record.system.eventData[0] = evtData[0]; 865c04e2e70SJason M. Bills record.record.system.eventData[1] = evtData[1]; 866c04e2e70SJason M. Bills record.record.system.eventData[2] = evtData[2]; 867c04e2e70SJason M. Bills } 868c04e2e70SJason M. Bills else if (record.recordType >= 869c04e2e70SJason M. Bills intel_oem::ipmi::sel::oemTsEventFirst && 870c04e2e70SJason M. Bills record.recordType <= intel_oem::ipmi::sel::oemTsEventLast) 871c04e2e70SJason M. Bills { 872c04e2e70SJason M. Bills // Get the timestamp 873c04e2e70SJason M. Bills uint64_t timestamp = 0; 874c04e2e70SJason M. Bills if (sd_journal_get_realtime_usec(journal.get(), ×tamp) < 0) 875c04e2e70SJason M. Bills { 876c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 877c04e2e70SJason M. Bills } 878c04e2e70SJason M. Bills record.record.oemTs.timestamp = static_cast<uint32_t>( 879c04e2e70SJason M. Bills timestamp / 1000 / 1000); // Convert from us to s 880c04e2e70SJason M. Bills 881c04e2e70SJason M. Bills std::vector<uint8_t> evtData; 882c04e2e70SJason M. Bills // Get the OEM data from the IPMI_SEL_DATA field 883c04e2e70SJason M. Bills if (getJournalSelData(journal.get(), evtData) < 0) 884c04e2e70SJason M. Bills { 885c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 886c04e2e70SJason M. Bills } 887c04e2e70SJason M. Bills // Only keep the bytes that fit in the record 888c04e2e70SJason M. Bills std::copy_n(evtData.begin(), 889c04e2e70SJason M. Bills std::min(evtData.size(), 890c04e2e70SJason M. Bills intel_oem::ipmi::sel::oemTsEventSize), 891c04e2e70SJason M. Bills record.record.oemTs.eventData); 892c04e2e70SJason M. Bills } 893c04e2e70SJason M. Bills else if (record.recordType >= intel_oem::ipmi::sel::oemEventFirst && 894c04e2e70SJason M. Bills record.recordType <= intel_oem::ipmi::sel::oemEventLast) 895c04e2e70SJason M. Bills { 896c04e2e70SJason M. Bills std::vector<uint8_t> evtData; 897c04e2e70SJason M. Bills // Get the OEM data from the IPMI_SEL_DATA field 898c04e2e70SJason M. Bills if (getJournalSelData(journal.get(), evtData) < 0) 899c04e2e70SJason M. Bills { 900c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 901c04e2e70SJason M. Bills } 902c04e2e70SJason M. Bills // Only keep the bytes that fit in the record 903c04e2e70SJason M. Bills std::copy_n(evtData.begin(), 904c04e2e70SJason M. Bills std::min(evtData.size(), 905c04e2e70SJason M. Bills intel_oem::ipmi::sel::oemEventSize), 906c04e2e70SJason M. Bills record.record.oem.eventData); 907c04e2e70SJason M. Bills } 908c04e2e70SJason M. Bills } 909c04e2e70SJason M. Bills else if (id == nextID) 910c04e2e70SJason M. Bills { 911c04e2e70SJason M. Bills record.nextRecordID = id; 912c04e2e70SJason M. Bills } 913c04e2e70SJason M. Bills } 914c04e2e70SJason M. Bills 915c04e2e70SJason M. Bills // If we didn't find the requested record, return an error 916c04e2e70SJason M. Bills if (record.recordID == 0) 917c04e2e70SJason M. Bills { 918c04e2e70SJason M. Bills return IPMI_CC_SENSOR_INVALID; 919c04e2e70SJason M. Bills } 920c04e2e70SJason M. Bills 921c04e2e70SJason M. Bills if (requestData->readLength == ipmi::sel::entireRecord) 922c04e2e70SJason M. Bills { 923c04e2e70SJason M. Bills std::copy(&record, &record + 1, 924c04e2e70SJason M. Bills static_cast<GetSELEntryResponse*>(response)); 925c04e2e70SJason M. Bills *data_len = sizeof(record); 926c04e2e70SJason M. Bills } 927c04e2e70SJason M. Bills else 928c04e2e70SJason M. Bills { 929c04e2e70SJason M. Bills if (requestData->offset >= ipmi::sel::selRecordSize || 930c04e2e70SJason M. Bills requestData->readLength > ipmi::sel::selRecordSize) 931c04e2e70SJason M. Bills { 932c04e2e70SJason M. Bills return IPMI_CC_PARM_OUT_OF_RANGE; 933c04e2e70SJason M. Bills } 934c04e2e70SJason M. Bills 935c04e2e70SJason M. Bills auto diff = ipmi::sel::selRecordSize - requestData->offset; 936c04e2e70SJason M. Bills auto readLength = 937c04e2e70SJason M. Bills std::min(diff, static_cast<int>(requestData->readLength)); 938c04e2e70SJason M. Bills 939c04e2e70SJason M. Bills *static_cast<uint16_t*>(response) = record.nextRecordID; 940c04e2e70SJason M. Bills std::copy_n( 941c04e2e70SJason M. Bills reinterpret_cast<uint8_t*>(&record.recordID) + requestData->offset, 942c04e2e70SJason M. Bills readLength, 943c04e2e70SJason M. Bills static_cast<uint8_t*>(response) + sizeof(record.nextRecordID)); 944c04e2e70SJason M. Bills *data_len = sizeof(record.nextRecordID) + readLength; 945c04e2e70SJason M. Bills } 946c04e2e70SJason M. Bills 947c04e2e70SJason M. Bills return IPMI_CC_OK; 948c04e2e70SJason M. Bills } 949c04e2e70SJason M. Bills 950c04e2e70SJason M. Bills ipmi_ret_t ipmiStorageAddSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 951c04e2e70SJason M. Bills ipmi_request_t request, 952c04e2e70SJason M. Bills ipmi_response_t response, 953c04e2e70SJason M. Bills ipmi_data_len_t data_len, 954c04e2e70SJason M. Bills ipmi_context_t context) 955c04e2e70SJason M. Bills { 956c04e2e70SJason M. Bills static constexpr char const* ipmiSELObject = 957c04e2e70SJason M. Bills "xyz.openbmc_project.Logging.IPMI"; 958c04e2e70SJason M. Bills static constexpr char const* ipmiSELPath = 959c04e2e70SJason M. Bills "/xyz/openbmc_project/Logging/IPMI"; 960c04e2e70SJason M. Bills static constexpr char const* ipmiSELAddInterface = 961c04e2e70SJason M. Bills "xyz.openbmc_project.Logging.IPMI"; 962c04e2e70SJason M. Bills static const std::string ipmiSELAddMessage = 963c04e2e70SJason M. Bills "IPMI SEL entry logged using IPMI Add SEL Entry command."; 964c04e2e70SJason M. Bills uint16_t recordID = 0; 965c04e2e70SJason M. Bills sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 966c04e2e70SJason M. Bills 967c04e2e70SJason M. Bills if (*data_len != sizeof(AddSELRequest)) 968c04e2e70SJason M. Bills { 969c04e2e70SJason M. Bills *data_len = 0; 970c04e2e70SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 971c04e2e70SJason M. Bills } 972c04e2e70SJason M. Bills AddSELRequest* req = static_cast<AddSELRequest*>(request); 973c04e2e70SJason M. Bills 974c04e2e70SJason M. Bills // Per the IPMI spec, need to cancel any reservation when a SEL entry is 975c04e2e70SJason M. Bills // added 976c04e2e70SJason M. Bills cancelSELReservation(); 977c04e2e70SJason M. Bills 978c04e2e70SJason M. Bills if (req->recordType == intel_oem::ipmi::sel::systemEvent) 979c04e2e70SJason M. Bills { 980c04e2e70SJason M. Bills std::string sensorPath = 981c04e2e70SJason M. Bills getPathFromSensorNumber(req->record.system.sensorNum); 982c04e2e70SJason M. Bills std::vector<uint8_t> eventData( 983c04e2e70SJason M. Bills req->record.system.eventData, 984c04e2e70SJason M. Bills req->record.system.eventData + 985c04e2e70SJason M. Bills intel_oem::ipmi::sel::systemEventSize); 986c04e2e70SJason M. Bills bool assert = req->record.system.eventDir ? false : true; 987c04e2e70SJason M. Bills uint16_t genId = req->record.system.generatorID; 988c04e2e70SJason M. Bills sdbusplus::message::message writeSEL = bus.new_method_call( 989c04e2e70SJason M. Bills ipmiSELObject, ipmiSELPath, ipmiSELAddInterface, "IpmiSelAdd"); 990c04e2e70SJason M. Bills writeSEL.append(ipmiSELAddMessage, sensorPath, eventData, assert, 991c04e2e70SJason M. Bills genId); 992c04e2e70SJason M. Bills try 993c04e2e70SJason M. Bills { 994c04e2e70SJason M. Bills sdbusplus::message::message writeSELResp = bus.call(writeSEL); 995c04e2e70SJason M. Bills writeSELResp.read(recordID); 996c04e2e70SJason M. Bills } 997c04e2e70SJason M. Bills catch (sdbusplus::exception_t& e) 998c04e2e70SJason M. Bills { 999c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 1000c04e2e70SJason M. Bills *data_len = 0; 1001c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 1002c04e2e70SJason M. Bills } 1003c04e2e70SJason M. Bills } 1004c04e2e70SJason M. Bills else if (req->recordType >= intel_oem::ipmi::sel::oemTsEventFirst && 1005c04e2e70SJason M. Bills req->recordType <= intel_oem::ipmi::sel::oemEventLast) 1006c04e2e70SJason M. Bills { 1007c04e2e70SJason M. Bills std::vector<uint8_t> eventData; 1008c04e2e70SJason M. Bills if (req->recordType <= intel_oem::ipmi::sel::oemTsEventLast) 1009c04e2e70SJason M. Bills { 1010c04e2e70SJason M. Bills eventData = 1011c04e2e70SJason M. Bills std::vector<uint8_t>(req->record.oemTs.eventData, 1012c04e2e70SJason M. Bills req->record.oemTs.eventData + 1013c04e2e70SJason M. Bills intel_oem::ipmi::sel::oemTsEventSize); 1014c04e2e70SJason M. Bills } 1015c04e2e70SJason M. Bills else 1016c04e2e70SJason M. Bills { 1017c04e2e70SJason M. Bills eventData = std::vector<uint8_t>( 1018c04e2e70SJason M. Bills req->record.oem.eventData, 1019c04e2e70SJason M. Bills req->record.oem.eventData + intel_oem::ipmi::sel::oemEventSize); 1020c04e2e70SJason M. Bills } 1021c04e2e70SJason M. Bills sdbusplus::message::message writeSEL = bus.new_method_call( 1022c04e2e70SJason M. Bills ipmiSELObject, ipmiSELPath, ipmiSELAddInterface, "IpmiSelAddOem"); 1023c04e2e70SJason M. Bills writeSEL.append(ipmiSELAddMessage, eventData, req->recordType); 1024c04e2e70SJason M. Bills try 1025c04e2e70SJason M. Bills { 1026c04e2e70SJason M. Bills sdbusplus::message::message writeSELResp = bus.call(writeSEL); 1027c04e2e70SJason M. Bills writeSELResp.read(recordID); 1028c04e2e70SJason M. Bills } 1029c04e2e70SJason M. Bills catch (sdbusplus::exception_t& e) 1030c04e2e70SJason M. Bills { 1031c04e2e70SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 1032c04e2e70SJason M. Bills *data_len = 0; 1033c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 1034c04e2e70SJason M. Bills } 1035c04e2e70SJason M. Bills } 1036c04e2e70SJason M. Bills else 1037c04e2e70SJason M. Bills { 1038c04e2e70SJason M. Bills *data_len = 0; 1039c04e2e70SJason M. Bills return IPMI_CC_PARM_OUT_OF_RANGE; 1040c04e2e70SJason M. Bills } 1041c04e2e70SJason M. Bills 1042c04e2e70SJason M. Bills *static_cast<uint16_t*>(response) = recordID; 1043c04e2e70SJason M. Bills *data_len = sizeof(recordID); 1044c04e2e70SJason M. Bills return IPMI_CC_OK; 1045c04e2e70SJason M. Bills } 1046c04e2e70SJason M. Bills 1047c04e2e70SJason M. Bills ipmi_ret_t ipmiStorageClearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1048c04e2e70SJason M. Bills ipmi_request_t request, ipmi_response_t response, 1049c04e2e70SJason M. Bills ipmi_data_len_t data_len, ipmi_context_t context) 1050c04e2e70SJason M. Bills { 1051c04e2e70SJason M. Bills if (*data_len != sizeof(ipmi::sel::ClearSELRequest)) 1052c04e2e70SJason M. Bills { 1053c04e2e70SJason M. Bills *data_len = 0; 1054c04e2e70SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 1055c04e2e70SJason M. Bills } 1056c04e2e70SJason M. Bills auto requestData = static_cast<const ipmi::sel::ClearSELRequest*>(request); 1057c04e2e70SJason M. Bills 1058c04e2e70SJason M. Bills if (!checkSELReservation(requestData->reservationID)) 1059c04e2e70SJason M. Bills { 1060c04e2e70SJason M. Bills *data_len = 0; 1061c04e2e70SJason M. Bills return IPMI_CC_INVALID_RESERVATION_ID; 1062c04e2e70SJason M. Bills } 1063c04e2e70SJason M. Bills 1064c04e2e70SJason M. Bills if (requestData->charC != 'C' || requestData->charL != 'L' || 1065c04e2e70SJason M. Bills requestData->charR != 'R') 1066c04e2e70SJason M. Bills { 1067c04e2e70SJason M. Bills *data_len = 0; 1068c04e2e70SJason M. Bills return IPMI_CC_INVALID_FIELD_REQUEST; 1069c04e2e70SJason M. Bills } 1070c04e2e70SJason M. Bills 1071c04e2e70SJason M. Bills uint8_t eraseProgress = ipmi::sel::eraseComplete; 1072c04e2e70SJason M. Bills 1073c04e2e70SJason M. Bills /* 1074c04e2e70SJason M. Bills * Erasure status cannot be fetched from DBUS, so always return erasure 1075c04e2e70SJason M. Bills * status as `erase completed`. 1076c04e2e70SJason M. Bills */ 1077c04e2e70SJason M. Bills if (requestData->eraseOperation == ipmi::sel::getEraseStatus) 1078c04e2e70SJason M. Bills { 1079c04e2e70SJason M. Bills *static_cast<uint8_t*>(response) = eraseProgress; 1080c04e2e70SJason M. Bills *data_len = sizeof(eraseProgress); 1081c04e2e70SJason M. Bills return IPMI_CC_OK; 1082c04e2e70SJason M. Bills } 1083c04e2e70SJason M. Bills 1084c04e2e70SJason M. Bills // Per the IPMI spec, need to cancel any reservation when the SEL is cleared 1085c04e2e70SJason M. Bills cancelSELReservation(); 1086c04e2e70SJason M. Bills 1087*7944c307SJason M. Bills // Save the erase time 1088*7944c307SJason M. Bills intel_oem::ipmi::sel::erase_time::save(); 1089*7944c307SJason M. Bills 1090c04e2e70SJason M. Bills // Clear the SEL by by rotating the journal to start a new file then 1091c04e2e70SJason M. Bills // vacuuming to keep only the new file 1092c49adb70SJason M. Bills if (boost::process::system("/bin/journalctl", "--rotate") != 0) 1093c04e2e70SJason M. Bills { 1094c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 1095c04e2e70SJason M. Bills } 1096c49adb70SJason M. Bills if (boost::process::system("/bin/journalctl", "--vacuum-files=1") != 0) 1097c04e2e70SJason M. Bills { 1098c04e2e70SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 1099c04e2e70SJason M. Bills } 1100c04e2e70SJason M. Bills 1101c04e2e70SJason M. Bills *static_cast<uint8_t*>(response) = eraseProgress; 1102c04e2e70SJason M. Bills *data_len = sizeof(eraseProgress); 1103c04e2e70SJason M. Bills return IPMI_CC_OK; 1104c04e2e70SJason M. Bills } 1105c04e2e70SJason M. Bills 1106cac97a53SJason M. Bills ipmi_ret_t ipmiStorageSetSELTime(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1107cac97a53SJason M. Bills ipmi_request_t request, 1108cac97a53SJason M. Bills ipmi_response_t response, 1109cac97a53SJason M. Bills ipmi_data_len_t data_len, 1110cac97a53SJason M. Bills ipmi_context_t context) 1111cac97a53SJason M. Bills { 1112cac97a53SJason M. Bills // Set SEL Time is not supported 1113cac97a53SJason M. Bills *data_len = 0; 1114cac97a53SJason M. Bills return IPMI_CC_INVALID; 1115cac97a53SJason M. Bills } 1116cac97a53SJason M. Bills 1117e2d1aee3SJason M. Bills void registerStorageFunctions() 1118e2d1aee3SJason M. Bills { 1119e2d1aee3SJason M. Bills // <Get FRU Inventory Area Info> 1120e2d1aee3SJason M. Bills ipmiPrintAndRegister( 1121e2d1aee3SJason M. Bills NETFUN_STORAGE, 1122e2d1aee3SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetFRUInvAreaInfo), 1123e2d1aee3SJason M. Bills NULL, ipmiStorageGetFRUInvAreaInfo, PRIVILEGE_OPERATOR); 1124e2d1aee3SJason M. Bills 1125c04e2e70SJason M. Bills // <READ FRU Data> 1126e2d1aee3SJason M. Bills ipmiPrintAndRegister( 1127e2d1aee3SJason M. Bills NETFUN_STORAGE, 1128e2d1aee3SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReadFRUData), NULL, 1129e2d1aee3SJason M. Bills ipmiStorageReadFRUData, PRIVILEGE_OPERATOR); 1130e2d1aee3SJason M. Bills 1131c04e2e70SJason M. Bills // <WRITE FRU Data> 1132e2d1aee3SJason M. Bills ipmiPrintAndRegister( 1133e2d1aee3SJason M. Bills NETFUN_STORAGE, 1134e2d1aee3SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdWriteFRUData), 1135e2d1aee3SJason M. Bills NULL, ipmiStorageWriteFRUData, PRIVILEGE_OPERATOR); 1136c04e2e70SJason M. Bills 1137c04e2e70SJason M. Bills // <Get SEL Info> 1138c04e2e70SJason M. Bills ipmiPrintAndRegister( 1139c04e2e70SJason M. Bills NETFUN_STORAGE, 1140c04e2e70SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetSELInfo), NULL, 1141c04e2e70SJason M. Bills ipmiStorageGetSELInfo, PRIVILEGE_OPERATOR); 1142c04e2e70SJason M. Bills 1143c04e2e70SJason M. Bills // <Get SEL Entry> 1144c04e2e70SJason M. Bills ipmiPrintAndRegister( 1145c04e2e70SJason M. Bills NETFUN_STORAGE, 1146c04e2e70SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetSELEntry), NULL, 1147c04e2e70SJason M. Bills ipmiStorageGetSELEntry, PRIVILEGE_OPERATOR); 1148c04e2e70SJason M. Bills 1149c04e2e70SJason M. Bills // <Add SEL Entry> 1150c04e2e70SJason M. Bills ipmiPrintAndRegister( 1151c04e2e70SJason M. Bills NETFUN_STORAGE, 1152c04e2e70SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdAddSEL), NULL, 1153c04e2e70SJason M. Bills ipmiStorageAddSELEntry, PRIVILEGE_OPERATOR); 1154c04e2e70SJason M. Bills 1155c04e2e70SJason M. Bills // <Clear SEL> 1156c04e2e70SJason M. Bills ipmiPrintAndRegister( 1157c04e2e70SJason M. Bills NETFUN_STORAGE, 1158c04e2e70SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdClearSEL), NULL, 1159c04e2e70SJason M. Bills ipmiStorageClearSEL, PRIVILEGE_OPERATOR); 1160cac97a53SJason M. Bills 1161cac97a53SJason M. Bills // <Set SEL Time> 1162cac97a53SJason M. Bills ipmiPrintAndRegister( 1163cac97a53SJason M. Bills NETFUN_STORAGE, 1164cac97a53SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdSetSELTime), NULL, 1165cac97a53SJason M. Bills ipmiStorageSetSELTime, PRIVILEGE_OPERATOR); 1166e2d1aee3SJason M. Bills } 11673f7c5e40SJason M. Bills } // namespace storage 11683f7c5e40SJason M. Bills } // namespace ipmi 1169