/* // Copyright (c) 2017 2018 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #include "ipmi_to_redfish_hooks.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ipmi { void registerSensorFunctions() __attribute__((constructor)); namespace meHealth { constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy"; constexpr const char* path = "/xyz/openbmc_project/status/me"; constexpr const char* interface = "xyz.openbmc_project.SetHealth"; constexpr const char* method = "SetHealth"; constexpr const char* critical = "critical"; constexpr const char* warning = "warning"; constexpr const char* ok = "ok"; } // namespace meHealth static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable) { constexpr const std::array critical = { 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE}; constexpr const std::array warning = {0x3, 0xA, 0x13, 0x19, 0x1A}; std::string state; if (std::find(critical.begin(), critical.end(), eventData2) != critical.end()) { state = meHealth::critical; } // special case 0x3 as we only care about a few states else if (eventData2 == 0x3) { if (eventData3 <= 0x2) { state = meHealth::warning; } else { return; } } else if (std::find(warning.begin(), warning.end(), eventData2) != warning.end()) { state = meHealth::warning; } else { return; } if (disable) { state = meHealth::ok; } std::shared_ptr dbus = getSdBus(); auto setHealth = dbus->new_method_call(meHealth::busname, meHealth::path, meHealth::interface, meHealth::method); setHealth.append(std::to_string(static_cast(eventData2)), state); try { dbus->call(setHealth); } catch (const sdbusplus::exception_t&) { phosphor::logging::log( "Failed to set ME Health"); } } ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx, ipmi::message::Payload& p) { constexpr const uint8_t meId = 0x2C; constexpr const uint8_t meSensorNum = 0x17; constexpr const uint8_t disabled = 0x80; uint8_t sysgeneratorID = 0; uint8_t evmRev = 0; uint8_t sensorType = 0; uint8_t sensorNum = 0; uint8_t eventType = 0; uint8_t eventData1 = 0; std::optional eventData2 = 0; std::optional eventData3 = 0; uint16_t generatorID = 0; ipmi::ChannelInfo chInfo; if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess) { phosphor::logging::log( "Failed to get Channel Info", phosphor::logging::entry("CHANNEL=%d", ctx->channel)); return ipmi::responseUnspecifiedError(); } if (static_cast(chInfo.mediumType) == ipmi::EChannelMediumType::systemInterface) { p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType, eventData1, eventData2, eventData3); constexpr const uint8_t isSoftwareID = 0x01; if (!(sysgeneratorID & isSoftwareID)) { return ipmi::responseInvalidFieldRequest(); } // Refer to IPMI Spec Table 32: SEL Event Records generatorID = (ctx->channel << 12) // Channel | (0x0 << 10) // Reserved | (0x0 << 8) // 0x0 for sys-soft ID | sysgeneratorID; } else { p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1, eventData2, eventData3); // Refer to IPMI Spec Table 32: SEL Event Records generatorID = (ctx->channel << 12) // Channel | (0x0 << 10) // Reserved | ((ctx->lun & 0x3) << 8) // Lun | (ctx->rqSA << 1); } if (!p.fullyUnpacked()) { return ipmi::responseReqDataLenInvalid(); } // Check for valid evmRev and Sensor Type(per Table 42 of spec) if (evmRev != 0x04) { return ipmi::responseInvalidFieldRequest(); } if ((sensorType > 0x2C) && (sensorType < 0xC0)) { return ipmi::responseInvalidFieldRequest(); } // Send this request to the Redfish hooks to log it as a Redfish message // instead. There is no need to add it to the SEL, so just return success. intel_oem::ipmi::sel::checkRedfishHooks( generatorID, evmRev, sensorType, sensorNum, eventType, eventData1, eventData2.value_or(0xFF), eventData3.value_or(0xFF)); if (static_cast(generatorID) == meId && sensorNum == meSensorNum && eventData2 && eventData3) { setMeStatus(*eventData2, *eventData3, (eventType & disabled)); } return ipmi::responseSuccess(); } void registerSensorFunctions() { // ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor, ipmi::sensor_event::cmdPlatformEvent, ipmi::Privilege::Operator, ipmiSenPlatformEvent); } } // namespace ipmi