blob: 0cb4c043465e7d6570a424fd7d962440ca33b15b [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;
64static constexpr int GENERAL_ERROR = -1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070065
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053066SensorSubTree sensorTree;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070067
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070068static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
69
Jason M. Bills17add592018-11-12 14:30:12 -080070// Specify the comparison required to sort and find char* map objects
71struct CmpStr
72{
James Feistfcd2d3a2020-05-28 10:38:15 -070073 bool operator()(const char* a, const char* b) const
Jason M. Bills17add592018-11-12 14:30:12 -080074 {
75 return std::strcmp(a, b) < 0;
76 }
77};
James Feistfcd2d3a2020-05-28 10:38:15 -070078const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
Jason M. Bills17add592018-11-12 14:30:12 -080079 sensorUnits{{{"temperature", SensorUnits::degreesC},
80 {"voltage", SensorUnits::volts},
81 {"current", SensorUnits::amps},
82 {"fan_tach", SensorUnits::rpm},
83 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070084
85void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070086
87static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070088 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070089 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
90 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -070091 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070092 sensorTree.clear();
93 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
94 std::chrono::system_clock::now().time_since_epoch())
95 .count();
96 });
97
98static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070099 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700100 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
101 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700102 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700103 sensorTree.clear();
104 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
105 std::chrono::system_clock::now().time_since_epoch())
106 .count();
107 });
108
James Feist392786a2019-03-19 13:36:10 -0700109// this keeps track of deassertions for sensor event status command. A
110// deasertion can only happen if an assertion was seen first.
111static boost::container::flat_map<
112 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
113 thresholdDeassertMap;
114
115static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700116 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700117 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
118 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700119 [](sdbusplus::message::message& m) {
James Feist392786a2019-03-19 13:36:10 -0700120 boost::container::flat_map<std::string, std::variant<bool, double>>
121 values;
122 m.read(std::string(), values);
123
124 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700125 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700126 return pair.first.find("Alarm") != std::string::npos;
127 });
128 if (findAssert != values.end())
129 {
130 auto ptr = std::get_if<bool>(&(findAssert->second));
131 if (ptr == nullptr)
132 {
133 phosphor::logging::log<phosphor::logging::level::ERR>(
134 "thresholdChanged: Assert non bool");
135 return;
136 }
137 if (*ptr)
138 {
139 phosphor::logging::log<phosphor::logging::level::INFO>(
140 "thresholdChanged: Assert",
141 phosphor::logging::entry("SENSOR=%s", m.get_path()));
142 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
143 }
144 else
145 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700146 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700147 thresholdDeassertMap[m.get_path()][findAssert->first];
148 if (value)
149 {
150 phosphor::logging::log<phosphor::logging::level::INFO>(
151 "thresholdChanged: deassert",
152 phosphor::logging::entry("SENSOR=%s", m.get_path()));
153 value = *ptr;
154 }
155 }
156 }
157 });
158
James Feistfcd2d3a2020-05-28 10:38:15 -0700159static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
160 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700161{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700162 max = 127;
163 min = -128;
164
James Feistaecaef72019-04-26 10:30:32 -0700165 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
166 auto critical =
167 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
168 auto warning =
169 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
170
171 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700172 {
James Feistaecaef72019-04-26 10:30:32 -0700173 auto maxMap = sensorObject->second.find("MaxValue");
174 auto minMap = sensorObject->second.find("MinValue");
175
176 if (maxMap != sensorObject->second.end())
177 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700178 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700179 }
180 if (minMap != sensorObject->second.end())
181 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700182 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700183 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700184 }
James Feistaecaef72019-04-26 10:30:32 -0700185 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700186 {
James Feistaecaef72019-04-26 10:30:32 -0700187 auto lower = critical->second.find("CriticalLow");
188 auto upper = critical->second.find("CriticalHigh");
189 if (lower != critical->second.end())
190 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700191 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700192 min = std::min(value, min);
193 }
194 if (upper != critical->second.end())
195 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700196 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700197 max = std::max(value, max);
198 }
199 }
200 if (warning != sensorMap.end())
201 {
202
203 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);
James Feistaecaef72019-04-26 10:30:32 -0700208 min = std::min(value, min);
209 }
210 if (upper != warning->second.end())
211 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700212 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700213 max = std::max(value, max);
214 }
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>(
242 yield, ec, sensorConnection.c_str(), "/",
243 "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();
325 auto setHealth =
326 dbus->new_method_call(meHealth::busname, meHealth::path,
327 meHealth::interface, meHealth::method);
328 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
329 try
330 {
331 dbus->call(setHealth);
332 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700333 catch (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
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700347 uint8_t generatorID = 0;
348 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;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000355 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700356
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000357 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700358 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000359 phosphor::logging::log<phosphor::logging::level::ERR>(
360 "Failed to get Channel Info",
361 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
362 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700363 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000364
365 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
366 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700367 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000368
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700369 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
370 eventData1, eventData2, eventData3);
371 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000372 else
373 {
374
375 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
376 eventData2, eventData3);
377 generatorID = ctx->rqSA;
378 }
379
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700380 if (!p.fullyUnpacked())
381 {
382 return ipmi::responseReqDataLenInvalid();
383 }
384
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000385 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
386 if (evmRev != 0x04)
387 {
388 return ipmi::responseInvalidFieldRequest();
389 }
390 if ((sensorType > 0x2C) && (sensorType < 0xC0))
391 {
392 return ipmi::responseInvalidFieldRequest();
393 }
394
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700395 // Send this request to the Redfish hooks to log it as a Redfish message
396 // instead. There is no need to add it to the SEL, so just return success.
397 intel_oem::ipmi::sel::checkRedfishHooks(
398 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
399 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700400
James Feist7aaf3fe2019-06-25 11:52:11 -0700401 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
402 eventData3)
403 {
404 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
405 }
406
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700407 return ipmi::responseSuccess();
408}
409
James Feist0cd014a2019-04-08 15:04:33 -0700410ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700411 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700412{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700413 std::string connection;
414 std::string path;
415
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000416 if (sensnum == reservedSensorNumber)
417 {
418 return ipmi::responseInvalidFieldRequest();
419 }
420
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700421 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700422 if (status)
423 {
James Feist0cd014a2019-04-08 15:04:33 -0700424 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700425 }
426
427 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700428 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700429 {
James Feist0cd014a2019-04-08 15:04:33 -0700430 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700431 }
432 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
433
434 if (sensorObject == sensorMap.end() ||
435 sensorObject->second.find("Value") == sensorObject->second.end())
436 {
James Feist0cd014a2019-04-08 15:04:33 -0700437 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700439 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700440 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700441
Yong Li1f2eb5e2019-05-23 14:07:17 +0800442 double max = 0;
443 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700444 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700445
446 int16_t mValue = 0;
447 int16_t bValue = 0;
448 int8_t rExp = 0;
449 int8_t bExp = 0;
450 bool bSigned = false;
451
452 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
453 {
James Feist0cd014a2019-04-08 15:04:33 -0700454 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700455 }
456
James Feist0cd014a2019-04-08 15:04:33 -0700457 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700458 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700459 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700460 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700461 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800462 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700463 bool notReading = std::isnan(reading);
464
465 if (!notReading)
466 {
467 auto availableObject =
468 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
469 if (availableObject != sensorMap.end())
470 {
471 auto findAvailable = availableObject->second.find("Available");
472 if (findAvailable != availableObject->second.end())
473 {
474 bool* available = std::get_if<bool>(&(findAvailable->second));
475 if (available && !(*available))
476 {
477 notReading = true;
478 }
479 }
480 }
481 }
482
483 if (notReading)
484 {
485 operation |= static_cast<uint8_t>(
486 IPMISensorReadingByte2::readingStateUnavailable);
487 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700488
Josh Lehan06aa21a2020-10-28 21:59:06 -0700489 int byteValue;
490 if (bSigned)
491 {
492 byteValue = static_cast<int>(static_cast<int8_t>(value));
493 }
494 else
495 {
496 byteValue = static_cast<int>(static_cast<uint8_t>(value));
497 }
498
499 // Keep stats on the reading just obtained, even if it is "NaN"
500 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
501 {
502 // This is the first reading, show the coefficients
503 double step = (max - min) / 255.0;
504 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
505 << ": Range min=" << min << " max=" << max
506 << ", step=" << step
507 << ", Coefficients mValue=" << static_cast<int>(mValue)
508 << " rExp=" << static_cast<int>(rExp)
509 << " bValue=" << static_cast<int>(bValue)
510 << " bExp=" << static_cast<int>(bExp)
511 << " bSigned=" << static_cast<int>(bSigned) << "\n";
512 };
513
James Feist0cd014a2019-04-08 15:04:33 -0700514 uint8_t thresholds = 0;
515
516 auto warningObject =
517 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
518 if (warningObject != sensorMap.end())
519 {
520 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
521 auto alarmLow = warningObject->second.find("WarningAlarmLow");
522 if (alarmHigh != warningObject->second.end())
523 {
524 if (std::get<bool>(alarmHigh->second))
525 {
526 thresholds |= static_cast<uint8_t>(
527 IPMISensorReadingByte3::upperNonCritical);
528 }
529 }
530 if (alarmLow != warningObject->second.end())
531 {
532 if (std::get<bool>(alarmLow->second))
533 {
534 thresholds |= static_cast<uint8_t>(
535 IPMISensorReadingByte3::lowerNonCritical);
536 }
537 }
538 }
539
540 auto criticalObject =
541 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
542 if (criticalObject != sensorMap.end())
543 {
544 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
545 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
546 if (alarmHigh != criticalObject->second.end())
547 {
548 if (std::get<bool>(alarmHigh->second))
549 {
550 thresholds |=
551 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
552 }
553 }
554 if (alarmLow != criticalObject->second.end())
555 {
556 if (std::get<bool>(alarmLow->second))
557 {
558 thresholds |=
559 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
560 }
561 }
562 }
563
564 // no discrete as of today so optional byte is never returned
565 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700566}
567
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000568/** @brief implements the Set Sensor threshold command
569 * @param sensorNumber - sensor number
570 * @param lowerNonCriticalThreshMask
571 * @param lowerCriticalThreshMask
572 * @param lowerNonRecovThreshMask
573 * @param upperNonCriticalThreshMask
574 * @param upperCriticalThreshMask
575 * @param upperNonRecovThreshMask
576 * @param reserved
577 * @param lowerNonCritical - lower non-critical threshold
578 * @param lowerCritical - Lower critical threshold
579 * @param lowerNonRecoverable - Lower non recovarable threshold
580 * @param upperNonCritical - Upper non-critical threshold
581 * @param upperCritical - Upper critical
582 * @param upperNonRecoverable - Upper Non-recoverable
583 *
584 * @returns IPMI completion code
585 */
586ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700587 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
588 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
589 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
590 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
591 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
592 uint8_t upperNonCritical, uint8_t upperCritical,
593 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700594{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000595 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700596
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000597 if (sensorNum == reservedSensorNumber)
598 {
599 return ipmi::responseInvalidFieldRequest();
600 }
601
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000602 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700603 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000604 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605 }
606
607 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000608 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700609 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000610 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611 }
612
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000613 // if none of the threshold mask are set, nothing to do
614 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
615 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
616 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700617 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000618 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700619 }
620
621 std::string connection;
622 std::string path;
623
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700624 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700625 if (status)
626 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 }
629 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700630 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000632 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700633 }
634
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 double max = 0;
636 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700637 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638
639 int16_t mValue = 0;
640 int16_t bValue = 0;
641 int8_t rExp = 0;
642 int8_t bExp = 0;
643 bool bSigned = false;
644
645 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
646 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000647 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700648 }
649
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 // store a vector of property name, value to set, and interface
651 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
652
653 // define the indexes of the tuple
654 constexpr uint8_t propertyName = 0;
655 constexpr uint8_t thresholdValue = 1;
656 constexpr uint8_t interface = 2;
657 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000658 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659 {
660 auto findThreshold =
661 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
662 if (findThreshold == sensorMap.end())
663 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000664 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700665 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000666 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700667 {
668 auto findLower = findThreshold->second.find("CriticalLow");
669 if (findLower == findThreshold->second.end())
670 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000671 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700672 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000673 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700674 findThreshold->first);
675 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000676 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700677 {
678 auto findUpper = findThreshold->second.find("CriticalHigh");
679 if (findUpper == findThreshold->second.end())
680 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000681 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700682 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000683 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700684 findThreshold->first);
685 }
686 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000687 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688 {
689 auto findThreshold =
690 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
691 if (findThreshold == sensorMap.end())
692 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000693 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700694 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000695 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700696 {
697 auto findLower = findThreshold->second.find("WarningLow");
698 if (findLower == findThreshold->second.end())
699 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000700 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700701 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000702 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700703 findThreshold->first);
704 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000705 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700706 {
707 auto findUpper = findThreshold->second.find("WarningHigh");
708 if (findUpper == findThreshold->second.end())
709 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000710 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700711 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000712 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700713 findThreshold->first);
714 }
715 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700716 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700717 {
718 // from section 36.3 in the IPMI Spec, assume all linear
719 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800720 (bValue * std::pow(10.0, bExp))) *
721 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700722 setDbusProperty(
723 *getSdBus(), connection, path, std::get<interface>(property),
724 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700725 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000726 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700727}
728
James Feistfcd2d3a2020-05-28 10:38:15 -0700729IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700730{
James Feist902c4c52019-04-16 14:51:31 -0700731 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732 auto warningInterface =
733 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
734 auto criticalInterface =
735 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
736
737 if ((warningInterface != sensorMap.end()) ||
738 (criticalInterface != sensorMap.end()))
739 {
740 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
741
742 if (sensorPair == sensorMap.end())
743 {
744 // should not have been able to find a sensor not implementing
745 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700746 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700747 }
748
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800749 double max = 0;
750 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700751 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700752
753 int16_t mValue = 0;
754 int16_t bValue = 0;
755 int8_t rExp = 0;
756 int8_t bExp = 0;
757 bool bSigned = false;
758
759 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
760 {
James Feist902c4c52019-04-16 14:51:31 -0700761 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700762 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700763 if (warningInterface != sensorMap.end())
764 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700765 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700766
767 auto warningHigh = warningMap.find("WarningHigh");
768 auto warningLow = warningMap.find("WarningLow");
769
770 if (warningHigh != warningMap.end())
771 {
James Feist902c4c52019-04-16 14:51:31 -0700772
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700773 double value =
774 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700775 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700776 value, mValue, rExp, bValue, bExp, bSigned);
777 }
778 if (warningLow != warningMap.end())
779 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700780 double value =
781 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700782 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700783 value, mValue, rExp, bValue, bExp, bSigned);
784 }
785 }
786 if (criticalInterface != sensorMap.end())
787 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700788 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700789
790 auto criticalHigh = criticalMap.find("CriticalHigh");
791 auto criticalLow = criticalMap.find("CriticalLow");
792
793 if (criticalHigh != criticalMap.end())
794 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700795 double value =
796 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700797 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700798 value, mValue, rExp, bValue, bExp, bSigned);
799 }
800 if (criticalLow != criticalMap.end())
801 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700802 double value =
803 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700804 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700805 value, mValue, rExp, bValue, bExp, bSigned);
806 }
807 }
808 }
James Feist902c4c52019-04-16 14:51:31 -0700809 return resp;
810}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700811
James Feist902c4c52019-04-16 14:51:31 -0700812ipmi::RspType<uint8_t, // readable
813 uint8_t, // lowerNCrit
814 uint8_t, // lowerCrit
815 uint8_t, // lowerNrecoverable
816 uint8_t, // upperNC
817 uint8_t, // upperCrit
818 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700819 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700820{
821 std::string connection;
822 std::string path;
823
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000824 if (sensorNumber == reservedSensorNumber)
825 {
826 return ipmi::responseInvalidFieldRequest();
827 }
828
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700829 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700830 if (status)
831 {
832 return ipmi::response(status);
833 }
834
835 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700836 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700837 {
838 return ipmi::responseResponseError();
839 }
840
841 IPMIThresholds thresholdData;
842 try
843 {
844 thresholdData = getIPMIThresholds(sensorMap);
845 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700846 catch (std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700847 {
848 return ipmi::responseResponseError();
849 }
850
851 uint8_t readable = 0;
852 uint8_t lowerNC = 0;
853 uint8_t lowerCritical = 0;
854 uint8_t lowerNonRecoverable = 0;
855 uint8_t upperNC = 0;
856 uint8_t upperCritical = 0;
857 uint8_t upperNonRecoverable = 0;
858
859 if (thresholdData.warningHigh)
860 {
861 readable |=
862 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
863 upperNC = *thresholdData.warningHigh;
864 }
865 if (thresholdData.warningLow)
866 {
867 readable |=
868 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
869 lowerNC = *thresholdData.warningLow;
870 }
871
872 if (thresholdData.criticalHigh)
873 {
874 readable |=
875 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
876 upperCritical = *thresholdData.criticalHigh;
877 }
878 if (thresholdData.criticalLow)
879 {
880 readable |=
881 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
882 lowerCritical = *thresholdData.criticalLow;
883 }
884
885 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
886 lowerNonRecoverable, upperNC, upperCritical,
887 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700888}
889
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000890/** @brief implements the get Sensor event enable command
891 * @param sensorNumber - sensor number
892 *
893 * @returns IPMI completion code plus response data
894 * - enabled - Sensor Event messages
895 * - assertionEnabledLsb - Assertion event messages
896 * - assertionEnabledMsb - Assertion event messages
897 * - deassertionEnabledLsb - Deassertion event messages
898 * - deassertionEnabledMsb - Deassertion event messages
899 */
900
901ipmi::RspType<uint8_t, // enabled
902 uint8_t, // assertionEnabledLsb
903 uint8_t, // assertionEnabledMsb
904 uint8_t, // deassertionEnabledLsb
905 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700906 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700907{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700908 std::string connection;
909 std::string path;
910
Patrick Venturea41714c2019-09-25 16:59:41 -0700911 uint8_t enabled = 0;
912 uint8_t assertionEnabledLsb = 0;
913 uint8_t assertionEnabledMsb = 0;
914 uint8_t deassertionEnabledLsb = 0;
915 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000916
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000917 if (sensorNum == reservedSensorNumber)
918 {
919 return ipmi::responseInvalidFieldRequest();
920 }
921
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700922 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700923 if (status)
924 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000925 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700926 }
927
928 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700929 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700930 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000931 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700932 }
933
934 auto warningInterface =
935 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
936 auto criticalInterface =
937 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700938 if ((warningInterface != sensorMap.end()) ||
939 (criticalInterface != sensorMap.end()))
940 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000941 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700942 IPMISensorEventEnableByte2::sensorScanningEnable);
943 if (warningInterface != sensorMap.end())
944 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700945 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700946
947 auto warningHigh = warningMap.find("WarningHigh");
948 auto warningLow = warningMap.find("WarningLow");
949 if (warningHigh != warningMap.end())
950 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000951 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700952 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000953 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700954 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
955 }
956 if (warningLow != warningMap.end())
957 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000958 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700959 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000960 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
962 }
963 }
964 if (criticalInterface != sensorMap.end())
965 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700966 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700967
968 auto criticalHigh = criticalMap.find("CriticalHigh");
969 auto criticalLow = criticalMap.find("CriticalLow");
970
971 if (criticalHigh != criticalMap.end())
972 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000973 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700974 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000975 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700976 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
977 }
978 if (criticalLow != criticalMap.end())
979 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000980 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700981 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000982 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700983 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
984 }
985 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700986 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000987
988 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
989 assertionEnabledMsb, deassertionEnabledLsb,
990 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700991}
992
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000993/** @brief implements the get Sensor event status command
994 * @param sensorNumber - sensor number, FFh = reserved
995 *
996 * @returns IPMI completion code plus response data
997 * - sensorEventStatus - Sensor Event messages state
998 * - assertions - Assertion event messages
999 * - deassertions - Deassertion event messages
1000 */
1001ipmi::RspType<uint8_t, // sensorEventStatus
1002 std::bitset<16>, // assertions
1003 std::bitset<16> // deassertion
1004 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001005 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001006{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001007 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001008 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001009 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001010 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001011
1012 std::string connection;
1013 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001014 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001015 if (status)
1016 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001017 phosphor::logging::log<phosphor::logging::level::ERR>(
1018 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1019 phosphor::logging::entry("SENSOR=%d", sensorNum));
1020 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001021 }
1022
1023 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001024 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001025 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001026 phosphor::logging::log<phosphor::logging::level::ERR>(
1027 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1028 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1029 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001030 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001031 auto warningInterface =
1032 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1033 auto criticalInterface =
1034 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1035
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001036 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001037 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1038
James Feist392786a2019-03-19 13:36:10 -07001039 std::optional<bool> criticalDeassertHigh =
1040 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1041 std::optional<bool> criticalDeassertLow =
1042 thresholdDeassertMap[path]["CriticalAlarmLow"];
1043 std::optional<bool> warningDeassertHigh =
1044 thresholdDeassertMap[path]["WarningAlarmHigh"];
1045 std::optional<bool> warningDeassertLow =
1046 thresholdDeassertMap[path]["WarningAlarmLow"];
1047
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001048 std::bitset<16> assertions = 0;
1049 std::bitset<16> deassertions = 0;
1050
James Feist392786a2019-03-19 13:36:10 -07001051 if (criticalDeassertHigh && !*criticalDeassertHigh)
1052 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001053 deassertions.set(static_cast<size_t>(
1054 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001055 }
1056 if (criticalDeassertLow && !*criticalDeassertLow)
1057 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001058 deassertions.set(static_cast<size_t>(
1059 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001060 }
1061 if (warningDeassertHigh && !*warningDeassertHigh)
1062 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001063 deassertions.set(static_cast<size_t>(
1064 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001065 }
1066 if (warningDeassertLow && !*warningDeassertLow)
1067 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001068 deassertions.set(static_cast<size_t>(
1069 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001070 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071 if ((warningInterface != sensorMap.end()) ||
1072 (criticalInterface != sensorMap.end()))
1073 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001074 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075 IPMISensorEventEnableByte2::eventMessagesEnable);
1076 if (warningInterface != sensorMap.end())
1077 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001078 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001079
1080 auto warningHigh = warningMap.find("WarningAlarmHigh");
1081 auto warningLow = warningMap.find("WarningAlarmLow");
1082 auto warningHighAlarm = false;
1083 auto warningLowAlarm = false;
1084
1085 if (warningHigh != warningMap.end())
1086 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001087 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088 }
1089 if (warningLow != warningMap.end())
1090 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001091 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092 }
1093 if (warningHighAlarm)
1094 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001095 assertions.set(
1096 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1097 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001098 }
1099 if (warningLowAlarm)
1100 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001101 assertions.set(
1102 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1103 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001104 }
1105 }
1106 if (criticalInterface != sensorMap.end())
1107 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001108 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001109
1110 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1111 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1112 auto criticalHighAlarm = false;
1113 auto criticalLowAlarm = false;
1114
1115 if (criticalHigh != criticalMap.end())
1116 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001117 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118 }
1119 if (criticalLow != criticalMap.end())
1120 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001121 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001122 }
1123 if (criticalHighAlarm)
1124 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001125 assertions.set(
1126 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1127 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001128 }
1129 if (criticalLowAlarm)
1130 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001131 assertions.set(static_cast<size_t>(
1132 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133 }
1134 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135 }
1136
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001137 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001138}
1139
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001140static int getSensorDataRecord(ipmi::Context::ptr ctx,
1141 std::vector<uint8_t>& recordData,
1142 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001143{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001144 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001145 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1146 if (ret != ipmi::ccSuccess)
1147 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001148 phosphor::logging::log<phosphor::logging::level::ERR>(
1149 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001150 return GENERAL_ERROR;
1151 }
1152
1153 size_t lastRecord = sensorTree.size() + fruCount +
1154 ipmi::storage::type12Count +
1155 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001156 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001157 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001158 recordID = lastRecord;
1159 }
1160 if (recordID > lastRecord)
1161 {
1162 phosphor::logging::log<phosphor::logging::level::ERR>(
1163 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001164 return GENERAL_ERROR;
1165 }
1166
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001167 if (recordID >= sensorTree.size())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001168 {
1169 size_t fruIndex = recordID - sensorTree.size();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001170 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001171
1172 if (fruIndex >= type12End)
1173 {
1174 // NM discovery SDR
1175 size_t nmDiscoveryIndex = fruIndex - type12End;
1176 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1177 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001178 phosphor::logging::log<phosphor::logging::level::ERR>(
1179 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001180 return GENERAL_ERROR;
1181 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001182 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001183 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001184 }
1185 else if (fruIndex >= fruCount)
1186 {
1187 // handle type 12 hardcoded records
1188 size_t type12Index = fruIndex - fruCount;
1189 if (type12Index >= ipmi::storage::type12Count)
1190 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001191 phosphor::logging::log<phosphor::logging::level::ERR>(
1192 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001193 return GENERAL_ERROR;
1194 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001195 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001196 }
1197 else
1198 {
1199 // handle fru records
1200 get_sdr::SensorDataFruRecord data;
1201 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1202 if (ret != IPMI_CC_OK)
1203 {
1204 return GENERAL_ERROR;
1205 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001206 data.header.record_id_msb = recordID >> 8;
1207 data.header.record_id_lsb = recordID & 0xFF;
1208 recordData.insert(recordData.end(), (uint8_t*)&data,
1209 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001210 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001211
1212 return 0;
1213 }
1214
1215 std::string connection;
1216 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001217 uint16_t sensNumFromRecID{recordID};
1218 if ((recordID >= reservedSensorNumber) &&
1219 (recordID < (2 * maxSensorsPerLUN)))
1220 {
1221 sensNumFromRecID = (recordID + 1) & maxSensorsPerLUN;
1222 ctx->lun = 1;
1223 }
1224 else if ((recordID >= (2 * maxSensorsPerLUN)) &&
1225 (recordID < maxIPMISensors))
1226 {
1227 sensNumFromRecID = (recordID + 2) & maxSensorsPerLUN;
1228 ctx->lun = 3;
1229 }
1230 else if (recordID >= maxIPMISensors)
1231 {
1232 return GENERAL_ERROR;
1233 }
1234
1235 auto status = getSensorConnection(ctx, sensNumFromRecID, connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001236 if (status)
1237 {
1238 phosphor::logging::log<phosphor::logging::level::ERR>(
1239 "getSensorDataRecord: getSensorConnection error");
1240 return GENERAL_ERROR;
1241 }
1242 SensorMap sensorMap;
1243 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1244 sensorMapUpdatePeriod))
1245 {
1246 phosphor::logging::log<phosphor::logging::level::ERR>(
1247 "getSensorDataRecord: getSensorMap error");
1248 return GENERAL_ERROR;
1249 }
1250 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001251 if (sensorNum >= maxIPMISensors)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001252 {
1253 phosphor::logging::log<phosphor::logging::level::ERR>(
1254 "getSensorDataRecord: invalidSensorNumber");
1255 return GENERAL_ERROR;
1256 }
1257 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1258 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1259
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001260 if ((sensornumber != sensNumFromRecID) && (lun != ctx->lun))
1261 {
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "getSensorDataRecord: sensor record mismatch");
1264 return GENERAL_ERROR;
1265 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001266 get_sdr::SensorDataFullRecord record = {0};
1267
1268 get_sdr::header::set_record_id(
1269 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1270
1271 record.header.sdr_version = ipmiSdrVersion;
1272 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1273 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1274 sizeof(get_sdr::SensorDataRecordHeader);
1275 record.key.owner_id = 0x20;
1276 record.key.owner_lun = lun;
1277 record.key.sensor_number = sensornumber;
1278
1279 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1280 record.body.sensor_type = getSensorTypeFromPath(path);
1281 std::string type = getSensorTypeStringFromPath(path);
1282 auto typeCstr = type.c_str();
1283 auto findUnits = sensorUnits.find(typeCstr);
1284 if (findUnits != sensorUnits.end())
1285 {
1286 record.body.sensor_units_2_base =
1287 static_cast<uint8_t>(findUnits->second);
1288 } // else default 0x0 unspecified
1289
1290 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1291
1292 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1293 if (sensorObject == sensorMap.end())
1294 {
1295 phosphor::logging::log<phosphor::logging::level::ERR>(
1296 "getSensorDataRecord: sensorObject error");
1297 return GENERAL_ERROR;
1298 }
1299
1300 uint8_t entityId = 0;
1301 uint8_t entityInstance = 0x01;
1302
1303 // follow the association chain to get the parent board's entityid and
1304 // entityInstance
1305 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1306
1307 record.body.entity_id = entityId;
1308 record.body.entity_instance = entityInstance;
1309
1310 auto maxObject = sensorObject->second.find("MaxValue");
1311 auto minObject = sensorObject->second.find("MinValue");
1312
1313 // If min and/or max are left unpopulated,
1314 // then default to what a signed byte would be, namely (-128,127) range.
1315 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1316 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1317 if (maxObject != sensorObject->second.end())
1318 {
1319 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1320 }
1321
1322 if (minObject != sensorObject->second.end())
1323 {
1324 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1325 }
1326
1327 int16_t mValue = 0;
1328 int8_t rExp = 0;
1329 int16_t bValue = 0;
1330 int8_t bExp = 0;
1331 bool bSigned = false;
1332
1333 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1334 {
1335 phosphor::logging::log<phosphor::logging::level::ERR>(
1336 "getSensorDataRecord: getSensorAttributes error");
1337 return GENERAL_ERROR;
1338 }
1339
1340 // The record.body is a struct SensorDataFullRecordBody
1341 // from sensorhandler.hpp in phosphor-ipmi-host.
1342 // The meaning of these bits appears to come from
1343 // table 43.1 of the IPMI spec.
1344 // The above 5 sensor attributes are stuffed in as follows:
1345 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1346 // Byte 22-24 are for other purposes
1347 // Byte 25 = MMMMMMMM = LSB of M
1348 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1349 // Byte 27 = BBBBBBBB = LSB of B
1350 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1351 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1352 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1353
1354 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1355 record.body.m_lsb = mValue & 0xFF;
1356
1357 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1358 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1359
1360 // move the smallest bit of the MSB into place (bit 9)
1361 // the MSbs are bits 7:8 in m_msb_and_tolerance
1362 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1363
1364 record.body.b_lsb = bValue & 0xFF;
1365
1366 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1367 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1368
1369 // move the smallest bit of the MSB into place (bit 9)
1370 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1371 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1372
1373 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1374 uint8_t rExpBits = rExp & 0x07;
1375
1376 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1377 uint8_t bExpBits = bExp & 0x07;
1378
1379 // move rExp and bExp into place
1380 record.body.r_b_exponents =
1381 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1382
1383 // Set the analog reading byte interpretation accordingly
1384 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1385
1386 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1387 // These seem redundant, but derivable from the above 5 attributes
1388 // Original comment said "todo fill out rest of units"
1389
1390 // populate sensor name from path
1391 std::string name;
1392 size_t nameStart = path.rfind("/");
1393 if (nameStart != std::string::npos)
1394 {
1395 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1396 }
1397
1398 std::replace(name.begin(), name.end(), '_', ' ');
1399 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1400 {
1401 // try to not truncate by replacing common words
1402 constexpr std::array<std::pair<const char*, const char*>, 2>
1403 replaceWords = {std::make_pair("Output", "Out"),
1404 std::make_pair("Input", "In")};
1405 for (const auto& [find, replace] : replaceWords)
1406 {
1407 boost::replace_all(name, find, replace);
1408 }
1409
1410 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1411 }
1412 record.body.id_string_info = name.size();
1413 std::strncpy(record.body.id_string, name.c_str(),
1414 sizeof(record.body.id_string));
1415
Josh Lehan06aa21a2020-10-28 21:59:06 -07001416 // Remember the sensor name, as determined for this sensor number
1417 details::sdrStatsTable.updateName(sensornumber, name);
1418
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001419 IPMIThresholds thresholdData;
1420 try
1421 {
1422 thresholdData = getIPMIThresholds(sensorMap);
1423 }
1424 catch (std::exception&)
1425 {
1426 phosphor::logging::log<phosphor::logging::level::ERR>(
1427 "getSensorDataRecord: getIPMIThresholds error");
1428 return GENERAL_ERROR;
1429 }
1430
1431 if (thresholdData.criticalHigh)
1432 {
1433 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1434 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1435 IPMISensorEventEnableThresholds::criticalThreshold);
1436 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1437 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1438 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1439 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1440 record.body.discrete_reading_setting_mask[0] |=
1441 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1442 }
1443 if (thresholdData.warningHigh)
1444 {
1445 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1446 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1447 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1448 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1449 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1450 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1451 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1452 record.body.discrete_reading_setting_mask[0] |=
1453 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1454 }
1455 if (thresholdData.criticalLow)
1456 {
1457 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1458 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1459 IPMISensorEventEnableThresholds::criticalThreshold);
1460 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1461 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1462 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1463 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1464 record.body.discrete_reading_setting_mask[0] |=
1465 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1466 }
1467 if (thresholdData.warningLow)
1468 {
1469 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1470 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1471 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1472 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1473 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1474 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1475 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1476 record.body.discrete_reading_setting_mask[0] |=
1477 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1478 }
1479
1480 // everything that is readable is setable
1481 record.body.discrete_reading_setting_mask[1] =
1482 record.body.discrete_reading_setting_mask[0];
1483 recordData.insert(recordData.end(), (uint8_t*)&record,
1484 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001485 return 0;
1486}
1487
1488/** @brief implements the get SDR Info command
1489 * @param count - Operation
1490 *
1491 * @returns IPMI completion code plus response data
1492 * - sdrCount - sensor/SDR count
1493 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1494 */
1495static ipmi::RspType<uint8_t, // respcount
1496 uint8_t, // dynamic population flags
1497 uint32_t // last time a sensor was added
1498 >
1499 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1500 std::optional<uint8_t> count)
1501{
1502 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001503 uint16_t recordID = 0;
1504 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001505 // Sensors are dynamically allocated, and there is at least one LUN
1506 uint8_t lunsAndDynamicPopulation = 0x80;
1507 constexpr uint8_t getSdrCount = 0x01;
1508 constexpr uint8_t getSensorCount = 0x00;
1509
1510 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1511 {
1512 return ipmi::responseResponseError();
1513 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001514 uint16_t numSensors = sensorTree.size();
1515 if (count.value_or(0) == getSdrCount)
1516 {
1517 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001518 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001519 {
1520 get_sdr::SensorDataRecordHeader* hdr =
1521 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001522 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001523 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1524 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001525 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001526 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001527 record.data());
1528 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001529 {
1530 sdrCount++;
1531 }
1532 }
1533 }
1534 }
1535 else if (count.value_or(0) == getSensorCount)
1536 {
1537 // Return the number of sensors attached to the LUN
1538 if ((ctx->lun == 0) && (numSensors > 0))
1539 {
1540 sdrCount =
1541 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1542 }
1543 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1544 {
1545 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1546 ? maxSensorsPerLUN
1547 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1548 }
1549 else if (ctx->lun == 3)
1550 {
1551 if (numSensors <= maxIPMISensors)
1552 {
1553 sdrCount =
1554 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1555 }
1556 else
1557 {
1558 // error
1559 throw std::out_of_range(
1560 "Maximum number of IPMI sensors exceeded.");
1561 }
1562 }
1563 }
1564 else
1565 {
1566 return ipmi::responseInvalidFieldRequest();
1567 }
1568
1569 // Get Sensor count. This returns the number of sensors
1570 if (numSensors > 0)
1571 {
1572 lunsAndDynamicPopulation |= 1;
1573 }
1574 if (numSensors > maxSensorsPerLUN)
1575 {
1576 lunsAndDynamicPopulation |= 2;
1577 }
1578 if (numSensors >= (maxSensorsPerLUN * 2))
1579 {
1580 lunsAndDynamicPopulation |= 8;
1581 }
1582 if (numSensors > maxIPMISensors)
1583 {
1584 // error
1585 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1586 }
1587
1588 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1589 sdrLastAdd);
1590}
1591
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001592/* end sensor commands */
1593
1594/* storage commands */
1595
James Feist74c50c62019-08-14 14:18:41 -07001596ipmi::RspType<uint8_t, // sdr version
1597 uint16_t, // record count
1598 uint16_t, // free space
1599 uint32_t, // most recent addition
1600 uint32_t, // most recent erase
1601 uint8_t // operationSupport
1602 >
James Feist25690252019-12-23 12:25:49 -08001603 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001604{
James Feist74c50c62019-08-14 14:18:41 -07001605 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001606 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001607 {
James Feist74c50c62019-08-14 14:18:41 -07001608 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001609 }
1610
James Feist74c50c62019-08-14 14:18:41 -07001611 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001612 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001613 if (ret != ipmi::ccSuccess)
1614 {
1615 return ipmi::response(ret);
1616 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001617
James Feist74c50c62019-08-14 14:18:41 -07001618 uint16_t recordCount =
1619 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001620
James Feist74c50c62019-08-14 14:18:41 -07001621 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001622 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001623
1624 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001625 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001626 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001627 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001628 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1629 unspecifiedFreeSpace, sdrLastAdd,
1630 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001631}
1632
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001633/** @brief implements the get SDR allocation info command
1634 *
1635 * @returns IPMI completion code plus response data
1636 * - allocUnits - Number of possible allocation units
1637 * - allocUnitSize - Allocation unit size in bytes.
1638 * - allocUnitFree - Number of free allocation units
1639 * - allocUnitLargestFree - Largest free block in allocation units
1640 * - maxRecordSize - Maximum record size in allocation units.
1641 */
1642ipmi::RspType<uint16_t, // allocUnits
1643 uint16_t, // allocUnitSize
1644 uint16_t, // allocUnitFree
1645 uint16_t, // allocUnitLargestFree
1646 uint8_t // maxRecordSize
1647 >
1648 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001649{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001650 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001651 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001652
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001653 constexpr uint16_t allocUnitFree = 0;
1654 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001655 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001656 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001657
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001658 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1659 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001660}
1661
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001662/** @brief implements the reserve SDR command
1663 * @returns IPMI completion code plus response data
1664 * - sdrReservationID
1665 */
1666ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001667{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001668 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001669 if (sdrReservationID == 0)
1670 {
1671 sdrReservationID++;
1672 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001673
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001674 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001675}
1676
James Feistb49a98a2019-04-16 13:48:09 -07001677ipmi::RspType<uint16_t, // next record ID
1678 std::vector<uint8_t> // payload
1679 >
James Feist25690252019-12-23 12:25:49 -08001680 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1681 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001682{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001683 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001684 // reservation required for partial reads with non zero offset into
1685 // record
James Feistb49a98a2019-04-16 13:48:09 -07001686 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001687 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001688 phosphor::logging::log<phosphor::logging::level::ERR>(
1689 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001690 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001691 }
James Feist25690252019-12-23 12:25:49 -08001692 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001693 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001695 phosphor::logging::log<phosphor::logging::level::ERR>(
1696 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001697 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001698 }
1699
Yong Lifee5e4c2020-01-17 19:36:29 +08001700 size_t lastRecord = sensorTree.size() + fruCount +
1701 ipmi::storage::type12Count +
1702 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001703 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1704
1705 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001706 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001707 phosphor::logging::log<phosphor::logging::level::ERR>(
1708 "ipmiStorageGetSDR: getSensorSubtree error");
1709 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001710 }
1711
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001712 std::vector<uint8_t> record;
1713 if (getSensorDataRecord(ctx, record, recordID))
1714 {
1715 phosphor::logging::log<phosphor::logging::level::ERR>(
1716 "ipmiStorageGetSDR: fail to get SDR");
1717 return ipmi::responseInvalidFieldRequest();
1718 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001719 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001720 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001721 if (!hdr)
1722 {
1723 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001724 "ipmiStorageGetSDR: record header is null");
1725 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001726 }
1727
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001728 size_t sdrLength =
1729 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1730 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001731 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001732 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001733 }
1734
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001735 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001736 if (!respStart)
1737 {
1738 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001739 "ipmiStorageGetSDR: record is null");
1740 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001741 }
James Feistb49a98a2019-04-16 13:48:09 -07001742 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001743
James Feistb49a98a2019-04-16 13:48:09 -07001744 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001745}
1746/* end storage commands */
1747
1748void registerSensorFunctions()
1749{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001750 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001751 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1752 ipmi::sensor_event::cmdPlatformEvent,
1753 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001754
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001755 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001756 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1757 ipmi::sensor_event::cmdGetSensorReading,
1758 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001759
1760 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001761 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1762 ipmi::sensor_event::cmdGetSensorThreshold,
1763 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001764
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001765 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001766 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1767 ipmi::sensor_event::cmdSetSensorThreshold,
1768 ipmi::Privilege::Operator,
1769 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001770
1771 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001772 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1773 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001774 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001775
1776 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001777 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1778 ipmi::sensor_event::cmdGetSensorEventStatus,
1779 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001780
1781 // register all storage commands for both Sensor and Storage command
1782 // versions
1783
1784 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001785 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1786 ipmi::storage::cmdGetSdrRepositoryInfo,
1787 ipmi::Privilege::User,
1788 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001789
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001790 // <Get Device SDR Info>
1791 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1792 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1793 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1794
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001795 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001796 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1797 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1798 ipmi::Privilege::User,
1799 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001800
1801 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001802 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1803 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001804 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001805
Vernon Mauery98bbf692019-09-16 11:14:59 -07001806 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1807 ipmi::storage::cmdReserveSdrRepository,
1808 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001809
1810 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001811 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1812 ipmi::sensor_event::cmdGetDeviceSdr,
1813 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001814
Vernon Mauery98bbf692019-09-16 11:14:59 -07001815 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1816 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1817 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001818}
1819} // namespace ipmi