blob: 2512d1b20c50856028b0abe597bb0b29f7ecf8a7 [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. Bills17add592018-11-12 14:30:12 -080081// Specify the comparison required to sort and find char* map objects
82struct CmpStr
83{
James Feistfcd2d3a2020-05-28 10:38:15 -070084 bool operator()(const char* a, const char* b) const
Jason M. Bills17add592018-11-12 14:30:12 -080085 {
86 return std::strcmp(a, b) < 0;
87 }
88};
James Feistfcd2d3a2020-05-28 10:38:15 -070089const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
Jason M. Bills17add592018-11-12 14:30:12 -080090 sensorUnits{{{"temperature", SensorUnits::degreesC},
91 {"voltage", SensorUnits::volts},
92 {"current", SensorUnits::amps},
93 {"fan_tach", SensorUnits::rpm},
94 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070095
96void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070097
98static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070099 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700100 "type='signal',member='InterfacesAdded',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 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
105 std::chrono::system_clock::now().time_since_epoch())
106 .count();
107 });
108
109static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700110 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700111 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
112 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700113 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700114 sensorTree.clear();
115 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
116 std::chrono::system_clock::now().time_since_epoch())
117 .count();
118 });
119
James Feist392786a2019-03-19 13:36:10 -0700120// this keeps track of deassertions for sensor event status command. A
121// deasertion can only happen if an assertion was seen first.
122static boost::container::flat_map<
123 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
124 thresholdDeassertMap;
125
126static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700127 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700128 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
129 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700130 [](sdbusplus::message::message& m) {
James Feist392786a2019-03-19 13:36:10 -0700131 boost::container::flat_map<std::string, std::variant<bool, double>>
132 values;
133 m.read(std::string(), values);
134
135 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700136 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700137 return pair.first.find("Alarm") != std::string::npos;
138 });
139 if (findAssert != values.end())
140 {
141 auto ptr = std::get_if<bool>(&(findAssert->second));
142 if (ptr == nullptr)
143 {
144 phosphor::logging::log<phosphor::logging::level::ERR>(
145 "thresholdChanged: Assert non bool");
146 return;
147 }
148 if (*ptr)
149 {
150 phosphor::logging::log<phosphor::logging::level::INFO>(
151 "thresholdChanged: Assert",
152 phosphor::logging::entry("SENSOR=%s", m.get_path()));
153 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
154 }
155 else
156 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700157 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700158 thresholdDeassertMap[m.get_path()][findAssert->first];
159 if (value)
160 {
161 phosphor::logging::log<phosphor::logging::level::INFO>(
162 "thresholdChanged: deassert",
163 phosphor::logging::entry("SENSOR=%s", m.get_path()));
164 value = *ptr;
165 }
166 }
167 }
168 });
169
James Feistfcd2d3a2020-05-28 10:38:15 -0700170static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
171 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700172{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700173 max = 127;
174 min = -128;
175
James Feistaecaef72019-04-26 10:30:32 -0700176 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
177 auto critical =
178 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
179 auto warning =
180 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
181
182 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700183 {
James Feistaecaef72019-04-26 10:30:32 -0700184 auto maxMap = sensorObject->second.find("MaxValue");
185 auto minMap = sensorObject->second.find("MinValue");
186
187 if (maxMap != sensorObject->second.end())
188 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700189 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700190 }
191 if (minMap != sensorObject->second.end())
192 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700193 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700194 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700195 }
James Feistaecaef72019-04-26 10:30:32 -0700196 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700197 {
James Feistaecaef72019-04-26 10:30:32 -0700198 auto lower = critical->second.find("CriticalLow");
199 auto upper = critical->second.find("CriticalHigh");
200 if (lower != critical->second.end())
201 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700202 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700203 min = std::min(value, min);
204 }
205 if (upper != critical->second.end())
206 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700207 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700208 max = std::max(value, max);
209 }
210 }
211 if (warning != sensorMap.end())
212 {
213
214 auto lower = warning->second.find("WarningLow");
215 auto upper = warning->second.find("WarningHigh");
216 if (lower != warning->second.end())
217 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700218 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700219 min = std::min(value, min);
220 }
221 if (upper != warning->second.end())
222 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700223 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700224 max = std::max(value, max);
225 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700226 }
227}
228
James Feist25690252019-12-23 12:25:49 -0800229static bool getSensorMap(boost::asio::yield_context yield,
230 std::string sensorConnection, std::string sensorPath,
Alex Qiu09701ef2020-07-15 17:56:21 -0700231 SensorMap& sensorMap,
232 int updatePeriod = sensorMapUpdatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700233{
234 static boost::container::flat_map<
235 std::string, std::chrono::time_point<std::chrono::steady_clock>>
236 updateTimeMap;
237
238 auto updateFind = updateTimeMap.find(sensorConnection);
239 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
240 if (updateFind != updateTimeMap.end())
241 {
242 lastUpdate = updateFind->second;
243 }
244
245 auto now = std::chrono::steady_clock::now();
246
247 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu09701ef2020-07-15 17:56:21 -0700248 .count() > updatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700249 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700250 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800251 boost::system::error_code ec;
252 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
253 yield, ec, sensorConnection.c_str(), "/",
254 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
255 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700256 {
257 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800258 "GetMangagedObjects for getSensorMap failed",
259 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
260
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700261 return false;
262 }
263
264 SensorCache[sensorConnection] = managedObjects;
Alex Qiu09701ef2020-07-15 17:56:21 -0700265 // Update time after finish building the map which allow the
266 // data to be cached for updatePeriod plus the build time.
267 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700268 }
269 auto connection = SensorCache.find(sensorConnection);
270 if (connection == SensorCache.end())
271 {
272 return false;
273 }
274 auto path = connection->second.find(sensorPath);
275 if (path == connection->second.end())
276 {
277 return false;
278 }
279 sensorMap = path->second;
280
281 return true;
282}
283
284/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700285namespace meHealth
286{
James Feistfcd2d3a2020-05-28 10:38:15 -0700287constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
288constexpr const char* path = "/xyz/openbmc_project/status/me";
289constexpr const char* interface = "xyz.openbmc_project.SetHealth";
290constexpr const char* method = "SetHealth";
291constexpr const char* critical = "critical";
292constexpr const char* warning = "warning";
293constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700294} // namespace meHealth
295
296static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
297{
298 constexpr const std::array<uint8_t, 10> critical = {
299 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
300 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
301 0x1A};
302
303 std::string state;
304 if (std::find(critical.begin(), critical.end(), eventData2) !=
305 critical.end())
306 {
307 state = meHealth::critical;
308 }
309 // special case 0x3 as we only care about a few states
310 else if (eventData2 == 0x3)
311 {
312 if (eventData3 <= 0x2)
313 {
314 state = meHealth::warning;
315 }
316 else
317 {
318 return;
319 }
320 }
321 else if (std::find(warning.begin(), warning.end(), eventData2) !=
322 warning.end())
323 {
324 state = meHealth::warning;
325 }
326 else
327 {
328 return;
329 }
330 if (disable)
331 {
332 state = meHealth::ok;
333 }
334
335 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
336 auto setHealth =
337 dbus->new_method_call(meHealth::busname, meHealth::path,
338 meHealth::interface, meHealth::method);
339 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
340 try
341 {
342 dbus->call(setHealth);
343 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700344 catch (sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700345 {
346 phosphor::logging::log<phosphor::logging::level::ERR>(
347 "Failed to set ME Health");
348 }
349}
350
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000351ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
352 ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700353{
James Feist7aaf3fe2019-06-25 11:52:11 -0700354 constexpr const uint8_t meId = 0x2C;
355 constexpr const uint8_t meSensorNum = 0x17;
356 constexpr const uint8_t disabled = 0x80;
357
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700358 uint8_t generatorID = 0;
359 uint8_t evmRev = 0;
360 uint8_t sensorType = 0;
361 uint8_t sensorNum = 0;
362 uint8_t eventType = 0;
363 uint8_t eventData1 = 0;
364 std::optional<uint8_t> eventData2 = 0;
365 std::optional<uint8_t> eventData3 = 0;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000366 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700367
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000368 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700369 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000370 phosphor::logging::log<phosphor::logging::level::ERR>(
371 "Failed to get Channel Info",
372 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
373 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700374 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000375
376 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
377 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700378 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000379
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700380 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
381 eventData1, eventData2, eventData3);
382 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000383 else
384 {
385
386 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
387 eventData2, eventData3);
388 generatorID = ctx->rqSA;
389 }
390
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700391 if (!p.fullyUnpacked())
392 {
393 return ipmi::responseReqDataLenInvalid();
394 }
395
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000396 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
397 if (evmRev != 0x04)
398 {
399 return ipmi::responseInvalidFieldRequest();
400 }
401 if ((sensorType > 0x2C) && (sensorType < 0xC0))
402 {
403 return ipmi::responseInvalidFieldRequest();
404 }
405
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700406 // Send this request to the Redfish hooks to log it as a Redfish message
407 // instead. There is no need to add it to the SEL, so just return success.
408 intel_oem::ipmi::sel::checkRedfishHooks(
409 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
410 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700411
James Feist7aaf3fe2019-06-25 11:52:11 -0700412 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
413 eventData3)
414 {
415 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
416 }
417
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700418 return ipmi::responseSuccess();
419}
420
James Feist0cd014a2019-04-08 15:04:33 -0700421ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700422 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700423{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700424 std::string connection;
425 std::string path;
426
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000427 if (sensnum == reservedSensorNumber)
428 {
429 return ipmi::responseInvalidFieldRequest();
430 }
431
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700432 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700433 if (status)
434 {
James Feist0cd014a2019-04-08 15:04:33 -0700435 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700436 }
437
438 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700439 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700440 {
James Feist0cd014a2019-04-08 15:04:33 -0700441 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700442 }
443 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
444
445 if (sensorObject == sensorMap.end() ||
446 sensorObject->second.find("Value") == sensorObject->second.end())
447 {
James Feist0cd014a2019-04-08 15:04:33 -0700448 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700449 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700450 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700451 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700452
Yong Li1f2eb5e2019-05-23 14:07:17 +0800453 double max = 0;
454 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700455 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700456
457 int16_t mValue = 0;
458 int16_t bValue = 0;
459 int8_t rExp = 0;
460 int8_t bExp = 0;
461 bool bSigned = false;
462
463 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
464 {
James Feist0cd014a2019-04-08 15:04:33 -0700465 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700466 }
467
James Feist0cd014a2019-04-08 15:04:33 -0700468 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700469 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700470 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700471 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700472 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800473 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700474 bool notReading = std::isnan(reading);
475
476 if (!notReading)
477 {
478 auto availableObject =
479 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
480 if (availableObject != sensorMap.end())
481 {
482 auto findAvailable = availableObject->second.find("Available");
483 if (findAvailable != availableObject->second.end())
484 {
485 bool* available = std::get_if<bool>(&(findAvailable->second));
486 if (available && !(*available))
487 {
488 notReading = true;
489 }
490 }
491 }
492 }
493
494 if (notReading)
495 {
496 operation |= static_cast<uint8_t>(
497 IPMISensorReadingByte2::readingStateUnavailable);
498 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700499
Josh Lehan06aa21a2020-10-28 21:59:06 -0700500 int byteValue;
501 if (bSigned)
502 {
503 byteValue = static_cast<int>(static_cast<int8_t>(value));
504 }
505 else
506 {
507 byteValue = static_cast<int>(static_cast<uint8_t>(value));
508 }
509
510 // Keep stats on the reading just obtained, even if it is "NaN"
511 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
512 {
513 // This is the first reading, show the coefficients
514 double step = (max - min) / 255.0;
515 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
516 << ": Range min=" << min << " max=" << max
517 << ", step=" << step
518 << ", Coefficients mValue=" << static_cast<int>(mValue)
519 << " rExp=" << static_cast<int>(rExp)
520 << " bValue=" << static_cast<int>(bValue)
521 << " bExp=" << static_cast<int>(bExp)
522 << " bSigned=" << static_cast<int>(bSigned) << "\n";
523 };
524
James Feist0cd014a2019-04-08 15:04:33 -0700525 uint8_t thresholds = 0;
526
527 auto warningObject =
528 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
529 if (warningObject != sensorMap.end())
530 {
531 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
532 auto alarmLow = warningObject->second.find("WarningAlarmLow");
533 if (alarmHigh != warningObject->second.end())
534 {
535 if (std::get<bool>(alarmHigh->second))
536 {
537 thresholds |= static_cast<uint8_t>(
538 IPMISensorReadingByte3::upperNonCritical);
539 }
540 }
541 if (alarmLow != warningObject->second.end())
542 {
543 if (std::get<bool>(alarmLow->second))
544 {
545 thresholds |= static_cast<uint8_t>(
546 IPMISensorReadingByte3::lowerNonCritical);
547 }
548 }
549 }
550
551 auto criticalObject =
552 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
553 if (criticalObject != sensorMap.end())
554 {
555 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
556 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
557 if (alarmHigh != criticalObject->second.end())
558 {
559 if (std::get<bool>(alarmHigh->second))
560 {
561 thresholds |=
562 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
563 }
564 }
565 if (alarmLow != criticalObject->second.end())
566 {
567 if (std::get<bool>(alarmLow->second))
568 {
569 thresholds |=
570 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
571 }
572 }
573 }
574
575 // no discrete as of today so optional byte is never returned
576 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700577}
578
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000579/** @brief implements the Set Sensor threshold command
580 * @param sensorNumber - sensor number
581 * @param lowerNonCriticalThreshMask
582 * @param lowerCriticalThreshMask
583 * @param lowerNonRecovThreshMask
584 * @param upperNonCriticalThreshMask
585 * @param upperCriticalThreshMask
586 * @param upperNonRecovThreshMask
587 * @param reserved
588 * @param lowerNonCritical - lower non-critical threshold
589 * @param lowerCritical - Lower critical threshold
590 * @param lowerNonRecoverable - Lower non recovarable threshold
591 * @param upperNonCritical - Upper non-critical threshold
592 * @param upperCritical - Upper critical
593 * @param upperNonRecoverable - Upper Non-recoverable
594 *
595 * @returns IPMI completion code
596 */
597ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700598 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
599 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
600 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
601 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
602 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
603 uint8_t upperNonCritical, uint8_t upperCritical,
604 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000606 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700607
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000608 if (sensorNum == reservedSensorNumber)
609 {
610 return ipmi::responseInvalidFieldRequest();
611 }
612
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000613 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700614 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000615 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700616 }
617
618 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622 }
623
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000624 // if none of the threshold mask are set, nothing to do
625 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
626 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
627 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 }
631
632 std::string connection;
633 std::string path;
634
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700635 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700636 if (status)
637 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 }
640 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700641 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000643 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 }
645
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700646 double max = 0;
647 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700648 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700649
650 int16_t mValue = 0;
651 int16_t bValue = 0;
652 int8_t rExp = 0;
653 int8_t bExp = 0;
654 bool bSigned = false;
655
656 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
657 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000658 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659 }
660
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700661 // store a vector of property name, value to set, and interface
662 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
663
664 // define the indexes of the tuple
665 constexpr uint8_t propertyName = 0;
666 constexpr uint8_t thresholdValue = 1;
667 constexpr uint8_t interface = 2;
668 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000669 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700670 {
671 auto findThreshold =
672 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
673 if (findThreshold == sensorMap.end())
674 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000675 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700676 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000677 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700678 {
679 auto findLower = findThreshold->second.find("CriticalLow");
680 if (findLower == findThreshold->second.end())
681 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000682 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700683 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000684 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700685 findThreshold->first);
686 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000687 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688 {
689 auto findUpper = findThreshold->second.find("CriticalHigh");
690 if (findUpper == findThreshold->second.end())
691 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000692 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700693 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000694 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700695 findThreshold->first);
696 }
697 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000698 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700699 {
700 auto findThreshold =
701 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
702 if (findThreshold == sensorMap.end())
703 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000704 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700705 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000706 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700707 {
708 auto findLower = findThreshold->second.find("WarningLow");
709 if (findLower == findThreshold->second.end())
710 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000711 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700712 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000713 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700714 findThreshold->first);
715 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000716 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700717 {
718 auto findUpper = findThreshold->second.find("WarningHigh");
719 if (findUpper == findThreshold->second.end())
720 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000721 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700722 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000723 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700724 findThreshold->first);
725 }
726 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700727 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700728 {
729 // from section 36.3 in the IPMI Spec, assume all linear
730 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800731 (bValue * std::pow(10.0, bExp))) *
732 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700733 setDbusProperty(
734 *getSdBus(), connection, path, std::get<interface>(property),
735 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700736 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000737 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700738}
739
James Feistfcd2d3a2020-05-28 10:38:15 -0700740IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700741{
James Feist902c4c52019-04-16 14:51:31 -0700742 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700743 auto warningInterface =
744 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
745 auto criticalInterface =
746 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
747
748 if ((warningInterface != sensorMap.end()) ||
749 (criticalInterface != sensorMap.end()))
750 {
751 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
752
753 if (sensorPair == sensorMap.end())
754 {
755 // should not have been able to find a sensor not implementing
756 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700757 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700758 }
759
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800760 double max = 0;
761 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700762 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700763
764 int16_t mValue = 0;
765 int16_t bValue = 0;
766 int8_t rExp = 0;
767 int8_t bExp = 0;
768 bool bSigned = false;
769
770 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
771 {
James Feist902c4c52019-04-16 14:51:31 -0700772 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700773 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700774 if (warningInterface != sensorMap.end())
775 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700776 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700777
778 auto warningHigh = warningMap.find("WarningHigh");
779 auto warningLow = warningMap.find("WarningLow");
780
781 if (warningHigh != warningMap.end())
782 {
James Feist902c4c52019-04-16 14:51:31 -0700783
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700784 double value =
785 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700786 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700787 value, mValue, rExp, bValue, bExp, bSigned);
788 }
789 if (warningLow != warningMap.end())
790 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700791 double value =
792 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700793 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700794 value, mValue, rExp, bValue, bExp, bSigned);
795 }
796 }
797 if (criticalInterface != sensorMap.end())
798 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700799 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700800
801 auto criticalHigh = criticalMap.find("CriticalHigh");
802 auto criticalLow = criticalMap.find("CriticalLow");
803
804 if (criticalHigh != criticalMap.end())
805 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700806 double value =
807 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700808 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700809 value, mValue, rExp, bValue, bExp, bSigned);
810 }
811 if (criticalLow != criticalMap.end())
812 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700813 double value =
814 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700815 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700816 value, mValue, rExp, bValue, bExp, bSigned);
817 }
818 }
819 }
James Feist902c4c52019-04-16 14:51:31 -0700820 return resp;
821}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700822
James Feist902c4c52019-04-16 14:51:31 -0700823ipmi::RspType<uint8_t, // readable
824 uint8_t, // lowerNCrit
825 uint8_t, // lowerCrit
826 uint8_t, // lowerNrecoverable
827 uint8_t, // upperNC
828 uint8_t, // upperCrit
829 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700830 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700831{
832 std::string connection;
833 std::string path;
834
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000835 if (sensorNumber == reservedSensorNumber)
836 {
837 return ipmi::responseInvalidFieldRequest();
838 }
839
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700840 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700841 if (status)
842 {
843 return ipmi::response(status);
844 }
845
846 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700847 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700848 {
849 return ipmi::responseResponseError();
850 }
851
852 IPMIThresholds thresholdData;
853 try
854 {
855 thresholdData = getIPMIThresholds(sensorMap);
856 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700857 catch (std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700858 {
859 return ipmi::responseResponseError();
860 }
861
862 uint8_t readable = 0;
863 uint8_t lowerNC = 0;
864 uint8_t lowerCritical = 0;
865 uint8_t lowerNonRecoverable = 0;
866 uint8_t upperNC = 0;
867 uint8_t upperCritical = 0;
868 uint8_t upperNonRecoverable = 0;
869
870 if (thresholdData.warningHigh)
871 {
872 readable |=
873 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
874 upperNC = *thresholdData.warningHigh;
875 }
876 if (thresholdData.warningLow)
877 {
878 readable |=
879 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
880 lowerNC = *thresholdData.warningLow;
881 }
882
883 if (thresholdData.criticalHigh)
884 {
885 readable |=
886 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
887 upperCritical = *thresholdData.criticalHigh;
888 }
889 if (thresholdData.criticalLow)
890 {
891 readable |=
892 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
893 lowerCritical = *thresholdData.criticalLow;
894 }
895
896 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
897 lowerNonRecoverable, upperNC, upperCritical,
898 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700899}
900
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000901/** @brief implements the get Sensor event enable command
902 * @param sensorNumber - sensor number
903 *
904 * @returns IPMI completion code plus response data
905 * - enabled - Sensor Event messages
906 * - assertionEnabledLsb - Assertion event messages
907 * - assertionEnabledMsb - Assertion event messages
908 * - deassertionEnabledLsb - Deassertion event messages
909 * - deassertionEnabledMsb - Deassertion event messages
910 */
911
912ipmi::RspType<uint8_t, // enabled
913 uint8_t, // assertionEnabledLsb
914 uint8_t, // assertionEnabledMsb
915 uint8_t, // deassertionEnabledLsb
916 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700917 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700918{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700919 std::string connection;
920 std::string path;
921
Patrick Venturea41714c2019-09-25 16:59:41 -0700922 uint8_t enabled = 0;
923 uint8_t assertionEnabledLsb = 0;
924 uint8_t assertionEnabledMsb = 0;
925 uint8_t deassertionEnabledLsb = 0;
926 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000927
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000928 if (sensorNum == reservedSensorNumber)
929 {
930 return ipmi::responseInvalidFieldRequest();
931 }
932
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700933 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700934 if (status)
935 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000936 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700937 }
938
939 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700940 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700941 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000942 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700943 }
944
945 auto warningInterface =
946 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
947 auto criticalInterface =
948 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700949 if ((warningInterface != sensorMap.end()) ||
950 (criticalInterface != sensorMap.end()))
951 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000952 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700953 IPMISensorEventEnableByte2::sensorScanningEnable);
954 if (warningInterface != sensorMap.end())
955 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700956 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700957
958 auto warningHigh = warningMap.find("WarningHigh");
959 auto warningLow = warningMap.find("WarningLow");
960 if (warningHigh != warningMap.end())
961 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000962 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700963 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000964 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700965 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
966 }
967 if (warningLow != warningMap.end())
968 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000969 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700970 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000971 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700972 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
973 }
974 }
975 if (criticalInterface != sensorMap.end())
976 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700977 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700978
979 auto criticalHigh = criticalMap.find("CriticalHigh");
980 auto criticalLow = criticalMap.find("CriticalLow");
981
982 if (criticalHigh != criticalMap.end())
983 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000984 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700985 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000986 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700987 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
988 }
989 if (criticalLow != criticalMap.end())
990 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000991 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700992 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000993 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700994 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
995 }
996 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700997 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000998
999 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1000 assertionEnabledMsb, deassertionEnabledLsb,
1001 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001002}
1003
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001004/** @brief implements the get Sensor event status command
1005 * @param sensorNumber - sensor number, FFh = reserved
1006 *
1007 * @returns IPMI completion code plus response data
1008 * - sensorEventStatus - Sensor Event messages state
1009 * - assertions - Assertion event messages
1010 * - deassertions - Deassertion event messages
1011 */
1012ipmi::RspType<uint8_t, // sensorEventStatus
1013 std::bitset<16>, // assertions
1014 std::bitset<16> // deassertion
1015 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001016 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001017{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001018 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001019 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001020 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001021 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001022
1023 std::string connection;
1024 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001025 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001026 if (status)
1027 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001028 phosphor::logging::log<phosphor::logging::level::ERR>(
1029 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1030 phosphor::logging::entry("SENSOR=%d", sensorNum));
1031 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001032 }
1033
1034 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001035 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001036 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001037 phosphor::logging::log<phosphor::logging::level::ERR>(
1038 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1039 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1040 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001041 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001042 auto warningInterface =
1043 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1044 auto criticalInterface =
1045 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1046
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001047 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001048 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1049
James Feist392786a2019-03-19 13:36:10 -07001050 std::optional<bool> criticalDeassertHigh =
1051 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1052 std::optional<bool> criticalDeassertLow =
1053 thresholdDeassertMap[path]["CriticalAlarmLow"];
1054 std::optional<bool> warningDeassertHigh =
1055 thresholdDeassertMap[path]["WarningAlarmHigh"];
1056 std::optional<bool> warningDeassertLow =
1057 thresholdDeassertMap[path]["WarningAlarmLow"];
1058
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001059 std::bitset<16> assertions = 0;
1060 std::bitset<16> deassertions = 0;
1061
James Feist392786a2019-03-19 13:36:10 -07001062 if (criticalDeassertHigh && !*criticalDeassertHigh)
1063 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001064 deassertions.set(static_cast<size_t>(
1065 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001066 }
1067 if (criticalDeassertLow && !*criticalDeassertLow)
1068 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001069 deassertions.set(static_cast<size_t>(
1070 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001071 }
1072 if (warningDeassertHigh && !*warningDeassertHigh)
1073 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001074 deassertions.set(static_cast<size_t>(
1075 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001076 }
1077 if (warningDeassertLow && !*warningDeassertLow)
1078 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001079 deassertions.set(static_cast<size_t>(
1080 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001081 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001082 if ((warningInterface != sensorMap.end()) ||
1083 (criticalInterface != sensorMap.end()))
1084 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001085 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086 IPMISensorEventEnableByte2::eventMessagesEnable);
1087 if (warningInterface != sensorMap.end())
1088 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001089 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090
1091 auto warningHigh = warningMap.find("WarningAlarmHigh");
1092 auto warningLow = warningMap.find("WarningAlarmLow");
1093 auto warningHighAlarm = false;
1094 auto warningLowAlarm = false;
1095
1096 if (warningHigh != warningMap.end())
1097 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001098 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001099 }
1100 if (warningLow != warningMap.end())
1101 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001102 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001103 }
1104 if (warningHighAlarm)
1105 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001106 assertions.set(
1107 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1108 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001109 }
1110 if (warningLowAlarm)
1111 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001112 assertions.set(
1113 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1114 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115 }
1116 }
1117 if (criticalInterface != sensorMap.end())
1118 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001119 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120
1121 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1122 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1123 auto criticalHighAlarm = false;
1124 auto criticalLowAlarm = false;
1125
1126 if (criticalHigh != criticalMap.end())
1127 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001128 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001129 }
1130 if (criticalLow != criticalMap.end())
1131 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001132 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133 }
1134 if (criticalHighAlarm)
1135 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001136 assertions.set(
1137 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1138 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139 }
1140 if (criticalLowAlarm)
1141 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001142 assertions.set(static_cast<size_t>(
1143 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144 }
1145 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001146 }
1147
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001148 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149}
1150
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001151static inline uint16_t getNumberOfSensors(void)
1152{
1153 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1154 : sensorTree.size();
1155}
1156
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001157static int getSensorDataRecord(ipmi::Context::ptr ctx,
1158 std::vector<uint8_t>& recordData,
1159 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001160{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001161 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001162 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1163 if (ret != ipmi::ccSuccess)
1164 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001165 phosphor::logging::log<phosphor::logging::level::ERR>(
1166 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001167 return GENERAL_ERROR;
1168 }
1169
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001170 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001171 ipmi::storage::type12Count +
1172 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001173 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001174 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001175 recordID = lastRecord;
1176 }
1177 if (recordID > lastRecord)
1178 {
1179 phosphor::logging::log<phosphor::logging::level::ERR>(
1180 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001181 return GENERAL_ERROR;
1182 }
1183
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001184 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001185 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001186 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001187 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001188
1189 if (fruIndex >= type12End)
1190 {
1191 // NM discovery SDR
1192 size_t nmDiscoveryIndex = fruIndex - type12End;
1193 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1194 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001195 phosphor::logging::log<phosphor::logging::level::ERR>(
1196 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001197 return GENERAL_ERROR;
1198 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001199 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001200 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001201 }
1202 else if (fruIndex >= fruCount)
1203 {
1204 // handle type 12 hardcoded records
1205 size_t type12Index = fruIndex - fruCount;
1206 if (type12Index >= ipmi::storage::type12Count)
1207 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001208 phosphor::logging::log<phosphor::logging::level::ERR>(
1209 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001210 return GENERAL_ERROR;
1211 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001212 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001213 }
1214 else
1215 {
1216 // handle fru records
1217 get_sdr::SensorDataFruRecord data;
1218 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1219 if (ret != IPMI_CC_OK)
1220 {
1221 return GENERAL_ERROR;
1222 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001223 data.header.record_id_msb = recordID >> 8;
1224 data.header.record_id_lsb = recordID & 0xFF;
1225 recordData.insert(recordData.end(), (uint8_t*)&data,
1226 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001227 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001228
1229 return 0;
1230 }
1231
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001232 // Perform a incremental scan of the SDR Record ID's and translate the
1233 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1234 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1235 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1236 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001237 std::string connection;
1238 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001239 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001240 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001241 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001242 // LUN 0 has one reserved sensor number. Compensate here by adding one
1243 // to the record ID
1244 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001245 ctx->lun = 1;
1246 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001247 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001248 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001249 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1250 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1251 // rules governing its use.
1252 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001253 ctx->lun = 3;
1254 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001255
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001256 auto status = getSensorConnection(
1257 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001258 if (status)
1259 {
1260 phosphor::logging::log<phosphor::logging::level::ERR>(
1261 "getSensorDataRecord: getSensorConnection error");
1262 return GENERAL_ERROR;
1263 }
1264 SensorMap sensorMap;
1265 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1266 sensorMapUpdatePeriod))
1267 {
1268 phosphor::logging::log<phosphor::logging::level::ERR>(
1269 "getSensorDataRecord: getSensorMap error");
1270 return GENERAL_ERROR;
1271 }
1272 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001273 // Return an error on LUN 2 assingments, and any sensor number beyond the
1274 // range of LUN 3
1275 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1276 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001277 {
1278 phosphor::logging::log<phosphor::logging::level::ERR>(
1279 "getSensorDataRecord: invalidSensorNumber");
1280 return GENERAL_ERROR;
1281 }
1282 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1283 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1284
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001285 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1286 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001287 {
1288 phosphor::logging::log<phosphor::logging::level::ERR>(
1289 "getSensorDataRecord: sensor record mismatch");
1290 return GENERAL_ERROR;
1291 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001292 get_sdr::SensorDataFullRecord record = {0};
1293
1294 get_sdr::header::set_record_id(
1295 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1296
1297 record.header.sdr_version = ipmiSdrVersion;
1298 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1299 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1300 sizeof(get_sdr::SensorDataRecordHeader);
1301 record.key.owner_id = 0x20;
1302 record.key.owner_lun = lun;
1303 record.key.sensor_number = sensornumber;
1304
1305 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1306 record.body.sensor_type = getSensorTypeFromPath(path);
1307 std::string type = getSensorTypeStringFromPath(path);
1308 auto typeCstr = type.c_str();
1309 auto findUnits = sensorUnits.find(typeCstr);
1310 if (findUnits != sensorUnits.end())
1311 {
1312 record.body.sensor_units_2_base =
1313 static_cast<uint8_t>(findUnits->second);
1314 } // else default 0x0 unspecified
1315
1316 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1317
1318 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1319 if (sensorObject == sensorMap.end())
1320 {
1321 phosphor::logging::log<phosphor::logging::level::ERR>(
1322 "getSensorDataRecord: sensorObject error");
1323 return GENERAL_ERROR;
1324 }
1325
1326 uint8_t entityId = 0;
1327 uint8_t entityInstance = 0x01;
1328
1329 // follow the association chain to get the parent board's entityid and
1330 // entityInstance
1331 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1332
1333 record.body.entity_id = entityId;
1334 record.body.entity_instance = entityInstance;
1335
1336 auto maxObject = sensorObject->second.find("MaxValue");
1337 auto minObject = sensorObject->second.find("MinValue");
1338
1339 // If min and/or max are left unpopulated,
1340 // then default to what a signed byte would be, namely (-128,127) range.
1341 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1342 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1343 if (maxObject != sensorObject->second.end())
1344 {
1345 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1346 }
1347
1348 if (minObject != sensorObject->second.end())
1349 {
1350 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1351 }
1352
1353 int16_t mValue = 0;
1354 int8_t rExp = 0;
1355 int16_t bValue = 0;
1356 int8_t bExp = 0;
1357 bool bSigned = false;
1358
1359 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1360 {
1361 phosphor::logging::log<phosphor::logging::level::ERR>(
1362 "getSensorDataRecord: getSensorAttributes error");
1363 return GENERAL_ERROR;
1364 }
1365
1366 // The record.body is a struct SensorDataFullRecordBody
1367 // from sensorhandler.hpp in phosphor-ipmi-host.
1368 // The meaning of these bits appears to come from
1369 // table 43.1 of the IPMI spec.
1370 // The above 5 sensor attributes are stuffed in as follows:
1371 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1372 // Byte 22-24 are for other purposes
1373 // Byte 25 = MMMMMMMM = LSB of M
1374 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1375 // Byte 27 = BBBBBBBB = LSB of B
1376 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1377 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1378 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1379
1380 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1381 record.body.m_lsb = mValue & 0xFF;
1382
1383 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1384 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1385
1386 // move the smallest bit of the MSB into place (bit 9)
1387 // the MSbs are bits 7:8 in m_msb_and_tolerance
1388 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1389
1390 record.body.b_lsb = bValue & 0xFF;
1391
1392 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1393 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1394
1395 // move the smallest bit of the MSB into place (bit 9)
1396 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1397 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1398
1399 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1400 uint8_t rExpBits = rExp & 0x07;
1401
1402 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1403 uint8_t bExpBits = bExp & 0x07;
1404
1405 // move rExp and bExp into place
1406 record.body.r_b_exponents =
1407 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1408
1409 // Set the analog reading byte interpretation accordingly
1410 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1411
1412 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1413 // These seem redundant, but derivable from the above 5 attributes
1414 // Original comment said "todo fill out rest of units"
1415
1416 // populate sensor name from path
1417 std::string name;
1418 size_t nameStart = path.rfind("/");
1419 if (nameStart != std::string::npos)
1420 {
1421 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1422 }
1423
1424 std::replace(name.begin(), name.end(), '_', ' ');
1425 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1426 {
1427 // try to not truncate by replacing common words
1428 constexpr std::array<std::pair<const char*, const char*>, 2>
1429 replaceWords = {std::make_pair("Output", "Out"),
1430 std::make_pair("Input", "In")};
1431 for (const auto& [find, replace] : replaceWords)
1432 {
1433 boost::replace_all(name, find, replace);
1434 }
1435
1436 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1437 }
1438 record.body.id_string_info = name.size();
1439 std::strncpy(record.body.id_string, name.c_str(),
1440 sizeof(record.body.id_string));
1441
Josh Lehan06aa21a2020-10-28 21:59:06 -07001442 // Remember the sensor name, as determined for this sensor number
1443 details::sdrStatsTable.updateName(sensornumber, name);
1444
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001445 IPMIThresholds thresholdData;
1446 try
1447 {
1448 thresholdData = getIPMIThresholds(sensorMap);
1449 }
1450 catch (std::exception&)
1451 {
1452 phosphor::logging::log<phosphor::logging::level::ERR>(
1453 "getSensorDataRecord: getIPMIThresholds error");
1454 return GENERAL_ERROR;
1455 }
1456
1457 if (thresholdData.criticalHigh)
1458 {
1459 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1460 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1461 IPMISensorEventEnableThresholds::criticalThreshold);
1462 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1463 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1464 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1465 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1466 record.body.discrete_reading_setting_mask[0] |=
1467 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1468 }
1469 if (thresholdData.warningHigh)
1470 {
1471 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1472 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1473 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1474 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1475 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1476 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1477 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1478 record.body.discrete_reading_setting_mask[0] |=
1479 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1480 }
1481 if (thresholdData.criticalLow)
1482 {
1483 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1484 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1485 IPMISensorEventEnableThresholds::criticalThreshold);
1486 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1487 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1488 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1489 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1490 record.body.discrete_reading_setting_mask[0] |=
1491 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1492 }
1493 if (thresholdData.warningLow)
1494 {
1495 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1496 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1497 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1498 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1499 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1500 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1501 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1502 record.body.discrete_reading_setting_mask[0] |=
1503 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1504 }
1505
1506 // everything that is readable is setable
1507 record.body.discrete_reading_setting_mask[1] =
1508 record.body.discrete_reading_setting_mask[0];
1509 recordData.insert(recordData.end(), (uint8_t*)&record,
1510 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001511 return 0;
1512}
1513
1514/** @brief implements the get SDR Info command
1515 * @param count - Operation
1516 *
1517 * @returns IPMI completion code plus response data
1518 * - sdrCount - sensor/SDR count
1519 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1520 */
1521static ipmi::RspType<uint8_t, // respcount
1522 uint8_t, // dynamic population flags
1523 uint32_t // last time a sensor was added
1524 >
1525 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1526 std::optional<uint8_t> count)
1527{
1528 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001529 uint16_t recordID = 0;
1530 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001531 // Sensors are dynamically allocated, and there is at least one LUN
1532 uint8_t lunsAndDynamicPopulation = 0x80;
1533 constexpr uint8_t getSdrCount = 0x01;
1534 constexpr uint8_t getSensorCount = 0x00;
1535
1536 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1537 {
1538 return ipmi::responseResponseError();
1539 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001540 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001541 if (count.value_or(0) == getSdrCount)
1542 {
1543 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001544 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001545 {
1546 get_sdr::SensorDataRecordHeader* hdr =
1547 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001548 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001549 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1550 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001551 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001552 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001553 record.data());
1554 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001555 {
1556 sdrCount++;
1557 }
1558 }
1559 }
1560 }
1561 else if (count.value_or(0) == getSensorCount)
1562 {
1563 // Return the number of sensors attached to the LUN
1564 if ((ctx->lun == 0) && (numSensors > 0))
1565 {
1566 sdrCount =
1567 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1568 }
1569 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1570 {
1571 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1572 ? maxSensorsPerLUN
1573 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1574 }
1575 else if (ctx->lun == 3)
1576 {
1577 if (numSensors <= maxIPMISensors)
1578 {
1579 sdrCount =
1580 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1581 }
1582 else
1583 {
1584 // error
1585 throw std::out_of_range(
1586 "Maximum number of IPMI sensors exceeded.");
1587 }
1588 }
1589 }
1590 else
1591 {
1592 return ipmi::responseInvalidFieldRequest();
1593 }
1594
1595 // Get Sensor count. This returns the number of sensors
1596 if (numSensors > 0)
1597 {
1598 lunsAndDynamicPopulation |= 1;
1599 }
1600 if (numSensors > maxSensorsPerLUN)
1601 {
1602 lunsAndDynamicPopulation |= 2;
1603 }
1604 if (numSensors >= (maxSensorsPerLUN * 2))
1605 {
1606 lunsAndDynamicPopulation |= 8;
1607 }
1608 if (numSensors > maxIPMISensors)
1609 {
1610 // error
1611 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1612 }
1613
1614 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1615 sdrLastAdd);
1616}
1617
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001618/* end sensor commands */
1619
1620/* storage commands */
1621
James Feist74c50c62019-08-14 14:18:41 -07001622ipmi::RspType<uint8_t, // sdr version
1623 uint16_t, // record count
1624 uint16_t, // free space
1625 uint32_t, // most recent addition
1626 uint32_t, // most recent erase
1627 uint8_t // operationSupport
1628 >
James Feist25690252019-12-23 12:25:49 -08001629 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001630{
James Feist74c50c62019-08-14 14:18:41 -07001631 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001632 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001633 {
James Feist74c50c62019-08-14 14:18:41 -07001634 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001635 }
1636
James Feist74c50c62019-08-14 14:18:41 -07001637 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001638 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001639 if (ret != ipmi::ccSuccess)
1640 {
1641 return ipmi::response(ret);
1642 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001643
James Feist74c50c62019-08-14 14:18:41 -07001644 uint16_t recordCount =
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001645 getNumberOfSensors() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001646
James Feist74c50c62019-08-14 14:18:41 -07001647 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001648 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001649
1650 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001651 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001652 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001653 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001654 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1655 unspecifiedFreeSpace, sdrLastAdd,
1656 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001657}
1658
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001659/** @brief implements the get SDR allocation info command
1660 *
1661 * @returns IPMI completion code plus response data
1662 * - allocUnits - Number of possible allocation units
1663 * - allocUnitSize - Allocation unit size in bytes.
1664 * - allocUnitFree - Number of free allocation units
1665 * - allocUnitLargestFree - Largest free block in allocation units
1666 * - maxRecordSize - Maximum record size in allocation units.
1667 */
1668ipmi::RspType<uint16_t, // allocUnits
1669 uint16_t, // allocUnitSize
1670 uint16_t, // allocUnitFree
1671 uint16_t, // allocUnitLargestFree
1672 uint8_t // maxRecordSize
1673 >
1674 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001675{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001676 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001677 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001678
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001679 constexpr uint16_t allocUnitFree = 0;
1680 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001681 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001682 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001683
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001684 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1685 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001686}
1687
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001688/** @brief implements the reserve SDR command
1689 * @returns IPMI completion code plus response data
1690 * - sdrReservationID
1691 */
1692ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001693{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001695 if (sdrReservationID == 0)
1696 {
1697 sdrReservationID++;
1698 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001699
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001700 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001701}
1702
James Feistb49a98a2019-04-16 13:48:09 -07001703ipmi::RspType<uint16_t, // next record ID
1704 std::vector<uint8_t> // payload
1705 >
James Feist25690252019-12-23 12:25:49 -08001706 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1707 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001708{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001709 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001710 // reservation required for partial reads with non zero offset into
1711 // record
James Feistb49a98a2019-04-16 13:48:09 -07001712 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001713 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001714 phosphor::logging::log<phosphor::logging::level::ERR>(
1715 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001716 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001717 }
James Feist25690252019-12-23 12:25:49 -08001718 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001719 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001720 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001721 phosphor::logging::log<phosphor::logging::level::ERR>(
1722 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001723 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001724 }
1725
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001726 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001727 ipmi::storage::type12Count +
1728 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001729 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1730
1731 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001732 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001733 phosphor::logging::log<phosphor::logging::level::ERR>(
1734 "ipmiStorageGetSDR: getSensorSubtree error");
1735 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001736 }
1737
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001738 std::vector<uint8_t> record;
1739 if (getSensorDataRecord(ctx, record, recordID))
1740 {
1741 phosphor::logging::log<phosphor::logging::level::ERR>(
1742 "ipmiStorageGetSDR: fail to get SDR");
1743 return ipmi::responseInvalidFieldRequest();
1744 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001745 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001746 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001747 if (!hdr)
1748 {
1749 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001750 "ipmiStorageGetSDR: record header is null");
1751 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001752 }
1753
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001754 size_t sdrLength =
1755 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1756 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001757 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001758 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001759 }
1760
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001761 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001762 if (!respStart)
1763 {
1764 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001765 "ipmiStorageGetSDR: record is null");
1766 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001767 }
James Feistb49a98a2019-04-16 13:48:09 -07001768 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001769
James Feistb49a98a2019-04-16 13:48:09 -07001770 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001771}
1772/* end storage commands */
1773
1774void registerSensorFunctions()
1775{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001776 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001777 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1778 ipmi::sensor_event::cmdPlatformEvent,
1779 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001780
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001781 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001782 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1783 ipmi::sensor_event::cmdGetSensorReading,
1784 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001785
1786 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001787 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1788 ipmi::sensor_event::cmdGetSensorThreshold,
1789 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001790
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001791 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001792 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1793 ipmi::sensor_event::cmdSetSensorThreshold,
1794 ipmi::Privilege::Operator,
1795 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001796
1797 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001798 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1799 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001800 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001801
1802 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001803 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1804 ipmi::sensor_event::cmdGetSensorEventStatus,
1805 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001806
1807 // register all storage commands for both Sensor and Storage command
1808 // versions
1809
1810 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001811 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1812 ipmi::storage::cmdGetSdrRepositoryInfo,
1813 ipmi::Privilege::User,
1814 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001815
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001816 // <Get Device SDR Info>
1817 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1818 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1819 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1820
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001821 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001822 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1823 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1824 ipmi::Privilege::User,
1825 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001826
1827 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001828 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1829 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001830 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001831
Vernon Mauery98bbf692019-09-16 11:14:59 -07001832 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1833 ipmi::storage::cmdReserveSdrRepository,
1834 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001835
1836 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001837 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1838 ipmi::sensor_event::cmdGetDeviceSdr,
1839 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001840
Vernon Mauery98bbf692019-09-16 11:14:59 -07001841 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1842 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1843 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001844}
1845} // namespace ipmi