xref: /openbmc/intel-ipmi-oem/src/sensorcommands.cpp (revision a021e32b2486b3a2248f141c78b8e3b365ecf5fd)
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 
1731b35d5aSPatrick Venture #include "ipmi_to_redfish_hooks.hpp"
1831b35d5aSPatrick Venture 
193f7c5e40SJason M. Bills #include <boost/algorithm/string.hpp>
203f7c5e40SJason M. Bills #include <boost/container/flat_map.hpp>
21fcd2d3a9SJames Feist #include <ipmid/api.hpp>
22fcd2d3a9SJames Feist #include <ipmid/utils.hpp>
23fcd2d3a9SJames Feist #include <phosphor-logging/log.hpp>
24fcd2d3a9SJames Feist #include <sdbusplus/bus.hpp>
25fcd2d3a9SJames Feist 
26fcd2d3a9SJames Feist #include <algorithm>
27fcd2d3a9SJames Feist #include <array>
283f7c5e40SJason M. Bills #include <cmath>
29dcff1506SVernon Mauery #include <cstdint>
305c2d26e9SPatrick Venture #include <cstring>
31fd2a938cSPatrick Venture #include <memory>
32c4e9de6cSPatrick Venture #include <optional>
333f7c5e40SJason M. Bills #include <string>
343f7c5e40SJason M. Bills 
353f7c5e40SJason M. Bills namespace ipmi
363f7c5e40SJason M. Bills {
373f7c5e40SJason M. Bills void registerSensorFunctions() __attribute__((constructor));
383f7c5e40SJason M. Bills 
397aaf3fe8SJames Feist namespace meHealth
407aaf3fe8SJames Feist {
417aaf3fe8SJames Feist constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
427aaf3fe8SJames Feist constexpr const char* path = "/xyz/openbmc_project/status/me";
437aaf3fe8SJames Feist constexpr const char* interface = "xyz.openbmc_project.SetHealth";
447aaf3fe8SJames Feist constexpr const char* method = "SetHealth";
457aaf3fe8SJames Feist constexpr const char* critical = "critical";
467aaf3fe8SJames Feist constexpr const char* warning = "warning";
477aaf3fe8SJames Feist constexpr const char* ok = "ok";
487aaf3fe8SJames Feist } // namespace meHealth
497aaf3fe8SJames Feist 
setMeStatus(uint8_t eventData2,uint8_t eventData3,bool disable)507aaf3fe8SJames Feist static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
517aaf3fe8SJames Feist {
527aaf3fe8SJames Feist     constexpr const std::array<uint8_t, 10> critical = {
537aaf3fe8SJames Feist         0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
547aaf3fe8SJames Feist     constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
557aaf3fe8SJames Feist                                                       0x1A};
567aaf3fe8SJames Feist 
577aaf3fe8SJames Feist     std::string state;
587aaf3fe8SJames Feist     if (std::find(critical.begin(), critical.end(), eventData2) !=
597aaf3fe8SJames Feist         critical.end())
607aaf3fe8SJames Feist     {
617aaf3fe8SJames Feist         state = meHealth::critical;
627aaf3fe8SJames Feist     }
637aaf3fe8SJames Feist     // special case 0x3 as we only care about a few states
647aaf3fe8SJames Feist     else if (eventData2 == 0x3)
657aaf3fe8SJames Feist     {
667aaf3fe8SJames Feist         if (eventData3 <= 0x2)
677aaf3fe8SJames Feist         {
687aaf3fe8SJames Feist             state = meHealth::warning;
697aaf3fe8SJames Feist         }
707aaf3fe8SJames Feist         else
717aaf3fe8SJames Feist         {
727aaf3fe8SJames Feist             return;
737aaf3fe8SJames Feist         }
747aaf3fe8SJames Feist     }
757aaf3fe8SJames Feist     else if (std::find(warning.begin(), warning.end(), eventData2) !=
767aaf3fe8SJames Feist              warning.end())
777aaf3fe8SJames Feist     {
787aaf3fe8SJames Feist         state = meHealth::warning;
797aaf3fe8SJames Feist     }
807aaf3fe8SJames Feist     else
817aaf3fe8SJames Feist     {
827aaf3fe8SJames Feist         return;
837aaf3fe8SJames Feist     }
847aaf3fe8SJames Feist     if (disable)
857aaf3fe8SJames Feist     {
867aaf3fe8SJames Feist         state = meHealth::ok;
877aaf3fe8SJames Feist     }
887aaf3fe8SJames Feist 
897aaf3fe8SJames Feist     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
90*1bcced08SPatrick Williams     auto setHealth =
91*1bcced08SPatrick Williams         dbus->new_method_call(meHealth::busname, meHealth::path,
92*1bcced08SPatrick Williams                               meHealth::interface, meHealth::method);
937aaf3fe8SJames Feist     setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
947aaf3fe8SJames Feist     try
957aaf3fe8SJames Feist     {
967aaf3fe8SJames Feist         dbus->call(setHealth);
977aaf3fe8SJames Feist     }
98bd51e6a9SPatrick Williams     catch (const sdbusplus::exception_t&)
997aaf3fe8SJames Feist     {
1007aaf3fe8SJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1017aaf3fe8SJames Feist             "Failed to set ME Health");
1027aaf3fe8SJames Feist     }
1037aaf3fe8SJames Feist }
1047aaf3fe8SJames Feist 
ipmiSenPlatformEvent(ipmi::Context::ptr ctx,ipmi::message::Payload & p)105989a13b4SChalapathi Venkataramashetty ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
106989a13b4SChalapathi Venkataramashetty                                      ipmi::message::Payload& p)
107ae6bdb11SJason M. Bills {
1087aaf3fe8SJames Feist     constexpr const uint8_t meId = 0x2C;
1097aaf3fe8SJames Feist     constexpr const uint8_t meSensorNum = 0x17;
1107aaf3fe8SJames Feist     constexpr const uint8_t disabled = 0x80;
1117aaf3fe8SJames Feist 
1129e58cfe1SSujoy Ray     uint8_t sysgeneratorID = 0;
113ae6bdb11SJason M. Bills     uint8_t evmRev = 0;
114ae6bdb11SJason M. Bills     uint8_t sensorType = 0;
115ae6bdb11SJason M. Bills     uint8_t sensorNum = 0;
116ae6bdb11SJason M. Bills     uint8_t eventType = 0;
117ae6bdb11SJason M. Bills     uint8_t eventData1 = 0;
118ae6bdb11SJason M. Bills     std::optional<uint8_t> eventData2 = 0;
119ae6bdb11SJason M. Bills     std::optional<uint8_t> eventData3 = 0;
1209e58cfe1SSujoy Ray     uint16_t generatorID = 0;
121989a13b4SChalapathi Venkataramashetty     ipmi::ChannelInfo chInfo;
122ae6bdb11SJason M. Bills 
123989a13b4SChalapathi Venkataramashetty     if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
124ae6bdb11SJason M. Bills     {
125989a13b4SChalapathi Venkataramashetty         phosphor::logging::log<phosphor::logging::level::ERR>(
126989a13b4SChalapathi Venkataramashetty             "Failed to get Channel Info",
127989a13b4SChalapathi Venkataramashetty             phosphor::logging::entry("CHANNEL=%d", ctx->channel));
128989a13b4SChalapathi Venkataramashetty         return ipmi::responseUnspecifiedError();
129ae6bdb11SJason M. Bills     }
130989a13b4SChalapathi Venkataramashetty 
131989a13b4SChalapathi Venkataramashetty     if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
132989a13b4SChalapathi Venkataramashetty         ipmi::EChannelMediumType::systemInterface)
133ae6bdb11SJason M. Bills     {
1349e58cfe1SSujoy Ray         p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
135ae6bdb11SJason M. Bills                  eventData1, eventData2, eventData3);
1365d24dda2SVernon Mauery         constexpr const uint8_t isSoftwareID = 0x01;
1375d24dda2SVernon Mauery         if (!(sysgeneratorID & isSoftwareID))
1385d24dda2SVernon Mauery         {
1395d24dda2SVernon Mauery             return ipmi::responseInvalidFieldRequest();
1405d24dda2SVernon Mauery         }
1419e58cfe1SSujoy Ray         // Refer to IPMI Spec Table 32: SEL Event Records
1429e58cfe1SSujoy Ray         generatorID = (ctx->channel << 12) // Channel
1439e58cfe1SSujoy Ray                       | (0x0 << 10)        // Reserved
1449e58cfe1SSujoy Ray                       | (0x0 << 8)         // 0x0 for sys-soft ID
1455d24dda2SVernon Mauery                       | sysgeneratorID;
146ae6bdb11SJason M. Bills     }
147989a13b4SChalapathi Venkataramashetty     else
148989a13b4SChalapathi Venkataramashetty     {
149989a13b4SChalapathi Venkataramashetty         p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
150989a13b4SChalapathi Venkataramashetty                  eventData2, eventData3);
1519e58cfe1SSujoy Ray         // Refer to IPMI Spec Table 32: SEL Event Records
1529e58cfe1SSujoy Ray         generatorID = (ctx->channel << 12)      // Channel
1539e58cfe1SSujoy Ray                       | (0x0 << 10)             // Reserved
1549e58cfe1SSujoy Ray                       | ((ctx->lun & 0x3) << 8) // Lun
1559e58cfe1SSujoy Ray                       | (ctx->rqSA << 1);
156989a13b4SChalapathi Venkataramashetty     }
157989a13b4SChalapathi Venkataramashetty 
158ae6bdb11SJason M. Bills     if (!p.fullyUnpacked())
159ae6bdb11SJason M. Bills     {
160ae6bdb11SJason M. Bills         return ipmi::responseReqDataLenInvalid();
161ae6bdb11SJason M. Bills     }
162ae6bdb11SJason M. Bills 
163989a13b4SChalapathi Venkataramashetty     // Check for valid evmRev and Sensor Type(per Table 42 of spec)
164989a13b4SChalapathi Venkataramashetty     if (evmRev != 0x04)
165989a13b4SChalapathi Venkataramashetty     {
166989a13b4SChalapathi Venkataramashetty         return ipmi::responseInvalidFieldRequest();
167989a13b4SChalapathi Venkataramashetty     }
168989a13b4SChalapathi Venkataramashetty     if ((sensorType > 0x2C) && (sensorType < 0xC0))
169989a13b4SChalapathi Venkataramashetty     {
170989a13b4SChalapathi Venkataramashetty         return ipmi::responseInvalidFieldRequest();
171989a13b4SChalapathi Venkataramashetty     }
172989a13b4SChalapathi Venkataramashetty 
1736dd8f047SJason M. Bills     // Send this request to the Redfish hooks to log it as a Redfish message
1746dd8f047SJason M. Bills     // instead.  There is no need to add it to the SEL, so just return success.
1756dd8f047SJason M. Bills     intel_oem::ipmi::sel::checkRedfishHooks(
17699b78ec8SJason M. Bills         generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
1776dd8f047SJason M. Bills         eventData2.value_or(0xFF), eventData3.value_or(0xFF));
178ae6bdb11SJason M. Bills 
179ce3b7577SVernon Mauery     if (static_cast<uint8_t>(generatorID) == meId && sensorNum == meSensorNum &&
1809e58cfe1SSujoy Ray         eventData2 && eventData3)
1817aaf3fe8SJames Feist     {
1827aaf3fe8SJames Feist         setMeStatus(*eventData2, *eventData3, (eventType & disabled));
1837aaf3fe8SJames Feist     }
1847aaf3fe8SJames Feist 
185ae6bdb11SJason M. Bills     return ipmi::responseSuccess();
186ae6bdb11SJason M. Bills }
187ae6bdb11SJason M. Bills 
registerSensorFunctions()1883f7c5e40SJason M. Bills void registerSensorFunctions()
1893f7c5e40SJason M. Bills {
190ae6bdb11SJason M. Bills     // <Platform Event>
19198bbf69aSVernon Mauery     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
19298bbf69aSVernon Mauery                           ipmi::sensor_event::cmdPlatformEvent,
193ae6bdb11SJason M. Bills                           ipmi::Privilege::Operator, ipmiSenPlatformEvent);
1943f7c5e40SJason M. Bills }
1953f7c5e40SJason M. Bills } // namespace ipmi
196