blob: d204885ddc94cf6bfc57426ba575e2d302496c24 [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);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700203 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700204 }
205 if (upper != critical->second.end())
206 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700207 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700208 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700209 }
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);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700219 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700220 }
221 if (upper != warning->second.end())
222 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700223 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700224 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700225 }
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 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500344 catch (const 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
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700358 uint8_t sysgeneratorID = 0;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700359 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;
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700366 uint16_t generatorID = 0;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000367 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700368
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000369 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700370 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000371 phosphor::logging::log<phosphor::logging::level::ERR>(
372 "Failed to get Channel Info",
373 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
374 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700375 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000376
377 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
378 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700379 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000380
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700381 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700382 eventData1, eventData2, eventData3);
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700383 constexpr const uint8_t isSoftwareID = 0x01;
384 if (!(sysgeneratorID & isSoftwareID))
385 {
386 return ipmi::responseInvalidFieldRequest();
387 }
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700388 // Refer to IPMI Spec Table 32: SEL Event Records
389 generatorID = (ctx->channel << 12) // Channel
390 | (0x0 << 10) // Reserved
391 | (0x0 << 8) // 0x0 for sys-soft ID
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700392 | sysgeneratorID;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700393 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000394 else
395 {
396
397 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
398 eventData2, eventData3);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700399 // Refer to IPMI Spec Table 32: SEL Event Records
400 generatorID = (ctx->channel << 12) // Channel
401 | (0x0 << 10) // Reserved
402 | ((ctx->lun & 0x3) << 8) // Lun
403 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000404 }
405
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700406 if (!p.fullyUnpacked())
407 {
408 return ipmi::responseReqDataLenInvalid();
409 }
410
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000411 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
412 if (evmRev != 0x04)
413 {
414 return ipmi::responseInvalidFieldRequest();
415 }
416 if ((sensorType > 0x2C) && (sensorType < 0xC0))
417 {
418 return ipmi::responseInvalidFieldRequest();
419 }
420
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700421 // Send this request to the Redfish hooks to log it as a Redfish message
422 // instead. There is no need to add it to the SEL, so just return success.
423 intel_oem::ipmi::sel::checkRedfishHooks(
424 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
425 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700426
Vernon Maueryce3b7572022-04-14 13:16:25 -0700427 if (static_cast<uint8_t>(generatorID) == meId && sensorNum == meSensorNum &&
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700428 eventData2 && eventData3)
James Feist7aaf3fe2019-06-25 11:52:11 -0700429 {
430 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
431 }
432
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700433 return ipmi::responseSuccess();
434}
435
James Feist0cd014a2019-04-08 15:04:33 -0700436ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700437 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700439 std::string connection;
440 std::string path;
441
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000442 if (sensnum == reservedSensorNumber)
443 {
444 return ipmi::responseInvalidFieldRequest();
445 }
446
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700447 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700448 if (status)
449 {
James Feist0cd014a2019-04-08 15:04:33 -0700450 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700451 }
452
453 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700454 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700455 {
James Feist0cd014a2019-04-08 15:04:33 -0700456 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700457 }
458 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
459
460 if (sensorObject == sensorMap.end() ||
461 sensorObject->second.find("Value") == sensorObject->second.end())
462 {
James Feist0cd014a2019-04-08 15:04:33 -0700463 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700464 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700465 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700466 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700467
Yong Li1f2eb5e2019-05-23 14:07:17 +0800468 double max = 0;
469 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700470 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700471
472 int16_t mValue = 0;
473 int16_t bValue = 0;
474 int8_t rExp = 0;
475 int8_t bExp = 0;
476 bool bSigned = false;
477
478 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
479 {
James Feist0cd014a2019-04-08 15:04:33 -0700480 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700481 }
482
James Feist0cd014a2019-04-08 15:04:33 -0700483 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700484 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700485 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700486 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700487 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800488 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700489 bool notReading = std::isnan(reading);
490
491 if (!notReading)
492 {
493 auto availableObject =
494 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
495 if (availableObject != sensorMap.end())
496 {
497 auto findAvailable = availableObject->second.find("Available");
498 if (findAvailable != availableObject->second.end())
499 {
500 bool* available = std::get_if<bool>(&(findAvailable->second));
501 if (available && !(*available))
502 {
503 notReading = true;
504 }
505 }
506 }
507 }
508
509 if (notReading)
510 {
511 operation |= static_cast<uint8_t>(
512 IPMISensorReadingByte2::readingStateUnavailable);
513 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700514
Josh Lehan06aa21a2020-10-28 21:59:06 -0700515 int byteValue;
516 if (bSigned)
517 {
518 byteValue = static_cast<int>(static_cast<int8_t>(value));
519 }
520 else
521 {
522 byteValue = static_cast<int>(static_cast<uint8_t>(value));
523 }
524
525 // Keep stats on the reading just obtained, even if it is "NaN"
526 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
527 {
528 // This is the first reading, show the coefficients
529 double step = (max - min) / 255.0;
530 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
531 << ": Range min=" << min << " max=" << max
532 << ", step=" << step
533 << ", Coefficients mValue=" << static_cast<int>(mValue)
534 << " rExp=" << static_cast<int>(rExp)
535 << " bValue=" << static_cast<int>(bValue)
536 << " bExp=" << static_cast<int>(bExp)
537 << " bSigned=" << static_cast<int>(bSigned) << "\n";
538 };
539
James Feist0cd014a2019-04-08 15:04:33 -0700540 uint8_t thresholds = 0;
541
542 auto warningObject =
543 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
544 if (warningObject != sensorMap.end())
545 {
546 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
547 auto alarmLow = warningObject->second.find("WarningAlarmLow");
548 if (alarmHigh != warningObject->second.end())
549 {
550 if (std::get<bool>(alarmHigh->second))
551 {
552 thresholds |= static_cast<uint8_t>(
553 IPMISensorReadingByte3::upperNonCritical);
554 }
555 }
556 if (alarmLow != warningObject->second.end())
557 {
558 if (std::get<bool>(alarmLow->second))
559 {
560 thresholds |= static_cast<uint8_t>(
561 IPMISensorReadingByte3::lowerNonCritical);
562 }
563 }
564 }
565
566 auto criticalObject =
567 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
568 if (criticalObject != sensorMap.end())
569 {
570 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
571 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
572 if (alarmHigh != criticalObject->second.end())
573 {
574 if (std::get<bool>(alarmHigh->second))
575 {
576 thresholds |=
577 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
578 }
579 }
580 if (alarmLow != criticalObject->second.end())
581 {
582 if (std::get<bool>(alarmLow->second))
583 {
584 thresholds |=
585 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
586 }
587 }
588 }
589
590 // no discrete as of today so optional byte is never returned
591 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700592}
593
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000594/** @brief implements the Set Sensor threshold command
595 * @param sensorNumber - sensor number
596 * @param lowerNonCriticalThreshMask
597 * @param lowerCriticalThreshMask
598 * @param lowerNonRecovThreshMask
599 * @param upperNonCriticalThreshMask
600 * @param upperCriticalThreshMask
601 * @param upperNonRecovThreshMask
602 * @param reserved
603 * @param lowerNonCritical - lower non-critical threshold
604 * @param lowerCritical - Lower critical threshold
605 * @param lowerNonRecoverable - Lower non recovarable threshold
606 * @param upperNonCritical - Upper non-critical threshold
607 * @param upperCritical - Upper critical
608 * @param upperNonRecoverable - Upper Non-recoverable
609 *
610 * @returns IPMI completion code
611 */
612ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700613 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
614 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
615 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
616 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
617 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
618 uint8_t upperNonCritical, uint8_t upperCritical,
619 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000621 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700622
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000623 if (sensorNum == reservedSensorNumber)
624 {
625 return ipmi::responseInvalidFieldRequest();
626 }
627
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000628 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 }
632
633 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000634 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000636 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700637 }
638
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 // if none of the threshold mask are set, nothing to do
640 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
641 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
642 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700643 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000644 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700645 }
646
647 std::string connection;
648 std::string path;
649
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700650 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700651 if (status)
652 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000653 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700654 }
655 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700656 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700657 {
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 double max = 0;
662 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700663 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700664
665 int16_t mValue = 0;
666 int16_t bValue = 0;
667 int8_t rExp = 0;
668 int8_t bExp = 0;
669 bool bSigned = false;
670
671 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
672 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000673 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700674 }
675
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700676 // store a vector of property name, value to set, and interface
677 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
678
679 // define the indexes of the tuple
680 constexpr uint8_t propertyName = 0;
681 constexpr uint8_t thresholdValue = 1;
682 constexpr uint8_t interface = 2;
683 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000684 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700685 {
686 auto findThreshold =
687 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
688 if (findThreshold == sensorMap.end())
689 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000690 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700691 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000692 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700693 {
694 auto findLower = findThreshold->second.find("CriticalLow");
695 if (findLower == findThreshold->second.end())
696 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000697 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700698 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000699 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700700 findThreshold->first);
701 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000702 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700703 {
704 auto findUpper = findThreshold->second.find("CriticalHigh");
705 if (findUpper == findThreshold->second.end())
706 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000707 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700708 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000709 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700710 findThreshold->first);
711 }
712 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000713 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700714 {
715 auto findThreshold =
716 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
717 if (findThreshold == sensorMap.end())
718 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000719 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700720 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000721 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700722 {
723 auto findLower = findThreshold->second.find("WarningLow");
724 if (findLower == findThreshold->second.end())
725 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000726 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700727 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000728 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700729 findThreshold->first);
730 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000731 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732 {
733 auto findUpper = findThreshold->second.find("WarningHigh");
734 if (findUpper == findThreshold->second.end())
735 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000736 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700737 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000738 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700739 findThreshold->first);
740 }
741 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700742 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700743 {
744 // from section 36.3 in the IPMI Spec, assume all linear
745 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800746 (bValue * std::pow(10.0, bExp))) *
747 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700748 setDbusProperty(
749 *getSdBus(), connection, path, std::get<interface>(property),
750 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700751 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000752 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700753}
754
James Feistfcd2d3a2020-05-28 10:38:15 -0700755IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700756{
James Feist902c4c52019-04-16 14:51:31 -0700757 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700758 auto warningInterface =
759 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
760 auto criticalInterface =
761 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
762
763 if ((warningInterface != sensorMap.end()) ||
764 (criticalInterface != sensorMap.end()))
765 {
766 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
767
768 if (sensorPair == sensorMap.end())
769 {
770 // should not have been able to find a sensor not implementing
771 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700772 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700773 }
774
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800775 double max = 0;
776 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700777 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700778
779 int16_t mValue = 0;
780 int16_t bValue = 0;
781 int8_t rExp = 0;
782 int8_t bExp = 0;
783 bool bSigned = false;
784
785 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
786 {
James Feist902c4c52019-04-16 14:51:31 -0700787 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700788 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700789 if (warningInterface != sensorMap.end())
790 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700791 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700792
793 auto warningHigh = warningMap.find("WarningHigh");
794 auto warningLow = warningMap.find("WarningLow");
795
796 if (warningHigh != warningMap.end())
797 {
James Feist902c4c52019-04-16 14:51:31 -0700798
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700799 double value =
800 std::visit(VariantToDoubleVisitor(), warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700801 if (std::isfinite(value))
802 {
803 resp.warningHigh = scaleIPMIValueFromDouble(
804 value, mValue, rExp, bValue, bExp, bSigned);
805 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700806 }
807 if (warningLow != warningMap.end())
808 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700809 double value =
810 std::visit(VariantToDoubleVisitor(), warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700811 if (std::isfinite(value))
812 {
813 resp.warningLow = scaleIPMIValueFromDouble(
814 value, mValue, rExp, bValue, bExp, bSigned);
815 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700816 }
817 }
818 if (criticalInterface != sensorMap.end())
819 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700820 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700821
822 auto criticalHigh = criticalMap.find("CriticalHigh");
823 auto criticalLow = criticalMap.find("CriticalLow");
824
825 if (criticalHigh != criticalMap.end())
826 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700827 double value =
828 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700829 if (std::isfinite(value))
830 {
831 resp.criticalHigh = scaleIPMIValueFromDouble(
832 value, mValue, rExp, bValue, bExp, bSigned);
833 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700834 }
835 if (criticalLow != criticalMap.end())
836 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700837 double value =
838 std::visit(VariantToDoubleVisitor(), criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700839 if (std::isfinite(value))
840 {
841 resp.criticalLow = scaleIPMIValueFromDouble(
842 value, mValue, rExp, bValue, bExp, bSigned);
843 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700844 }
845 }
846 }
James Feist902c4c52019-04-16 14:51:31 -0700847 return resp;
848}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700849
James Feist902c4c52019-04-16 14:51:31 -0700850ipmi::RspType<uint8_t, // readable
851 uint8_t, // lowerNCrit
852 uint8_t, // lowerCrit
853 uint8_t, // lowerNrecoverable
854 uint8_t, // upperNC
855 uint8_t, // upperCrit
856 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700857 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700858{
859 std::string connection;
860 std::string path;
861
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000862 if (sensorNumber == reservedSensorNumber)
863 {
864 return ipmi::responseInvalidFieldRequest();
865 }
866
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700867 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700868 if (status)
869 {
870 return ipmi::response(status);
871 }
872
873 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700874 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700875 {
876 return ipmi::responseResponseError();
877 }
878
879 IPMIThresholds thresholdData;
880 try
881 {
882 thresholdData = getIPMIThresholds(sensorMap);
883 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500884 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700885 {
886 return ipmi::responseResponseError();
887 }
888
889 uint8_t readable = 0;
890 uint8_t lowerNC = 0;
891 uint8_t lowerCritical = 0;
892 uint8_t lowerNonRecoverable = 0;
893 uint8_t upperNC = 0;
894 uint8_t upperCritical = 0;
895 uint8_t upperNonRecoverable = 0;
896
897 if (thresholdData.warningHigh)
898 {
899 readable |=
900 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
901 upperNC = *thresholdData.warningHigh;
902 }
903 if (thresholdData.warningLow)
904 {
905 readable |=
906 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
907 lowerNC = *thresholdData.warningLow;
908 }
909
910 if (thresholdData.criticalHigh)
911 {
912 readable |=
913 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
914 upperCritical = *thresholdData.criticalHigh;
915 }
916 if (thresholdData.criticalLow)
917 {
918 readable |=
919 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
920 lowerCritical = *thresholdData.criticalLow;
921 }
922
923 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
924 lowerNonRecoverable, upperNC, upperCritical,
925 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700926}
927
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000928/** @brief implements the get Sensor event enable command
929 * @param sensorNumber - sensor number
930 *
931 * @returns IPMI completion code plus response data
932 * - enabled - Sensor Event messages
933 * - assertionEnabledLsb - Assertion event messages
934 * - assertionEnabledMsb - Assertion event messages
935 * - deassertionEnabledLsb - Deassertion event messages
936 * - deassertionEnabledMsb - Deassertion event messages
937 */
938
939ipmi::RspType<uint8_t, // enabled
940 uint8_t, // assertionEnabledLsb
941 uint8_t, // assertionEnabledMsb
942 uint8_t, // deassertionEnabledLsb
943 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700944 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700945{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700946 std::string connection;
947 std::string path;
948
Patrick Venturea41714c2019-09-25 16:59:41 -0700949 uint8_t enabled = 0;
950 uint8_t assertionEnabledLsb = 0;
951 uint8_t assertionEnabledMsb = 0;
952 uint8_t deassertionEnabledLsb = 0;
953 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000954
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000955 if (sensorNum == reservedSensorNumber)
956 {
957 return ipmi::responseInvalidFieldRequest();
958 }
959
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700960 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 if (status)
962 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000963 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700964 }
965
966 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700967 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700968 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000969 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700970 }
971
972 auto warningInterface =
973 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
974 auto criticalInterface =
975 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700976 if ((warningInterface != sensorMap.end()) ||
977 (criticalInterface != sensorMap.end()))
978 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000979 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700980 IPMISensorEventEnableByte2::sensorScanningEnable);
981 if (warningInterface != sensorMap.end())
982 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700983 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700984
985 auto warningHigh = warningMap.find("WarningHigh");
986 auto warningLow = warningMap.find("WarningLow");
987 if (warningHigh != warningMap.end())
988 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700989 double value =
990 std::visit(VariantToDoubleVisitor(), warningHigh->second);
991 if (std::isfinite(value))
992 {
993 assertionEnabledLsb |=
994 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
995 upperNonCriticalGoingHigh);
996 deassertionEnabledLsb |=
997 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
998 upperNonCriticalGoingLow);
999 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001000 }
1001 if (warningLow != warningMap.end())
1002 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001003 double value =
1004 std::visit(VariantToDoubleVisitor(), warningLow->second);
1005 if (std::isfinite(value))
1006 {
1007 assertionEnabledLsb |=
1008 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1009 lowerNonCriticalGoingLow);
1010 deassertionEnabledLsb |=
1011 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1012 lowerNonCriticalGoingHigh);
1013 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001014 }
1015 }
1016 if (criticalInterface != sensorMap.end())
1017 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001018 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001019
1020 auto criticalHigh = criticalMap.find("CriticalHigh");
1021 auto criticalLow = criticalMap.find("CriticalLow");
1022
1023 if (criticalHigh != criticalMap.end())
1024 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001025 double value =
1026 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
1027 if (std::isfinite(value))
1028 {
1029 assertionEnabledMsb |=
1030 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1031 upperCriticalGoingHigh);
1032 deassertionEnabledMsb |= static_cast<uint8_t>(
1033 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1034 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001035 }
1036 if (criticalLow != criticalMap.end())
1037 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001038 double value =
1039 std::visit(VariantToDoubleVisitor(), criticalLow->second);
1040 if (std::isfinite(value))
1041 {
1042 assertionEnabledLsb |= static_cast<uint8_t>(
1043 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1044 deassertionEnabledLsb |=
1045 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1046 lowerCriticalGoingHigh);
1047 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001048 }
1049 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001050 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001051
1052 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1053 assertionEnabledMsb, deassertionEnabledLsb,
1054 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001055}
1056
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001057/** @brief implements the get Sensor event status command
1058 * @param sensorNumber - sensor number, FFh = reserved
1059 *
1060 * @returns IPMI completion code plus response data
1061 * - sensorEventStatus - Sensor Event messages state
1062 * - assertions - Assertion event messages
1063 * - deassertions - Deassertion event messages
1064 */
1065ipmi::RspType<uint8_t, // sensorEventStatus
1066 std::bitset<16>, // assertions
1067 std::bitset<16> // deassertion
1068 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001069 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001070{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001071 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001072 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001073 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001074 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075
1076 std::string connection;
1077 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001078 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001079 if (status)
1080 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001081 phosphor::logging::log<phosphor::logging::level::ERR>(
1082 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1083 phosphor::logging::entry("SENSOR=%d", sensorNum));
1084 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085 }
1086
1087 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001088 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001090 phosphor::logging::log<phosphor::logging::level::ERR>(
1091 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1092 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1093 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001095 auto warningInterface =
1096 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1097 auto criticalInterface =
1098 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1099
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001100 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001101 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1102
James Feist392786a2019-03-19 13:36:10 -07001103 std::optional<bool> criticalDeassertHigh =
1104 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1105 std::optional<bool> criticalDeassertLow =
1106 thresholdDeassertMap[path]["CriticalAlarmLow"];
1107 std::optional<bool> warningDeassertHigh =
1108 thresholdDeassertMap[path]["WarningAlarmHigh"];
1109 std::optional<bool> warningDeassertLow =
1110 thresholdDeassertMap[path]["WarningAlarmLow"];
1111
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001112 std::bitset<16> assertions = 0;
1113 std::bitset<16> deassertions = 0;
1114
James Feist392786a2019-03-19 13:36:10 -07001115 if (criticalDeassertHigh && !*criticalDeassertHigh)
1116 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001117 deassertions.set(static_cast<size_t>(
1118 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001119 }
1120 if (criticalDeassertLow && !*criticalDeassertLow)
1121 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001122 deassertions.set(static_cast<size_t>(
1123 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001124 }
1125 if (warningDeassertHigh && !*warningDeassertHigh)
1126 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001127 deassertions.set(static_cast<size_t>(
1128 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001129 }
1130 if (warningDeassertLow && !*warningDeassertLow)
1131 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001132 deassertions.set(static_cast<size_t>(
1133 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001134 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135 if ((warningInterface != sensorMap.end()) ||
1136 (criticalInterface != sensorMap.end()))
1137 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001138 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139 IPMISensorEventEnableByte2::eventMessagesEnable);
1140 if (warningInterface != sensorMap.end())
1141 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001142 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143
1144 auto warningHigh = warningMap.find("WarningAlarmHigh");
1145 auto warningLow = warningMap.find("WarningAlarmLow");
1146 auto warningHighAlarm = false;
1147 auto warningLowAlarm = false;
1148
1149 if (warningHigh != warningMap.end())
1150 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001151 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152 }
1153 if (warningLow != warningMap.end())
1154 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001155 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001156 }
1157 if (warningHighAlarm)
1158 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001159 assertions.set(
1160 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1161 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001162 }
1163 if (warningLowAlarm)
1164 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001165 assertions.set(
1166 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1167 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 }
1169 }
1170 if (criticalInterface != sensorMap.end())
1171 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001172 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173
1174 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1175 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1176 auto criticalHighAlarm = false;
1177 auto criticalLowAlarm = false;
1178
1179 if (criticalHigh != criticalMap.end())
1180 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001181 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001182 }
1183 if (criticalLow != criticalMap.end())
1184 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001185 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001186 }
1187 if (criticalHighAlarm)
1188 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001189 assertions.set(
1190 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1191 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001192 }
1193 if (criticalLowAlarm)
1194 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001195 assertions.set(static_cast<size_t>(
1196 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001197 }
1198 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001199 }
1200
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001201 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001202}
1203
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001204static inline uint16_t getNumberOfSensors(void)
1205{
1206 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1207 : sensorTree.size();
1208}
1209
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001210static int getSensorDataRecord(ipmi::Context::ptr ctx,
1211 std::vector<uint8_t>& recordData,
1212 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001213{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001214 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001215 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1216 if (ret != ipmi::ccSuccess)
1217 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001218 phosphor::logging::log<phosphor::logging::level::ERR>(
1219 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001220 return GENERAL_ERROR;
1221 }
1222
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001223 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001224 ipmi::storage::type12Count +
1225 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001226 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001227 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001228 recordID = lastRecord;
1229 }
1230 if (recordID > lastRecord)
1231 {
1232 phosphor::logging::log<phosphor::logging::level::ERR>(
1233 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001234 return GENERAL_ERROR;
1235 }
1236
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001237 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001238 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001239 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001240 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001241
1242 if (fruIndex >= type12End)
1243 {
1244 // NM discovery SDR
1245 size_t nmDiscoveryIndex = fruIndex - type12End;
1246 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1247 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001248 phosphor::logging::log<phosphor::logging::level::ERR>(
1249 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001250 return GENERAL_ERROR;
1251 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001252 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001253 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001254 }
1255 else if (fruIndex >= fruCount)
1256 {
1257 // handle type 12 hardcoded records
1258 size_t type12Index = fruIndex - fruCount;
1259 if (type12Index >= ipmi::storage::type12Count)
1260 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001261 phosphor::logging::log<phosphor::logging::level::ERR>(
1262 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001263 return GENERAL_ERROR;
1264 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001265 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001266 }
1267 else
1268 {
1269 // handle fru records
1270 get_sdr::SensorDataFruRecord data;
1271 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1272 if (ret != IPMI_CC_OK)
1273 {
1274 return GENERAL_ERROR;
1275 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001276 data.header.record_id_msb = recordID >> 8;
1277 data.header.record_id_lsb = recordID & 0xFF;
1278 recordData.insert(recordData.end(), (uint8_t*)&data,
1279 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001280 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001281
1282 return 0;
1283 }
1284
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001285 // Perform a incremental scan of the SDR Record ID's and translate the
1286 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1287 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1288 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1289 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001290 std::string connection;
1291 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001292 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001293 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001294 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001295 // LUN 0 has one reserved sensor number. Compensate here by adding one
1296 // to the record ID
1297 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001298 ctx->lun = 1;
1299 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001300 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001301 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001302 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1303 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1304 // rules governing its use.
1305 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001306 ctx->lun = 3;
1307 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001308
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001309 auto status = getSensorConnection(
1310 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001311 if (status)
1312 {
1313 phosphor::logging::log<phosphor::logging::level::ERR>(
1314 "getSensorDataRecord: getSensorConnection error");
1315 return GENERAL_ERROR;
1316 }
1317 SensorMap sensorMap;
1318 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1319 sensorMapUpdatePeriod))
1320 {
1321 phosphor::logging::log<phosphor::logging::level::ERR>(
1322 "getSensorDataRecord: getSensorMap error");
1323 return GENERAL_ERROR;
1324 }
1325 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001326 // Return an error on LUN 2 assingments, and any sensor number beyond the
1327 // range of LUN 3
1328 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1329 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001330 {
1331 phosphor::logging::log<phosphor::logging::level::ERR>(
1332 "getSensorDataRecord: invalidSensorNumber");
1333 return GENERAL_ERROR;
1334 }
1335 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1336 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1337
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001338 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1339 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001340 {
1341 phosphor::logging::log<phosphor::logging::level::ERR>(
1342 "getSensorDataRecord: sensor record mismatch");
1343 return GENERAL_ERROR;
1344 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001345 get_sdr::SensorDataFullRecord record = {0};
1346
1347 get_sdr::header::set_record_id(
1348 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1349
1350 record.header.sdr_version = ipmiSdrVersion;
1351 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1352 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1353 sizeof(get_sdr::SensorDataRecordHeader);
1354 record.key.owner_id = 0x20;
1355 record.key.owner_lun = lun;
1356 record.key.sensor_number = sensornumber;
1357
1358 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1359 record.body.sensor_type = getSensorTypeFromPath(path);
1360 std::string type = getSensorTypeStringFromPath(path);
1361 auto typeCstr = type.c_str();
1362 auto findUnits = sensorUnits.find(typeCstr);
1363 if (findUnits != sensorUnits.end())
1364 {
1365 record.body.sensor_units_2_base =
1366 static_cast<uint8_t>(findUnits->second);
1367 } // else default 0x0 unspecified
1368
1369 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1370
1371 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1372 if (sensorObject == sensorMap.end())
1373 {
1374 phosphor::logging::log<phosphor::logging::level::ERR>(
1375 "getSensorDataRecord: sensorObject error");
1376 return GENERAL_ERROR;
1377 }
1378
1379 uint8_t entityId = 0;
1380 uint8_t entityInstance = 0x01;
1381
1382 // follow the association chain to get the parent board's entityid and
1383 // entityInstance
1384 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1385
1386 record.body.entity_id = entityId;
1387 record.body.entity_instance = entityInstance;
1388
1389 auto maxObject = sensorObject->second.find("MaxValue");
1390 auto minObject = sensorObject->second.find("MinValue");
1391
1392 // If min and/or max are left unpopulated,
1393 // then default to what a signed byte would be, namely (-128,127) range.
1394 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1395 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1396 if (maxObject != sensorObject->second.end())
1397 {
1398 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1399 }
1400
1401 if (minObject != sensorObject->second.end())
1402 {
1403 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1404 }
1405
1406 int16_t mValue = 0;
1407 int8_t rExp = 0;
1408 int16_t bValue = 0;
1409 int8_t bExp = 0;
1410 bool bSigned = false;
1411
1412 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1413 {
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 "getSensorDataRecord: getSensorAttributes error");
1416 return GENERAL_ERROR;
1417 }
1418
1419 // The record.body is a struct SensorDataFullRecordBody
1420 // from sensorhandler.hpp in phosphor-ipmi-host.
1421 // The meaning of these bits appears to come from
1422 // table 43.1 of the IPMI spec.
1423 // The above 5 sensor attributes are stuffed in as follows:
1424 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1425 // Byte 22-24 are for other purposes
1426 // Byte 25 = MMMMMMMM = LSB of M
1427 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1428 // Byte 27 = BBBBBBBB = LSB of B
1429 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1430 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1431 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1432
1433 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1434 record.body.m_lsb = mValue & 0xFF;
1435
1436 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1437 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1438
1439 // move the smallest bit of the MSB into place (bit 9)
1440 // the MSbs are bits 7:8 in m_msb_and_tolerance
1441 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1442
1443 record.body.b_lsb = bValue & 0xFF;
1444
1445 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1446 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1447
1448 // move the smallest bit of the MSB into place (bit 9)
1449 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1450 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1451
1452 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1453 uint8_t rExpBits = rExp & 0x07;
1454
1455 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1456 uint8_t bExpBits = bExp & 0x07;
1457
1458 // move rExp and bExp into place
1459 record.body.r_b_exponents =
1460 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1461
1462 // Set the analog reading byte interpretation accordingly
1463 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1464
1465 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1466 // These seem redundant, but derivable from the above 5 attributes
1467 // Original comment said "todo fill out rest of units"
1468
1469 // populate sensor name from path
1470 std::string name;
1471 size_t nameStart = path.rfind("/");
1472 if (nameStart != std::string::npos)
1473 {
1474 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1475 }
1476
1477 std::replace(name.begin(), name.end(), '_', ' ');
1478 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1479 {
1480 // try to not truncate by replacing common words
1481 constexpr std::array<std::pair<const char*, const char*>, 2>
1482 replaceWords = {std::make_pair("Output", "Out"),
1483 std::make_pair("Input", "In")};
1484 for (const auto& [find, replace] : replaceWords)
1485 {
1486 boost::replace_all(name, find, replace);
1487 }
1488
1489 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1490 }
1491 record.body.id_string_info = name.size();
1492 std::strncpy(record.body.id_string, name.c_str(),
1493 sizeof(record.body.id_string));
1494
Josh Lehan06aa21a2020-10-28 21:59:06 -07001495 // Remember the sensor name, as determined for this sensor number
1496 details::sdrStatsTable.updateName(sensornumber, name);
1497
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001498 IPMIThresholds thresholdData;
1499 try
1500 {
1501 thresholdData = getIPMIThresholds(sensorMap);
1502 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001503 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001504 {
1505 phosphor::logging::log<phosphor::logging::level::ERR>(
1506 "getSensorDataRecord: getIPMIThresholds error");
1507 return GENERAL_ERROR;
1508 }
1509
1510 if (thresholdData.criticalHigh)
1511 {
1512 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1513 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1514 IPMISensorEventEnableThresholds::criticalThreshold);
1515 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1516 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1517 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1518 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1519 record.body.discrete_reading_setting_mask[0] |=
1520 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1521 }
1522 if (thresholdData.warningHigh)
1523 {
1524 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1525 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1526 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1527 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1528 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1529 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1530 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1531 record.body.discrete_reading_setting_mask[0] |=
1532 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1533 }
1534 if (thresholdData.criticalLow)
1535 {
1536 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1537 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1538 IPMISensorEventEnableThresholds::criticalThreshold);
1539 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1540 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1541 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1542 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1543 record.body.discrete_reading_setting_mask[0] |=
1544 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1545 }
1546 if (thresholdData.warningLow)
1547 {
1548 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1549 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1550 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1551 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1552 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1553 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1554 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1555 record.body.discrete_reading_setting_mask[0] |=
1556 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1557 }
1558
1559 // everything that is readable is setable
1560 record.body.discrete_reading_setting_mask[1] =
1561 record.body.discrete_reading_setting_mask[0];
1562 recordData.insert(recordData.end(), (uint8_t*)&record,
1563 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001564 return 0;
1565}
1566
1567/** @brief implements the get SDR Info command
1568 * @param count - Operation
1569 *
1570 * @returns IPMI completion code plus response data
1571 * - sdrCount - sensor/SDR count
1572 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1573 */
1574static ipmi::RspType<uint8_t, // respcount
1575 uint8_t, // dynamic population flags
1576 uint32_t // last time a sensor was added
1577 >
1578 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1579 std::optional<uint8_t> count)
1580{
1581 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001582 uint16_t recordID = 0;
1583 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001584 // Sensors are dynamically allocated, and there is at least one LUN
1585 uint8_t lunsAndDynamicPopulation = 0x80;
1586 constexpr uint8_t getSdrCount = 0x01;
1587 constexpr uint8_t getSensorCount = 0x00;
1588
1589 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1590 {
1591 return ipmi::responseResponseError();
1592 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001593 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001594 if (count.value_or(0) == getSdrCount)
1595 {
1596 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001597 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001598 {
1599 get_sdr::SensorDataRecordHeader* hdr =
1600 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001601 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001602 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1603 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001604 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001605 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001606 record.data());
1607 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001608 {
1609 sdrCount++;
1610 }
1611 }
1612 }
1613 }
1614 else if (count.value_or(0) == getSensorCount)
1615 {
1616 // Return the number of sensors attached to the LUN
1617 if ((ctx->lun == 0) && (numSensors > 0))
1618 {
1619 sdrCount =
1620 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1621 }
1622 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1623 {
1624 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1625 ? maxSensorsPerLUN
1626 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1627 }
1628 else if (ctx->lun == 3)
1629 {
1630 if (numSensors <= maxIPMISensors)
1631 {
1632 sdrCount =
1633 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1634 }
1635 else
1636 {
1637 // error
1638 throw std::out_of_range(
1639 "Maximum number of IPMI sensors exceeded.");
1640 }
1641 }
1642 }
1643 else
1644 {
1645 return ipmi::responseInvalidFieldRequest();
1646 }
1647
1648 // Get Sensor count. This returns the number of sensors
1649 if (numSensors > 0)
1650 {
1651 lunsAndDynamicPopulation |= 1;
1652 }
1653 if (numSensors > maxSensorsPerLUN)
1654 {
1655 lunsAndDynamicPopulation |= 2;
1656 }
1657 if (numSensors >= (maxSensorsPerLUN * 2))
1658 {
1659 lunsAndDynamicPopulation |= 8;
1660 }
1661 if (numSensors > maxIPMISensors)
1662 {
1663 // error
1664 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1665 }
1666
1667 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1668 sdrLastAdd);
1669}
1670
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001671/* end sensor commands */
1672
1673/* storage commands */
1674
James Feist74c50c62019-08-14 14:18:41 -07001675ipmi::RspType<uint8_t, // sdr version
1676 uint16_t, // record count
1677 uint16_t, // free space
1678 uint32_t, // most recent addition
1679 uint32_t, // most recent erase
1680 uint8_t // operationSupport
1681 >
James Feist25690252019-12-23 12:25:49 -08001682 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001683{
James Feist74c50c62019-08-14 14:18:41 -07001684 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001685 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001686 {
James Feist74c50c62019-08-14 14:18:41 -07001687 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001688 }
1689
James Feist74c50c62019-08-14 14:18:41 -07001690 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001691 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001692 if (ret != ipmi::ccSuccess)
1693 {
1694 return ipmi::response(ret);
1695 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001696
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301697 uint16_t recordCount = getNumberOfSensors() + fruCount +
1698 ipmi::storage::type12Count +
1699 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001700
James Feist74c50c62019-08-14 14:18:41 -07001701 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001702 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001703
1704 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001705 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001706 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001707 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001708 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1709 unspecifiedFreeSpace, sdrLastAdd,
1710 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001711}
1712
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001713/** @brief implements the get SDR allocation info command
1714 *
1715 * @returns IPMI completion code plus response data
1716 * - allocUnits - Number of possible allocation units
1717 * - allocUnitSize - Allocation unit size in bytes.
1718 * - allocUnitFree - Number of free allocation units
1719 * - allocUnitLargestFree - Largest free block in allocation units
1720 * - maxRecordSize - Maximum record size in allocation units.
1721 */
1722ipmi::RspType<uint16_t, // allocUnits
1723 uint16_t, // allocUnitSize
1724 uint16_t, // allocUnitFree
1725 uint16_t, // allocUnitLargestFree
1726 uint8_t // maxRecordSize
1727 >
1728 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001729{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001730 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001731 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001732
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001733 constexpr uint16_t allocUnitFree = 0;
1734 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001735 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001736 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001737
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001738 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1739 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001740}
1741
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001742/** @brief implements the reserve SDR command
1743 * @returns IPMI completion code plus response data
1744 * - sdrReservationID
1745 */
1746ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001747{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001748 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001749 if (sdrReservationID == 0)
1750 {
1751 sdrReservationID++;
1752 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001753
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001754 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001755}
1756
James Feistb49a98a2019-04-16 13:48:09 -07001757ipmi::RspType<uint16_t, // next record ID
1758 std::vector<uint8_t> // payload
1759 >
James Feist25690252019-12-23 12:25:49 -08001760 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1761 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001762{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001763 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001764 // reservation required for partial reads with non zero offset into
1765 // record
James Feistb49a98a2019-04-16 13:48:09 -07001766 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001767 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001768 phosphor::logging::log<phosphor::logging::level::ERR>(
1769 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001770 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001771 }
James Feist25690252019-12-23 12:25:49 -08001772 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001773 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001774 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001775 phosphor::logging::log<phosphor::logging::level::ERR>(
1776 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001777 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001778 }
1779
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001780 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001781 ipmi::storage::type12Count +
1782 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001783 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1784
1785 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001786 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001787 phosphor::logging::log<phosphor::logging::level::ERR>(
1788 "ipmiStorageGetSDR: getSensorSubtree error");
1789 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001790 }
1791
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001792 std::vector<uint8_t> record;
1793 if (getSensorDataRecord(ctx, record, recordID))
1794 {
1795 phosphor::logging::log<phosphor::logging::level::ERR>(
1796 "ipmiStorageGetSDR: fail to get SDR");
1797 return ipmi::responseInvalidFieldRequest();
1798 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001799 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001800 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001801 if (!hdr)
1802 {
1803 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001804 "ipmiStorageGetSDR: record header is null");
1805 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001806 }
1807
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001808 size_t sdrLength =
1809 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1810 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001811 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001812 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001813 }
1814
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001815 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001816 if (!respStart)
1817 {
1818 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001819 "ipmiStorageGetSDR: record is null");
1820 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001821 }
James Feistb49a98a2019-04-16 13:48:09 -07001822 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001823
James Feistb49a98a2019-04-16 13:48:09 -07001824 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001825}
1826/* end storage commands */
1827
1828void registerSensorFunctions()
1829{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001830 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001831 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1832 ipmi::sensor_event::cmdPlatformEvent,
1833 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001834
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001835 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001836 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1837 ipmi::sensor_event::cmdGetSensorReading,
1838 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001839
1840 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001841 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1842 ipmi::sensor_event::cmdGetSensorThreshold,
1843 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001844
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001845 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001846 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1847 ipmi::sensor_event::cmdSetSensorThreshold,
1848 ipmi::Privilege::Operator,
1849 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001850
1851 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001852 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1853 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001854 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001855
1856 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001857 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1858 ipmi::sensor_event::cmdGetSensorEventStatus,
1859 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001860
1861 // register all storage commands for both Sensor and Storage command
1862 // versions
1863
1864 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001865 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1866 ipmi::storage::cmdGetSdrRepositoryInfo,
1867 ipmi::Privilege::User,
1868 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001869
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001870 // <Get Device SDR Info>
1871 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1872 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1873 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1874
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001875 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001876 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1877 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1878 ipmi::Privilege::User,
1879 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001880
1881 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001882 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1883 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001884 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001885
Vernon Mauery98bbf692019-09-16 11:14:59 -07001886 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1887 ipmi::storage::cmdReserveSdrRepository,
1888 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001889
1890 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001891 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1892 ipmi::sensor_event::cmdGetDeviceSdr,
1893 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001894
Vernon Mauery98bbf692019-09-16 11:14:59 -07001895 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1896 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1897 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001898}
1899} // namespace ipmi