blob: 4dc170f8d80283ec8787129494055af5e18798b8 [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venture31b35d52019-10-20 13:25:16 -070017#include "sensorcommands.hpp"
18
19#include "commandutils.hpp"
20#include "ipmi_to_redfish_hooks.hpp"
21#include "sdrutils.hpp"
22#include "sensorutils.hpp"
23#include "storagecommands.hpp"
Patrick Venturec2a07d42020-05-30 16:35:03 -070024#include "types.hpp"
Patrick Venture31b35d52019-10-20 13:25:16 -070025
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070026#include <boost/algorithm/string.hpp>
27#include <boost/container/flat_map.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070028#include <ipmid/api.hpp>
29#include <ipmid/utils.hpp>
30#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
32
33#include <algorithm>
34#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070035#include <chrono>
36#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070037#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <iostream>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070039#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070040#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070041#include <optional>
Patrick Venturee6154022019-09-25 17:50:25 -070042#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070043#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070044#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070045#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070046
47namespace ipmi
48{
49using ManagedObjectType =
50 std::map<sdbusplus::message::object_path,
51 std::map<std::string, std::map<std::string, DbusVariant>>>;
52
James Feist25690252019-12-23 12:25:49 -080053static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu09701ef2020-07-15 17:56:21 -070054static constexpr int sensorMapSdrUpdatePeriod = 60;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070055
56constexpr size_t maxSDRTotalSize =
57 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
58constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
59
60static uint16_t sdrReservationID;
61static uint32_t sdrLastAdd = noTimestamp;
62static uint32_t sdrLastRemove = noTimestamp;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070063static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey2346b5d2021-08-06 11:21:10 -070064
65// The IPMI spec defines four Logical Units (LUN), each capable of supporting
66// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
67// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
68// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
69// location.
70static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
71
72static constexpr size_t lun0MaxSensorNum = 0xfe;
73static constexpr size_t lun1MaxSensorNum = 0x1fe;
74static constexpr size_t lun3MaxSensorNum = 0x3fe;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070075static constexpr int GENERAL_ERROR = -1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070076
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053077SensorSubTree sensorTree;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070078
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
80
Jason M. Bills039c3492022-09-09 14:27:28 -070081constexpr static std::array<std::pair<const char*, SensorUnits>, 5> sensorUnits{
82 {{"temperature", SensorUnits::degreesC},
83 {"voltage", SensorUnits::volts},
84 {"current", SensorUnits::amps},
85 {"fan_tach", SensorUnits::rpm},
86 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070087
88void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070089
Patrick Williamsf944d2e2022-07-22 19:26:52 -050090static sdbusplus::bus::match_t sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070091 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070092 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
93 "sensors/'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -050094 [](sdbusplus::message_t& m) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -050095 sensorTree.clear();
96 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
97 std::chrono::system_clock::now().time_since_epoch())
98 .count();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070099 });
100
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500101static sdbusplus::bus::match_t sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700102 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700103 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
104 "sensors/'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500105 [](sdbusplus::message_t& m) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500106 sensorTree.clear();
107 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
108 std::chrono::system_clock::now().time_since_epoch())
109 .count();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700110 });
111
James Feist392786a2019-03-19 13:36:10 -0700112// this keeps track of deassertions for sensor event status command. A
113// deasertion can only happen if an assertion was seen first.
114static boost::container::flat_map<
115 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
116 thresholdDeassertMap;
117
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500118static sdbusplus::bus::match_t thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700119 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700120 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
121 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500122 [](sdbusplus::message_t& m) {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500123 boost::container::flat_map<std::string, ipmi::DbusVariant> values;
124 m.read(std::string(), values);
James Feist392786a2019-03-19 13:36:10 -0700125
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500126 auto findAssert = std::find_if(values.begin(), values.end(),
127 [](const auto& pair) {
128 return pair.first.find("Alarm") != std::string::npos;
129 });
130 if (findAssert != values.end())
131 {
132 auto ptr = std::get_if<bool>(&(findAssert->second));
133 if (ptr == nullptr)
James Feist392786a2019-03-19 13:36:10 -0700134 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500135 phosphor::logging::log<phosphor::logging::level::ERR>(
136 "thresholdChanged: Assert non bool");
137 return;
138 }
139 if (*ptr)
140 {
141 phosphor::logging::log<phosphor::logging::level::INFO>(
142 "thresholdChanged: Assert",
143 phosphor::logging::entry("SENSOR=%s", m.get_path()));
144 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
145 }
146 else
147 {
148 auto& value = thresholdDeassertMap[m.get_path()][findAssert->first];
149 if (value)
James Feist392786a2019-03-19 13:36:10 -0700150 {
151 phosphor::logging::log<phosphor::logging::level::INFO>(
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500152 "thresholdChanged: deassert",
James Feist392786a2019-03-19 13:36:10 -0700153 phosphor::logging::entry("SENSOR=%s", m.get_path()));
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500154 value = *ptr;
James Feist392786a2019-03-19 13:36:10 -0700155 }
156 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500157 }
James Feist392786a2019-03-19 13:36:10 -0700158 });
159
James Feistfcd2d3a2020-05-28 10:38:15 -0700160static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
161 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700162{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700163 max = 127;
164 min = -128;
165
James Feistaecaef72019-04-26 10:30:32 -0700166 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
167 auto critical =
168 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
169 auto warning =
170 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
171
172 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700173 {
James Feistaecaef72019-04-26 10:30:32 -0700174 auto maxMap = sensorObject->second.find("MaxValue");
175 auto minMap = sensorObject->second.find("MinValue");
176
177 if (maxMap != sensorObject->second.end())
178 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700179 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700180 }
181 if (minMap != sensorObject->second.end())
182 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700183 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700184 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700185 }
James Feistaecaef72019-04-26 10:30:32 -0700186 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700187 {
James Feistaecaef72019-04-26 10:30:32 -0700188 auto lower = critical->second.find("CriticalLow");
189 auto upper = critical->second.find("CriticalHigh");
190 if (lower != critical->second.end())
191 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700192 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700193 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700194 }
195 if (upper != critical->second.end())
196 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700197 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700198 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700199 }
200 }
201 if (warning != sensorMap.end())
202 {
James Feistaecaef72019-04-26 10:30:32 -0700203 auto lower = warning->second.find("WarningLow");
204 auto upper = warning->second.find("WarningHigh");
205 if (lower != warning->second.end())
206 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700207 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700208 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700209 }
210 if (upper != warning->second.end())
211 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700212 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700213 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700214 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700215 }
216}
217
James Feist25690252019-12-23 12:25:49 -0800218static bool getSensorMap(boost::asio::yield_context yield,
219 std::string sensorConnection, std::string sensorPath,
Alex Qiu09701ef2020-07-15 17:56:21 -0700220 SensorMap& sensorMap,
221 int updatePeriod = sensorMapUpdatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700222{
223 static boost::container::flat_map<
224 std::string, std::chrono::time_point<std::chrono::steady_clock>>
225 updateTimeMap;
226
227 auto updateFind = updateTimeMap.find(sensorConnection);
228 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
229 if (updateFind != updateTimeMap.end())
230 {
231 lastUpdate = updateFind->second;
232 }
233
234 auto now = std::chrono::steady_clock::now();
235
236 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu09701ef2020-07-15 17:56:21 -0700237 .count() > updatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700238 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700239 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800240 boost::system::error_code ec;
241 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
Ed Tanousff4982a2022-10-04 17:27:35 -0700242 yield, ec, sensorConnection.c_str(), "/xyz/openbmc_project/sensors",
James Feist25690252019-12-23 12:25:49 -0800243 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
244 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700245 {
246 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800247 "GetMangagedObjects for getSensorMap failed",
248 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
249
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700250 return false;
251 }
252
253 SensorCache[sensorConnection] = managedObjects;
Alex Qiu09701ef2020-07-15 17:56:21 -0700254 // Update time after finish building the map which allow the
255 // data to be cached for updatePeriod plus the build time.
256 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700257 }
258 auto connection = SensorCache.find(sensorConnection);
259 if (connection == SensorCache.end())
260 {
261 return false;
262 }
263 auto path = connection->second.find(sensorPath);
264 if (path == connection->second.end())
265 {
266 return false;
267 }
268 sensorMap = path->second;
269
270 return true;
271}
272
273/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700274namespace meHealth
275{
James Feistfcd2d3a2020-05-28 10:38:15 -0700276constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
277constexpr const char* path = "/xyz/openbmc_project/status/me";
278constexpr const char* interface = "xyz.openbmc_project.SetHealth";
279constexpr const char* method = "SetHealth";
280constexpr const char* critical = "critical";
281constexpr const char* warning = "warning";
282constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700283} // namespace meHealth
284
285static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
286{
287 constexpr const std::array<uint8_t, 10> critical = {
288 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
289 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
290 0x1A};
291
292 std::string state;
293 if (std::find(critical.begin(), critical.end(), eventData2) !=
294 critical.end())
295 {
296 state = meHealth::critical;
297 }
298 // special case 0x3 as we only care about a few states
299 else if (eventData2 == 0x3)
300 {
301 if (eventData3 <= 0x2)
302 {
303 state = meHealth::warning;
304 }
305 else
306 {
307 return;
308 }
309 }
310 else if (std::find(warning.begin(), warning.end(), eventData2) !=
311 warning.end())
312 {
313 state = meHealth::warning;
314 }
315 else
316 {
317 return;
318 }
319 if (disable)
320 {
321 state = meHealth::ok;
322 }
323
324 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500325 auto setHealth = dbus->new_method_call(meHealth::busname, meHealth::path,
326 meHealth::interface,
327 meHealth::method);
James Feist7aaf3fe2019-06-25 11:52:11 -0700328 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
329 try
330 {
331 dbus->call(setHealth);
332 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500333 catch (const sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700334 {
335 phosphor::logging::log<phosphor::logging::level::ERR>(
336 "Failed to set ME Health");
337 }
338}
339
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000340ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
341 ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700342{
James Feist7aaf3fe2019-06-25 11:52:11 -0700343 constexpr const uint8_t meId = 0x2C;
344 constexpr const uint8_t meSensorNum = 0x17;
345 constexpr const uint8_t disabled = 0x80;
346
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700347 uint8_t sysgeneratorID = 0;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700348 uint8_t evmRev = 0;
349 uint8_t sensorType = 0;
350 uint8_t sensorNum = 0;
351 uint8_t eventType = 0;
352 uint8_t eventData1 = 0;
353 std::optional<uint8_t> eventData2 = 0;
354 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700355 uint16_t generatorID = 0;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000356 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700357
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000358 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700359 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000360 phosphor::logging::log<phosphor::logging::level::ERR>(
361 "Failed to get Channel Info",
362 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
363 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700364 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000365
366 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
367 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700368 {
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700369 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700370 eventData1, eventData2, eventData3);
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700371 constexpr const uint8_t isSoftwareID = 0x01;
372 if (!(sysgeneratorID & isSoftwareID))
373 {
374 return ipmi::responseInvalidFieldRequest();
375 }
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700376 // Refer to IPMI Spec Table 32: SEL Event Records
377 generatorID = (ctx->channel << 12) // Channel
378 | (0x0 << 10) // Reserved
379 | (0x0 << 8) // 0x0 for sys-soft ID
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700380 | sysgeneratorID;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700381 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000382 else
383 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000384 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
385 eventData2, eventData3);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700386 // Refer to IPMI Spec Table 32: SEL Event Records
387 generatorID = (ctx->channel << 12) // Channel
388 | (0x0 << 10) // Reserved
389 | ((ctx->lun & 0x3) << 8) // Lun
390 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000391 }
392
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700393 if (!p.fullyUnpacked())
394 {
395 return ipmi::responseReqDataLenInvalid();
396 }
397
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000398 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
399 if (evmRev != 0x04)
400 {
401 return ipmi::responseInvalidFieldRequest();
402 }
403 if ((sensorType > 0x2C) && (sensorType < 0xC0))
404 {
405 return ipmi::responseInvalidFieldRequest();
406 }
407
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700408 // Send this request to the Redfish hooks to log it as a Redfish message
409 // instead. There is no need to add it to the SEL, so just return success.
410 intel_oem::ipmi::sel::checkRedfishHooks(
411 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
412 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700413
Vernon Maueryce3b7572022-04-14 13:16:25 -0700414 if (static_cast<uint8_t>(generatorID) == meId && sensorNum == meSensorNum &&
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700415 eventData2 && eventData3)
James Feist7aaf3fe2019-06-25 11:52:11 -0700416 {
417 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
418 }
419
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700420 return ipmi::responseSuccess();
421}
422
James Feist0cd014a2019-04-08 15:04:33 -0700423ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700424 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700425{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700426 std::string connection;
427 std::string path;
428
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000429 if (sensnum == reservedSensorNumber)
430 {
431 return ipmi::responseInvalidFieldRequest();
432 }
433
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700434 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700435 if (status)
436 {
James Feist0cd014a2019-04-08 15:04:33 -0700437 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438 }
439
440 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700441 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700442 {
James Feist0cd014a2019-04-08 15:04:33 -0700443 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700444 }
445 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
446
447 if (sensorObject == sensorMap.end() ||
448 sensorObject->second.find("Value") == sensorObject->second.end())
449 {
James Feist0cd014a2019-04-08 15:04:33 -0700450 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700451 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700452 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700453 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700454
Yong Li1f2eb5e2019-05-23 14:07:17 +0800455 double max = 0;
456 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700457 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700458
459 int16_t mValue = 0;
460 int16_t bValue = 0;
461 int8_t rExp = 0;
462 int8_t bExp = 0;
463 bool bSigned = false;
464
465 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
466 {
James Feist0cd014a2019-04-08 15:04:33 -0700467 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700468 }
469
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500470 uint8_t value = scaleIPMIValueFromDouble(reading, mValue, rExp, bValue,
471 bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700472 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700473 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700474 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800475 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700476 bool notReading = std::isnan(reading);
477
478 if (!notReading)
479 {
480 auto availableObject =
481 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
482 if (availableObject != sensorMap.end())
483 {
484 auto findAvailable = availableObject->second.find("Available");
485 if (findAvailable != availableObject->second.end())
486 {
487 bool* available = std::get_if<bool>(&(findAvailable->second));
488 if (available && !(*available))
489 {
490 notReading = true;
491 }
492 }
493 }
494 }
495
496 if (notReading)
497 {
498 operation |= static_cast<uint8_t>(
499 IPMISensorReadingByte2::readingStateUnavailable);
500 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700501
Josh Lehan06aa21a2020-10-28 21:59:06 -0700502 int byteValue;
503 if (bSigned)
504 {
505 byteValue = static_cast<int>(static_cast<int8_t>(value));
506 }
507 else
508 {
509 byteValue = static_cast<int>(static_cast<uint8_t>(value));
510 }
511
512 // Keep stats on the reading just obtained, even if it is "NaN"
513 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
514 {
515 // This is the first reading, show the coefficients
516 double step = (max - min) / 255.0;
517 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
518 << ": Range min=" << min << " max=" << max
519 << ", step=" << step
520 << ", Coefficients mValue=" << static_cast<int>(mValue)
521 << " rExp=" << static_cast<int>(rExp)
522 << " bValue=" << static_cast<int>(bValue)
523 << " bExp=" << static_cast<int>(bExp)
524 << " bSigned=" << static_cast<int>(bSigned) << "\n";
525 };
526
James Feist0cd014a2019-04-08 15:04:33 -0700527 uint8_t thresholds = 0;
528
529 auto warningObject =
530 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
531 if (warningObject != sensorMap.end())
532 {
533 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
534 auto alarmLow = warningObject->second.find("WarningAlarmLow");
535 if (alarmHigh != warningObject->second.end())
536 {
537 if (std::get<bool>(alarmHigh->second))
538 {
539 thresholds |= static_cast<uint8_t>(
540 IPMISensorReadingByte3::upperNonCritical);
541 }
542 }
543 if (alarmLow != warningObject->second.end())
544 {
545 if (std::get<bool>(alarmLow->second))
546 {
547 thresholds |= static_cast<uint8_t>(
548 IPMISensorReadingByte3::lowerNonCritical);
549 }
550 }
551 }
552
553 auto criticalObject =
554 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
555 if (criticalObject != sensorMap.end())
556 {
557 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
558 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
559 if (alarmHigh != criticalObject->second.end())
560 {
561 if (std::get<bool>(alarmHigh->second))
562 {
563 thresholds |=
564 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
565 }
566 }
567 if (alarmLow != criticalObject->second.end())
568 {
569 if (std::get<bool>(alarmLow->second))
570 {
571 thresholds |=
572 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
573 }
574 }
575 }
576
577 // no discrete as of today so optional byte is never returned
578 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700579}
580
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000581/** @brief implements the Set Sensor threshold command
582 * @param sensorNumber - sensor number
583 * @param lowerNonCriticalThreshMask
584 * @param lowerCriticalThreshMask
585 * @param lowerNonRecovThreshMask
586 * @param upperNonCriticalThreshMask
587 * @param upperCriticalThreshMask
588 * @param upperNonRecovThreshMask
589 * @param reserved
590 * @param lowerNonCritical - lower non-critical threshold
591 * @param lowerCritical - Lower critical threshold
592 * @param lowerNonRecoverable - Lower non recovarable threshold
593 * @param upperNonCritical - Upper non-critical threshold
594 * @param upperCritical - Upper critical
595 * @param upperNonRecoverable - Upper Non-recoverable
596 *
597 * @returns IPMI completion code
598 */
599ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700600 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
601 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
602 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
603 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
604 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
605 uint8_t upperNonCritical, uint8_t upperCritical,
606 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700607{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000608 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700609
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000610 if (sensorNum == reservedSensorNumber)
611 {
612 return ipmi::responseInvalidFieldRequest();
613 }
614
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000615 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000617 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 }
619
620 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 }
625
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000626 // if none of the threshold mask are set, nothing to do
627 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
628 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
629 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000631 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 }
633
634 std::string connection;
635 std::string path;
636
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700637 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638 if (status)
639 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000640 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700641 }
642 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700643 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000645 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700646 }
647
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700648 double max = 0;
649 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700650 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700651
652 int16_t mValue = 0;
653 int16_t bValue = 0;
654 int8_t rExp = 0;
655 int8_t bExp = 0;
656 bool bSigned = false;
657
658 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
659 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000660 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661 }
662
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700663 // store a vector of property name, value to set, and interface
664 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
665
666 // define the indexes of the tuple
667 constexpr uint8_t propertyName = 0;
668 constexpr uint8_t thresholdValue = 1;
669 constexpr uint8_t interface = 2;
670 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000671 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700672 {
673 auto findThreshold =
674 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
675 if (findThreshold == sensorMap.end())
676 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000677 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700678 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000679 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680 {
681 auto findLower = findThreshold->second.find("CriticalLow");
682 if (findLower == findThreshold->second.end())
683 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000684 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700685 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000686 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700687 findThreshold->first);
688 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000689 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700690 {
691 auto findUpper = findThreshold->second.find("CriticalHigh");
692 if (findUpper == findThreshold->second.end())
693 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000694 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700695 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000696 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700697 findThreshold->first);
698 }
699 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000700 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700701 {
702 auto findThreshold =
703 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
704 if (findThreshold == sensorMap.end())
705 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000706 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700707 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000708 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700709 {
710 auto findLower = findThreshold->second.find("WarningLow");
711 if (findLower == findThreshold->second.end())
712 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000713 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700714 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000715 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700716 findThreshold->first);
717 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000718 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700719 {
720 auto findUpper = findThreshold->second.find("WarningHigh");
721 if (findUpper == findThreshold->second.end())
722 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000723 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700724 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000725 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700726 findThreshold->first);
727 }
728 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700729 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700730 {
731 // from section 36.3 in the IPMI Spec, assume all linear
732 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800733 (bValue * std::pow(10.0, bExp))) *
734 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700735 setDbusProperty(
736 *getSdBus(), connection, path, std::get<interface>(property),
737 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700738 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000739 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700740}
741
James Feistfcd2d3a2020-05-28 10:38:15 -0700742IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700743{
James Feist902c4c52019-04-16 14:51:31 -0700744 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700745 auto warningInterface =
746 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
747 auto criticalInterface =
748 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
749
750 if ((warningInterface != sensorMap.end()) ||
751 (criticalInterface != sensorMap.end()))
752 {
753 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
754
755 if (sensorPair == sensorMap.end())
756 {
757 // should not have been able to find a sensor not implementing
758 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700759 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700760 }
761
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800762 double max = 0;
763 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700764 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700765
766 int16_t mValue = 0;
767 int16_t bValue = 0;
768 int8_t rExp = 0;
769 int8_t bExp = 0;
770 bool bSigned = false;
771
772 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
773 {
James Feist902c4c52019-04-16 14:51:31 -0700774 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700775 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700776 if (warningInterface != sensorMap.end())
777 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700778 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700779
780 auto warningHigh = warningMap.find("WarningHigh");
781 auto warningLow = warningMap.find("WarningLow");
782
783 if (warningHigh != warningMap.end())
784 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500785 double value = std::visit(VariantToDoubleVisitor(),
786 warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700787 if (std::isfinite(value))
788 {
789 resp.warningHigh = scaleIPMIValueFromDouble(
790 value, mValue, rExp, bValue, bExp, bSigned);
791 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700792 }
793 if (warningLow != warningMap.end())
794 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500795 double value = std::visit(VariantToDoubleVisitor(),
796 warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700797 if (std::isfinite(value))
798 {
799 resp.warningLow = scaleIPMIValueFromDouble(
800 value, mValue, rExp, bValue, bExp, bSigned);
801 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700802 }
803 }
804 if (criticalInterface != sensorMap.end())
805 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700806 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700807
808 auto criticalHigh = criticalMap.find("CriticalHigh");
809 auto criticalLow = criticalMap.find("CriticalLow");
810
811 if (criticalHigh != criticalMap.end())
812 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500813 double value = std::visit(VariantToDoubleVisitor(),
814 criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700815 if (std::isfinite(value))
816 {
817 resp.criticalHigh = scaleIPMIValueFromDouble(
818 value, mValue, rExp, bValue, bExp, bSigned);
819 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700820 }
821 if (criticalLow != criticalMap.end())
822 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500823 double value = std::visit(VariantToDoubleVisitor(),
824 criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700825 if (std::isfinite(value))
826 {
827 resp.criticalLow = scaleIPMIValueFromDouble(
828 value, mValue, rExp, bValue, bExp, bSigned);
829 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700830 }
831 }
832 }
James Feist902c4c52019-04-16 14:51:31 -0700833 return resp;
834}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700835
James Feist902c4c52019-04-16 14:51:31 -0700836ipmi::RspType<uint8_t, // readable
837 uint8_t, // lowerNCrit
838 uint8_t, // lowerCrit
839 uint8_t, // lowerNrecoverable
840 uint8_t, // upperNC
841 uint8_t, // upperCrit
842 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700843 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700844{
845 std::string connection;
846 std::string path;
847
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000848 if (sensorNumber == reservedSensorNumber)
849 {
850 return ipmi::responseInvalidFieldRequest();
851 }
852
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700853 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700854 if (status)
855 {
856 return ipmi::response(status);
857 }
858
859 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700860 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700861 {
862 return ipmi::responseResponseError();
863 }
864
865 IPMIThresholds thresholdData;
866 try
867 {
868 thresholdData = getIPMIThresholds(sensorMap);
869 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500870 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700871 {
872 return ipmi::responseResponseError();
873 }
874
875 uint8_t readable = 0;
876 uint8_t lowerNC = 0;
877 uint8_t lowerCritical = 0;
878 uint8_t lowerNonRecoverable = 0;
879 uint8_t upperNC = 0;
880 uint8_t upperCritical = 0;
881 uint8_t upperNonRecoverable = 0;
882
883 if (thresholdData.warningHigh)
884 {
885 readable |=
886 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
887 upperNC = *thresholdData.warningHigh;
888 }
889 if (thresholdData.warningLow)
890 {
891 readable |=
892 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
893 lowerNC = *thresholdData.warningLow;
894 }
895
896 if (thresholdData.criticalHigh)
897 {
898 readable |=
899 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
900 upperCritical = *thresholdData.criticalHigh;
901 }
902 if (thresholdData.criticalLow)
903 {
904 readable |=
905 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
906 lowerCritical = *thresholdData.criticalLow;
907 }
908
909 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
910 lowerNonRecoverable, upperNC, upperCritical,
911 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700912}
913
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000914/** @brief implements the get Sensor event enable command
915 * @param sensorNumber - sensor number
916 *
917 * @returns IPMI completion code plus response data
918 * - enabled - Sensor Event messages
919 * - assertionEnabledLsb - Assertion event messages
920 * - assertionEnabledMsb - Assertion event messages
921 * - deassertionEnabledLsb - Deassertion event messages
922 * - deassertionEnabledMsb - Deassertion event messages
923 */
924
925ipmi::RspType<uint8_t, // enabled
926 uint8_t, // assertionEnabledLsb
927 uint8_t, // assertionEnabledMsb
928 uint8_t, // deassertionEnabledLsb
929 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700930 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700931{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700932 std::string connection;
933 std::string path;
934
Patrick Venturea41714c2019-09-25 16:59:41 -0700935 uint8_t enabled = 0;
936 uint8_t assertionEnabledLsb = 0;
937 uint8_t assertionEnabledMsb = 0;
938 uint8_t deassertionEnabledLsb = 0;
939 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000940
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000941 if (sensorNum == reservedSensorNumber)
942 {
943 return ipmi::responseInvalidFieldRequest();
944 }
945
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700946 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700947 if (status)
948 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000949 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700950 }
951
952 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700953 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700954 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000955 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700956 }
957
958 auto warningInterface =
959 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
960 auto criticalInterface =
961 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700962 if ((warningInterface != sensorMap.end()) ||
963 (criticalInterface != sensorMap.end()))
964 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000965 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700966 IPMISensorEventEnableByte2::sensorScanningEnable);
967 if (warningInterface != sensorMap.end())
968 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700969 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700970
971 auto warningHigh = warningMap.find("WarningHigh");
972 auto warningLow = warningMap.find("WarningLow");
973 if (warningHigh != warningMap.end())
974 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500975 double value = std::visit(VariantToDoubleVisitor(),
976 warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700977 if (std::isfinite(value))
978 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500979 assertionEnabledLsb |= static_cast<uint8_t>(
980 IPMISensorEventEnableThresholds::
981 upperNonCriticalGoingHigh);
982 deassertionEnabledLsb |= static_cast<uint8_t>(
983 IPMISensorEventEnableThresholds::
984 upperNonCriticalGoingLow);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700985 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700986 }
987 if (warningLow != warningMap.end())
988 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500989 double value = std::visit(VariantToDoubleVisitor(),
990 warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700991 if (std::isfinite(value))
992 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500993 assertionEnabledLsb |= static_cast<uint8_t>(
994 IPMISensorEventEnableThresholds::
995 lowerNonCriticalGoingLow);
996 deassertionEnabledLsb |= static_cast<uint8_t>(
997 IPMISensorEventEnableThresholds::
998 lowerNonCriticalGoingHigh);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700999 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001000 }
1001 }
1002 if (criticalInterface != sensorMap.end())
1003 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001004 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001005
1006 auto criticalHigh = criticalMap.find("CriticalHigh");
1007 auto criticalLow = criticalMap.find("CriticalLow");
1008
1009 if (criticalHigh != criticalMap.end())
1010 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001011 double value = std::visit(VariantToDoubleVisitor(),
1012 criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001013 if (std::isfinite(value))
1014 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001015 assertionEnabledMsb |= static_cast<uint8_t>(
1016 IPMISensorEventEnableThresholds::
1017 upperCriticalGoingHigh);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001018 deassertionEnabledMsb |= static_cast<uint8_t>(
1019 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1020 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001021 }
1022 if (criticalLow != criticalMap.end())
1023 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001024 double value = std::visit(VariantToDoubleVisitor(),
1025 criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001026 if (std::isfinite(value))
1027 {
1028 assertionEnabledLsb |= static_cast<uint8_t>(
1029 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001030 deassertionEnabledLsb |= static_cast<uint8_t>(
1031 IPMISensorEventEnableThresholds::
1032 lowerCriticalGoingHigh);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001033 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001034 }
1035 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001036 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001037
1038 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1039 assertionEnabledMsb, deassertionEnabledLsb,
1040 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001041}
1042
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001043/** @brief implements the get Sensor event status command
1044 * @param sensorNumber - sensor number, FFh = reserved
1045 *
1046 * @returns IPMI completion code plus response data
1047 * - sensorEventStatus - Sensor Event messages state
1048 * - assertions - Assertion event messages
1049 * - deassertions - Deassertion event messages
1050 */
1051ipmi::RspType<uint8_t, // sensorEventStatus
1052 std::bitset<16>, // assertions
1053 std::bitset<16> // deassertion
1054 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001055 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001056{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001057 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001058 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001059 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001060 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001061
1062 std::string connection;
1063 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001064 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001065 if (status)
1066 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001067 phosphor::logging::log<phosphor::logging::level::ERR>(
1068 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1069 phosphor::logging::entry("SENSOR=%d", sensorNum));
1070 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071 }
1072
1073 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001074 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001076 phosphor::logging::log<phosphor::logging::level::ERR>(
1077 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1078 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1079 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001081 auto warningInterface =
1082 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1083 auto criticalInterface =
1084 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1085
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001086 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001087 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1088
James Feist392786a2019-03-19 13:36:10 -07001089 std::optional<bool> criticalDeassertHigh =
1090 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1091 std::optional<bool> criticalDeassertLow =
1092 thresholdDeassertMap[path]["CriticalAlarmLow"];
1093 std::optional<bool> warningDeassertHigh =
1094 thresholdDeassertMap[path]["WarningAlarmHigh"];
1095 std::optional<bool> warningDeassertLow =
1096 thresholdDeassertMap[path]["WarningAlarmLow"];
1097
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001098 std::bitset<16> assertions = 0;
1099 std::bitset<16> deassertions = 0;
1100
James Feist392786a2019-03-19 13:36:10 -07001101 if (criticalDeassertHigh && !*criticalDeassertHigh)
1102 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001103 deassertions.set(static_cast<size_t>(
1104 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001105 }
1106 if (criticalDeassertLow && !*criticalDeassertLow)
1107 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001108 deassertions.set(static_cast<size_t>(
1109 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001110 }
1111 if (warningDeassertHigh && !*warningDeassertHigh)
1112 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001113 deassertions.set(static_cast<size_t>(
1114 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001115 }
1116 if (warningDeassertLow && !*warningDeassertLow)
1117 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001118 deassertions.set(static_cast<size_t>(
1119 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001120 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001121 if ((warningInterface != sensorMap.end()) ||
1122 (criticalInterface != sensorMap.end()))
1123 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001124 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001125 IPMISensorEventEnableByte2::eventMessagesEnable);
1126 if (warningInterface != sensorMap.end())
1127 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001128 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001129
1130 auto warningHigh = warningMap.find("WarningAlarmHigh");
1131 auto warningLow = warningMap.find("WarningAlarmLow");
1132 auto warningHighAlarm = false;
1133 auto warningLowAlarm = false;
1134
1135 if (warningHigh != warningMap.end())
1136 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001137 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001138 }
1139 if (warningLow != warningMap.end())
1140 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001141 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142 }
1143 if (warningHighAlarm)
1144 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001145 assertions.set(
1146 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1147 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148 }
1149 if (warningLowAlarm)
1150 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001151 assertions.set(
1152 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1153 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 }
1155 }
1156 if (criticalInterface != sensorMap.end())
1157 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001158 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159
1160 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1161 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1162 auto criticalHighAlarm = false;
1163 auto criticalLowAlarm = false;
1164
1165 if (criticalHigh != criticalMap.end())
1166 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001167 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 }
1169 if (criticalLow != criticalMap.end())
1170 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001171 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 }
1173 if (criticalHighAlarm)
1174 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001175 assertions.set(
1176 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1177 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 }
1179 if (criticalLowAlarm)
1180 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001181 assertions.set(static_cast<size_t>(
1182 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001183 }
1184 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185 }
1186
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001187 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001188}
1189
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001190static inline uint16_t getNumberOfSensors(void)
1191{
1192 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1193 : sensorTree.size();
1194}
1195
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001196static int getSensorDataRecord(ipmi::Context::ptr ctx,
1197 std::vector<uint8_t>& recordData,
1198 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001199{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001200 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001201 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1202 if (ret != ipmi::ccSuccess)
1203 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001204 phosphor::logging::log<phosphor::logging::level::ERR>(
1205 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001206 return GENERAL_ERROR;
1207 }
1208
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001209 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001210 ipmi::storage::type12Count +
1211 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001212 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001213 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001214 recordID = lastRecord;
1215 }
1216 if (recordID > lastRecord)
1217 {
1218 phosphor::logging::log<phosphor::logging::level::ERR>(
1219 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001220 return GENERAL_ERROR;
1221 }
1222
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001223 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001224 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001225 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001226 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001227
1228 if (fruIndex >= type12End)
1229 {
1230 // NM discovery SDR
1231 size_t nmDiscoveryIndex = fruIndex - type12End;
1232 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1233 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001234 phosphor::logging::log<phosphor::logging::level::ERR>(
1235 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001236 return GENERAL_ERROR;
1237 }
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001238 recordData = ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex,
1239 recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001240 }
1241 else if (fruIndex >= fruCount)
1242 {
1243 // handle type 12 hardcoded records
1244 size_t type12Index = fruIndex - fruCount;
1245 if (type12Index >= ipmi::storage::type12Count)
1246 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001247 phosphor::logging::log<phosphor::logging::level::ERR>(
1248 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001249 return GENERAL_ERROR;
1250 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001251 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001252 }
1253 else
1254 {
1255 // handle fru records
1256 get_sdr::SensorDataFruRecord data;
1257 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1258 if (ret != IPMI_CC_OK)
1259 {
1260 return GENERAL_ERROR;
1261 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001262 data.header.record_id_msb = recordID >> 8;
1263 data.header.record_id_lsb = recordID & 0xFF;
1264 recordData.insert(recordData.end(), (uint8_t*)&data,
1265 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001266 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001267
1268 return 0;
1269 }
1270
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001271 // Perform a incremental scan of the SDR Record ID's and translate the
1272 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1273 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1274 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1275 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001276 std::string connection;
1277 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001278 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001279 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001280 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001281 // LUN 0 has one reserved sensor number. Compensate here by adding one
1282 // to the record ID
1283 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001284 ctx->lun = 1;
1285 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001286 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001287 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001288 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1289 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1290 // rules governing its use.
1291 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001292 ctx->lun = 3;
1293 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001294
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001295 auto status = getSensorConnection(
1296 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001297 if (status)
1298 {
1299 phosphor::logging::log<phosphor::logging::level::ERR>(
1300 "getSensorDataRecord: getSensorConnection error");
1301 return GENERAL_ERROR;
1302 }
1303 SensorMap sensorMap;
1304 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1305 sensorMapUpdatePeriod))
1306 {
1307 phosphor::logging::log<phosphor::logging::level::ERR>(
1308 "getSensorDataRecord: getSensorMap error");
1309 return GENERAL_ERROR;
1310 }
1311 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001312 // Return an error on LUN 2 assingments, and any sensor number beyond the
1313 // range of LUN 3
1314 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1315 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001316 {
1317 phosphor::logging::log<phosphor::logging::level::ERR>(
1318 "getSensorDataRecord: invalidSensorNumber");
1319 return GENERAL_ERROR;
1320 }
1321 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1322 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1323
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001324 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1325 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001326 {
1327 phosphor::logging::log<phosphor::logging::level::ERR>(
1328 "getSensorDataRecord: sensor record mismatch");
1329 return GENERAL_ERROR;
1330 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001331 get_sdr::SensorDataFullRecord record = {0};
1332
1333 get_sdr::header::set_record_id(
1334 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1335
1336 record.header.sdr_version = ipmiSdrVersion;
1337 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1338 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1339 sizeof(get_sdr::SensorDataRecordHeader);
1340 record.key.owner_id = 0x20;
1341 record.key.owner_lun = lun;
1342 record.key.sensor_number = sensornumber;
1343
1344 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1345 record.body.sensor_type = getSensorTypeFromPath(path);
1346 std::string type = getSensorTypeStringFromPath(path);
Jason M. Bills039c3492022-09-09 14:27:28 -07001347 for (const auto& [unitsType, units] : sensorUnits)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001348 {
Jason M. Bills039c3492022-09-09 14:27:28 -07001349 if (type == unitsType)
1350 {
1351 record.body.sensor_units_2_base = static_cast<uint8_t>(units);
1352 }
1353 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001354
1355 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1356
1357 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1358 if (sensorObject == sensorMap.end())
1359 {
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "getSensorDataRecord: sensorObject error");
1362 return GENERAL_ERROR;
1363 }
1364
1365 uint8_t entityId = 0;
1366 uint8_t entityInstance = 0x01;
1367
1368 // follow the association chain to get the parent board's entityid and
1369 // entityInstance
1370 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1371
1372 record.body.entity_id = entityId;
1373 record.body.entity_instance = entityInstance;
1374
1375 auto maxObject = sensorObject->second.find("MaxValue");
1376 auto minObject = sensorObject->second.find("MinValue");
1377
1378 // If min and/or max are left unpopulated,
1379 // then default to what a signed byte would be, namely (-128,127) range.
1380 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1381 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1382 if (maxObject != sensorObject->second.end())
1383 {
1384 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1385 }
1386
1387 if (minObject != sensorObject->second.end())
1388 {
1389 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1390 }
1391
1392 int16_t mValue = 0;
1393 int8_t rExp = 0;
1394 int16_t bValue = 0;
1395 int8_t bExp = 0;
1396 bool bSigned = false;
1397
1398 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1399 {
1400 phosphor::logging::log<phosphor::logging::level::ERR>(
1401 "getSensorDataRecord: getSensorAttributes error");
1402 return GENERAL_ERROR;
1403 }
1404
1405 // The record.body is a struct SensorDataFullRecordBody
1406 // from sensorhandler.hpp in phosphor-ipmi-host.
1407 // The meaning of these bits appears to come from
1408 // table 43.1 of the IPMI spec.
1409 // The above 5 sensor attributes are stuffed in as follows:
1410 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1411 // Byte 22-24 are for other purposes
1412 // Byte 25 = MMMMMMMM = LSB of M
1413 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1414 // Byte 27 = BBBBBBBB = LSB of B
1415 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1416 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1417 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1418
1419 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1420 record.body.m_lsb = mValue & 0xFF;
1421
1422 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1423 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1424
1425 // move the smallest bit of the MSB into place (bit 9)
1426 // the MSbs are bits 7:8 in m_msb_and_tolerance
1427 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1428
1429 record.body.b_lsb = bValue & 0xFF;
1430
1431 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1432 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1433
1434 // move the smallest bit of the MSB into place (bit 9)
1435 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1436 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1437
1438 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1439 uint8_t rExpBits = rExp & 0x07;
1440
1441 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1442 uint8_t bExpBits = bExp & 0x07;
1443
1444 // move rExp and bExp into place
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001445 record.body.r_b_exponents = (rExpSign << 7) | (rExpBits << 4) |
1446 (bExpSign << 3) | bExpBits;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001447
1448 // Set the analog reading byte interpretation accordingly
1449 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1450
1451 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1452 // These seem redundant, but derivable from the above 5 attributes
1453 // Original comment said "todo fill out rest of units"
1454
1455 // populate sensor name from path
1456 std::string name;
1457 size_t nameStart = path.rfind("/");
1458 if (nameStart != std::string::npos)
1459 {
1460 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1461 }
1462
1463 std::replace(name.begin(), name.end(), '_', ' ');
1464 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1465 {
1466 // try to not truncate by replacing common words
1467 constexpr std::array<std::pair<const char*, const char*>, 2>
1468 replaceWords = {std::make_pair("Output", "Out"),
1469 std::make_pair("Input", "In")};
1470 for (const auto& [find, replace] : replaceWords)
1471 {
1472 boost::replace_all(name, find, replace);
1473 }
1474
1475 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1476 }
Paul Fertser97221512022-08-18 12:36:41 +00001477 get_sdr::body::set_id_strlen(name.size(), &record.body);
1478 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001479 std::strncpy(record.body.id_string, name.c_str(),
1480 sizeof(record.body.id_string));
1481
Josh Lehan06aa21a2020-10-28 21:59:06 -07001482 // Remember the sensor name, as determined for this sensor number
1483 details::sdrStatsTable.updateName(sensornumber, name);
1484
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001485 IPMIThresholds thresholdData;
1486 try
1487 {
1488 thresholdData = getIPMIThresholds(sensorMap);
1489 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001490 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001491 {
1492 phosphor::logging::log<phosphor::logging::level::ERR>(
1493 "getSensorDataRecord: getIPMIThresholds error");
1494 return GENERAL_ERROR;
1495 }
1496
1497 if (thresholdData.criticalHigh)
1498 {
1499 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1500 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1501 IPMISensorEventEnableThresholds::criticalThreshold);
1502 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1503 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1504 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1505 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1506 record.body.discrete_reading_setting_mask[0] |=
1507 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1508 }
1509 if (thresholdData.warningHigh)
1510 {
1511 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1512 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1513 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1514 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1515 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1516 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1517 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1518 record.body.discrete_reading_setting_mask[0] |=
1519 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1520 }
1521 if (thresholdData.criticalLow)
1522 {
1523 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1524 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1525 IPMISensorEventEnableThresholds::criticalThreshold);
1526 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1527 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1528 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1529 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1530 record.body.discrete_reading_setting_mask[0] |=
1531 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1532 }
1533 if (thresholdData.warningLow)
1534 {
1535 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1536 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1537 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1538 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1539 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1540 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1541 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1542 record.body.discrete_reading_setting_mask[0] |=
1543 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1544 }
1545
1546 // everything that is readable is setable
1547 record.body.discrete_reading_setting_mask[1] =
1548 record.body.discrete_reading_setting_mask[0];
1549 recordData.insert(recordData.end(), (uint8_t*)&record,
1550 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001551 return 0;
1552}
1553
1554/** @brief implements the get SDR Info command
1555 * @param count - Operation
1556 *
1557 * @returns IPMI completion code plus response data
1558 * - sdrCount - sensor/SDR count
1559 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1560 */
1561static ipmi::RspType<uint8_t, // respcount
1562 uint8_t, // dynamic population flags
1563 uint32_t // last time a sensor was added
1564 >
1565 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1566 std::optional<uint8_t> count)
1567{
1568 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001569 uint16_t recordID = 0;
1570 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001571 // Sensors are dynamically allocated, and there is at least one LUN
1572 uint8_t lunsAndDynamicPopulation = 0x80;
1573 constexpr uint8_t getSdrCount = 0x01;
1574 constexpr uint8_t getSensorCount = 0x00;
1575
1576 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1577 {
1578 return ipmi::responseResponseError();
1579 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001580 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001581 if (count.value_or(0) == getSdrCount)
1582 {
1583 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001584 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001585 {
1586 get_sdr::SensorDataRecordHeader* hdr =
1587 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001588 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001589 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1590 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001591 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001592 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001593 record.data());
1594 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001595 {
1596 sdrCount++;
1597 }
1598 }
1599 }
1600 }
1601 else if (count.value_or(0) == getSensorCount)
1602 {
1603 // Return the number of sensors attached to the LUN
1604 if ((ctx->lun == 0) && (numSensors > 0))
1605 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001606 sdrCount = (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN
1607 : numSensors;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001608 }
1609 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1610 {
1611 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1612 ? maxSensorsPerLUN
1613 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1614 }
1615 else if (ctx->lun == 3)
1616 {
1617 if (numSensors <= maxIPMISensors)
1618 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001619 sdrCount = (numSensors - (2 * maxSensorsPerLUN)) &
1620 maxSensorsPerLUN;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001621 }
1622 else
1623 {
1624 // error
1625 throw std::out_of_range(
1626 "Maximum number of IPMI sensors exceeded.");
1627 }
1628 }
1629 }
1630 else
1631 {
1632 return ipmi::responseInvalidFieldRequest();
1633 }
1634
1635 // Get Sensor count. This returns the number of sensors
1636 if (numSensors > 0)
1637 {
1638 lunsAndDynamicPopulation |= 1;
1639 }
1640 if (numSensors > maxSensorsPerLUN)
1641 {
1642 lunsAndDynamicPopulation |= 2;
1643 }
1644 if (numSensors >= (maxSensorsPerLUN * 2))
1645 {
1646 lunsAndDynamicPopulation |= 8;
1647 }
1648 if (numSensors > maxIPMISensors)
1649 {
1650 // error
1651 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1652 }
1653
1654 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1655 sdrLastAdd);
1656}
1657
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001658/* end sensor commands */
1659
1660/* storage commands */
1661
James Feist74c50c62019-08-14 14:18:41 -07001662ipmi::RspType<uint8_t, // sdr version
1663 uint16_t, // record count
1664 uint16_t, // free space
1665 uint32_t, // most recent addition
1666 uint32_t, // most recent erase
1667 uint8_t // operationSupport
1668 >
James Feist25690252019-12-23 12:25:49 -08001669 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001670{
James Feist74c50c62019-08-14 14:18:41 -07001671 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001672 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001673 {
James Feist74c50c62019-08-14 14:18:41 -07001674 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001675 }
1676
James Feist74c50c62019-08-14 14:18:41 -07001677 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001678 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001679 if (ret != ipmi::ccSuccess)
1680 {
1681 return ipmi::response(ret);
1682 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001683
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301684 uint16_t recordCount = getNumberOfSensors() + fruCount +
1685 ipmi::storage::type12Count +
1686 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001687
James Feist74c50c62019-08-14 14:18:41 -07001688 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001689 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001690
1691 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001692 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001693 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001695 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1696 unspecifiedFreeSpace, sdrLastAdd,
1697 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001698}
1699
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001700/** @brief implements the get SDR allocation info command
1701 *
1702 * @returns IPMI completion code plus response data
1703 * - allocUnits - Number of possible allocation units
1704 * - allocUnitSize - Allocation unit size in bytes.
1705 * - allocUnitFree - Number of free allocation units
1706 * - allocUnitLargestFree - Largest free block in allocation units
1707 * - maxRecordSize - Maximum record size in allocation units.
1708 */
1709ipmi::RspType<uint16_t, // allocUnits
1710 uint16_t, // allocUnitSize
1711 uint16_t, // allocUnitFree
1712 uint16_t, // allocUnitLargestFree
1713 uint8_t // maxRecordSize
1714 >
1715 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001716{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001717 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001718 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001719
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001720 constexpr uint16_t allocUnitFree = 0;
1721 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001722 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001723 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001724
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001725 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1726 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001727}
1728
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001729/** @brief implements the reserve SDR command
1730 * @returns IPMI completion code plus response data
1731 * - sdrReservationID
1732 */
1733ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001734{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001735 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001736 if (sdrReservationID == 0)
1737 {
1738 sdrReservationID++;
1739 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001740
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001741 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001742}
1743
James Feistb49a98a2019-04-16 13:48:09 -07001744ipmi::RspType<uint16_t, // next record ID
1745 std::vector<uint8_t> // payload
1746 >
James Feist25690252019-12-23 12:25:49 -08001747 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1748 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001749{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001750 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001751 // reservation required for partial reads with non zero offset into
1752 // record
James Feistb49a98a2019-04-16 13:48:09 -07001753 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001754 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001755 phosphor::logging::log<phosphor::logging::level::ERR>(
1756 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001757 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001758 }
James Feist25690252019-12-23 12:25:49 -08001759 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001760 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001761 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001762 phosphor::logging::log<phosphor::logging::level::ERR>(
1763 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001764 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001765 }
1766
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001767 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001768 ipmi::storage::type12Count +
1769 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001770 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1771
1772 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001773 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001774 phosphor::logging::log<phosphor::logging::level::ERR>(
1775 "ipmiStorageGetSDR: getSensorSubtree error");
1776 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001777 }
1778
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001779 std::vector<uint8_t> record;
1780 if (getSensorDataRecord(ctx, record, recordID))
1781 {
1782 phosphor::logging::log<phosphor::logging::level::ERR>(
1783 "ipmiStorageGetSDR: fail to get SDR");
1784 return ipmi::responseInvalidFieldRequest();
1785 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001786 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001787 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001788 if (!hdr)
1789 {
1790 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001791 "ipmiStorageGetSDR: record header is null");
1792 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001793 }
1794
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001795 size_t sdrLength = sizeof(get_sdr::SensorDataRecordHeader) +
1796 hdr->record_length;
Jason M. Bills84c203d2023-07-21 09:55:41 -07001797 if (offset >= sdrLength)
1798 {
1799 phosphor::logging::log<phosphor::logging::level::ERR>(
1800 "ipmiStorageGetSDR: offset is outside the record");
1801 return ipmi::responseParmOutOfRange();
1802 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001803 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001804 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001805 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001806 }
1807
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001808 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001809 if (!respStart)
1810 {
1811 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001812 "ipmiStorageGetSDR: record is null");
1813 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001814 }
James Feistb49a98a2019-04-16 13:48:09 -07001815 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001816
James Feistb49a98a2019-04-16 13:48:09 -07001817 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001818}
1819/* end storage commands */
1820
1821void registerSensorFunctions()
1822{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001823 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001824 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1825 ipmi::sensor_event::cmdPlatformEvent,
1826 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001827
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001828 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001829 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1830 ipmi::sensor_event::cmdGetSensorReading,
1831 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001832
1833 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001834 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1835 ipmi::sensor_event::cmdGetSensorThreshold,
1836 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001837
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001838 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001839 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1840 ipmi::sensor_event::cmdSetSensorThreshold,
1841 ipmi::Privilege::Operator,
1842 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001843
1844 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001845 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1846 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001847 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001848
1849 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001850 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1851 ipmi::sensor_event::cmdGetSensorEventStatus,
1852 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001853
1854 // register all storage commands for both Sensor and Storage command
1855 // versions
1856
1857 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001858 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1859 ipmi::storage::cmdGetSdrRepositoryInfo,
1860 ipmi::Privilege::User,
1861 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001862
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001863 // <Get Device SDR Info>
1864 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1865 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1866 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1867
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001868 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001869 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1870 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1871 ipmi::Privilege::User,
1872 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001873
1874 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001875 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1876 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001877 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001878
Vernon Mauery98bbf692019-09-16 11:14:59 -07001879 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1880 ipmi::storage::cmdReserveSdrRepository,
1881 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001882
1883 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001884 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1885 ipmi::sensor_event::cmdGetDeviceSdr,
1886 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001887
Vernon Mauery98bbf692019-09-16 11:14:59 -07001888 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1889 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1890 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001891}
1892} // namespace ipmi