blob: 73b74ccad51d39db02bd45781cc3d12faff4f293 [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 }
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);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700383 // Refer to IPMI Spec Table 32: SEL Event Records
384 generatorID = (ctx->channel << 12) // Channel
385 | (0x0 << 10) // Reserved
386 | (0x0 << 8) // 0x0 for sys-soft ID
387 | ((sysgeneratorID << 1) | 0x1);
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700388 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000389 else
390 {
391
392 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
393 eventData2, eventData3);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700394 // Refer to IPMI Spec Table 32: SEL Event Records
395 generatorID = (ctx->channel << 12) // Channel
396 | (0x0 << 10) // Reserved
397 | ((ctx->lun & 0x3) << 8) // Lun
398 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000399 }
400
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700401 if (!p.fullyUnpacked())
402 {
403 return ipmi::responseReqDataLenInvalid();
404 }
405
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000406 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
407 if (evmRev != 0x04)
408 {
409 return ipmi::responseInvalidFieldRequest();
410 }
411 if ((sensorType > 0x2C) && (sensorType < 0xC0))
412 {
413 return ipmi::responseInvalidFieldRequest();
414 }
415
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700416 // Send this request to the Redfish hooks to log it as a Redfish message
417 // instead. There is no need to add it to the SEL, so just return success.
418 intel_oem::ipmi::sel::checkRedfishHooks(
419 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
420 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700421
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700422 if (((generatorID & 0xFF) >> 1) == meId && sensorNum == meSensorNum &&
423 eventData2 && eventData3)
James Feist7aaf3fe2019-06-25 11:52:11 -0700424 {
425 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
426 }
427
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700428 return ipmi::responseSuccess();
429}
430
James Feist0cd014a2019-04-08 15:04:33 -0700431ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700432 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700433{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700434 std::string connection;
435 std::string path;
436
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000437 if (sensnum == reservedSensorNumber)
438 {
439 return ipmi::responseInvalidFieldRequest();
440 }
441
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700442 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700443 if (status)
444 {
James Feist0cd014a2019-04-08 15:04:33 -0700445 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700446 }
447
448 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700449 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700450 {
James Feist0cd014a2019-04-08 15:04:33 -0700451 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700452 }
453 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
454
455 if (sensorObject == sensorMap.end() ||
456 sensorObject->second.find("Value") == sensorObject->second.end())
457 {
James Feist0cd014a2019-04-08 15:04:33 -0700458 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700459 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700460 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700461 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700462
Yong Li1f2eb5e2019-05-23 14:07:17 +0800463 double max = 0;
464 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700465 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700466
467 int16_t mValue = 0;
468 int16_t bValue = 0;
469 int8_t rExp = 0;
470 int8_t bExp = 0;
471 bool bSigned = false;
472
473 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
474 {
James Feist0cd014a2019-04-08 15:04:33 -0700475 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700476 }
477
James Feist0cd014a2019-04-08 15:04:33 -0700478 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700479 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700480 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700481 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700482 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800483 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700484 bool notReading = std::isnan(reading);
485
486 if (!notReading)
487 {
488 auto availableObject =
489 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
490 if (availableObject != sensorMap.end())
491 {
492 auto findAvailable = availableObject->second.find("Available");
493 if (findAvailable != availableObject->second.end())
494 {
495 bool* available = std::get_if<bool>(&(findAvailable->second));
496 if (available && !(*available))
497 {
498 notReading = true;
499 }
500 }
501 }
502 }
503
504 if (notReading)
505 {
506 operation |= static_cast<uint8_t>(
507 IPMISensorReadingByte2::readingStateUnavailable);
508 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700509
Josh Lehan06aa21a2020-10-28 21:59:06 -0700510 int byteValue;
511 if (bSigned)
512 {
513 byteValue = static_cast<int>(static_cast<int8_t>(value));
514 }
515 else
516 {
517 byteValue = static_cast<int>(static_cast<uint8_t>(value));
518 }
519
520 // Keep stats on the reading just obtained, even if it is "NaN"
521 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
522 {
523 // This is the first reading, show the coefficients
524 double step = (max - min) / 255.0;
525 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
526 << ": Range min=" << min << " max=" << max
527 << ", step=" << step
528 << ", Coefficients mValue=" << static_cast<int>(mValue)
529 << " rExp=" << static_cast<int>(rExp)
530 << " bValue=" << static_cast<int>(bValue)
531 << " bExp=" << static_cast<int>(bExp)
532 << " bSigned=" << static_cast<int>(bSigned) << "\n";
533 };
534
James Feist0cd014a2019-04-08 15:04:33 -0700535 uint8_t thresholds = 0;
536
537 auto warningObject =
538 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
539 if (warningObject != sensorMap.end())
540 {
541 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
542 auto alarmLow = warningObject->second.find("WarningAlarmLow");
543 if (alarmHigh != warningObject->second.end())
544 {
545 if (std::get<bool>(alarmHigh->second))
546 {
547 thresholds |= static_cast<uint8_t>(
548 IPMISensorReadingByte3::upperNonCritical);
549 }
550 }
551 if (alarmLow != warningObject->second.end())
552 {
553 if (std::get<bool>(alarmLow->second))
554 {
555 thresholds |= static_cast<uint8_t>(
556 IPMISensorReadingByte3::lowerNonCritical);
557 }
558 }
559 }
560
561 auto criticalObject =
562 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
563 if (criticalObject != sensorMap.end())
564 {
565 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
566 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
567 if (alarmHigh != criticalObject->second.end())
568 {
569 if (std::get<bool>(alarmHigh->second))
570 {
571 thresholds |=
572 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
573 }
574 }
575 if (alarmLow != criticalObject->second.end())
576 {
577 if (std::get<bool>(alarmLow->second))
578 {
579 thresholds |=
580 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
581 }
582 }
583 }
584
585 // no discrete as of today so optional byte is never returned
586 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700587}
588
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000589/** @brief implements the Set Sensor threshold command
590 * @param sensorNumber - sensor number
591 * @param lowerNonCriticalThreshMask
592 * @param lowerCriticalThreshMask
593 * @param lowerNonRecovThreshMask
594 * @param upperNonCriticalThreshMask
595 * @param upperCriticalThreshMask
596 * @param upperNonRecovThreshMask
597 * @param reserved
598 * @param lowerNonCritical - lower non-critical threshold
599 * @param lowerCritical - Lower critical threshold
600 * @param lowerNonRecoverable - Lower non recovarable threshold
601 * @param upperNonCritical - Upper non-critical threshold
602 * @param upperCritical - Upper critical
603 * @param upperNonRecoverable - Upper Non-recoverable
604 *
605 * @returns IPMI completion code
606 */
607ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700608 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
609 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
610 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
611 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
612 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
613 uint8_t upperNonCritical, uint8_t upperCritical,
614 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700615{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000616 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700617
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000618 if (sensorNum == reservedSensorNumber)
619 {
620 return ipmi::responseInvalidFieldRequest();
621 }
622
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000625 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700626 }
627
628 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000631 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700632 }
633
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000634 // if none of the threshold mask are set, nothing to do
635 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
636 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
637 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700638 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000639 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700640 }
641
642 std::string connection;
643 std::string path;
644
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700645 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700646 if (status)
647 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000648 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700649 }
650 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700651 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700652 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000653 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700654 }
655
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700656 double max = 0;
657 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700658 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700659
660 int16_t mValue = 0;
661 int16_t bValue = 0;
662 int8_t rExp = 0;
663 int8_t bExp = 0;
664 bool bSigned = false;
665
666 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
667 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000668 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700669 }
670
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700671 // store a vector of property name, value to set, and interface
672 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
673
674 // define the indexes of the tuple
675 constexpr uint8_t propertyName = 0;
676 constexpr uint8_t thresholdValue = 1;
677 constexpr uint8_t interface = 2;
678 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000679 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680 {
681 auto findThreshold =
682 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
683 if (findThreshold == sensorMap.end())
684 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000685 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700686 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000687 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700688 {
689 auto findLower = findThreshold->second.find("CriticalLow");
690 if (findLower == 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("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700695 findThreshold->first);
696 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000697 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700698 {
699 auto findUpper = findThreshold->second.find("CriticalHigh");
700 if (findUpper == findThreshold->second.end())
701 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000702 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700703 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000704 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700705 findThreshold->first);
706 }
707 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000708 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700709 {
710 auto findThreshold =
711 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
712 if (findThreshold == sensorMap.end())
713 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000714 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700715 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000716 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700717 {
718 auto findLower = findThreshold->second.find("WarningLow");
719 if (findLower == 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("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700724 findThreshold->first);
725 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000726 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700727 {
728 auto findUpper = findThreshold->second.find("WarningHigh");
729 if (findUpper == findThreshold->second.end())
730 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000731 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000733 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700734 findThreshold->first);
735 }
736 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700737 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700738 {
739 // from section 36.3 in the IPMI Spec, assume all linear
740 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800741 (bValue * std::pow(10.0, bExp))) *
742 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700743 setDbusProperty(
744 *getSdBus(), connection, path, std::get<interface>(property),
745 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700746 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000747 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700748}
749
James Feistfcd2d3a2020-05-28 10:38:15 -0700750IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700751{
James Feist902c4c52019-04-16 14:51:31 -0700752 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700753 auto warningInterface =
754 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
755 auto criticalInterface =
756 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
757
758 if ((warningInterface != sensorMap.end()) ||
759 (criticalInterface != sensorMap.end()))
760 {
761 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
762
763 if (sensorPair == sensorMap.end())
764 {
765 // should not have been able to find a sensor not implementing
766 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700767 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700768 }
769
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800770 double max = 0;
771 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700772 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700773
774 int16_t mValue = 0;
775 int16_t bValue = 0;
776 int8_t rExp = 0;
777 int8_t bExp = 0;
778 bool bSigned = false;
779
780 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
781 {
James Feist902c4c52019-04-16 14:51:31 -0700782 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700783 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700784 if (warningInterface != sensorMap.end())
785 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700786 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700787
788 auto warningHigh = warningMap.find("WarningHigh");
789 auto warningLow = warningMap.find("WarningLow");
790
791 if (warningHigh != warningMap.end())
792 {
James Feist902c4c52019-04-16 14:51:31 -0700793
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700794 double value =
795 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700796 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700797 value, mValue, rExp, bValue, bExp, bSigned);
798 }
799 if (warningLow != warningMap.end())
800 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700801 double value =
802 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700803 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700804 value, mValue, rExp, bValue, bExp, bSigned);
805 }
806 }
807 if (criticalInterface != sensorMap.end())
808 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700809 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700810
811 auto criticalHigh = criticalMap.find("CriticalHigh");
812 auto criticalLow = criticalMap.find("CriticalLow");
813
814 if (criticalHigh != criticalMap.end())
815 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700816 double value =
817 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700818 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700819 value, mValue, rExp, bValue, bExp, bSigned);
820 }
821 if (criticalLow != criticalMap.end())
822 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700823 double value =
824 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700825 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700826 value, mValue, rExp, bValue, bExp, bSigned);
827 }
828 }
829 }
James Feist902c4c52019-04-16 14:51:31 -0700830 return resp;
831}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700832
James Feist902c4c52019-04-16 14:51:31 -0700833ipmi::RspType<uint8_t, // readable
834 uint8_t, // lowerNCrit
835 uint8_t, // lowerCrit
836 uint8_t, // lowerNrecoverable
837 uint8_t, // upperNC
838 uint8_t, // upperCrit
839 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700840 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700841{
842 std::string connection;
843 std::string path;
844
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000845 if (sensorNumber == reservedSensorNumber)
846 {
847 return ipmi::responseInvalidFieldRequest();
848 }
849
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700850 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700851 if (status)
852 {
853 return ipmi::response(status);
854 }
855
856 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700857 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700858 {
859 return ipmi::responseResponseError();
860 }
861
862 IPMIThresholds thresholdData;
863 try
864 {
865 thresholdData = getIPMIThresholds(sensorMap);
866 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500867 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700868 {
869 return ipmi::responseResponseError();
870 }
871
872 uint8_t readable = 0;
873 uint8_t lowerNC = 0;
874 uint8_t lowerCritical = 0;
875 uint8_t lowerNonRecoverable = 0;
876 uint8_t upperNC = 0;
877 uint8_t upperCritical = 0;
878 uint8_t upperNonRecoverable = 0;
879
880 if (thresholdData.warningHigh)
881 {
882 readable |=
883 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
884 upperNC = *thresholdData.warningHigh;
885 }
886 if (thresholdData.warningLow)
887 {
888 readable |=
889 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
890 lowerNC = *thresholdData.warningLow;
891 }
892
893 if (thresholdData.criticalHigh)
894 {
895 readable |=
896 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
897 upperCritical = *thresholdData.criticalHigh;
898 }
899 if (thresholdData.criticalLow)
900 {
901 readable |=
902 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
903 lowerCritical = *thresholdData.criticalLow;
904 }
905
906 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
907 lowerNonRecoverable, upperNC, upperCritical,
908 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700909}
910
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000911/** @brief implements the get Sensor event enable command
912 * @param sensorNumber - sensor number
913 *
914 * @returns IPMI completion code plus response data
915 * - enabled - Sensor Event messages
916 * - assertionEnabledLsb - Assertion event messages
917 * - assertionEnabledMsb - Assertion event messages
918 * - deassertionEnabledLsb - Deassertion event messages
919 * - deassertionEnabledMsb - Deassertion event messages
920 */
921
922ipmi::RspType<uint8_t, // enabled
923 uint8_t, // assertionEnabledLsb
924 uint8_t, // assertionEnabledMsb
925 uint8_t, // deassertionEnabledLsb
926 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700927 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700928{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700929 std::string connection;
930 std::string path;
931
Patrick Venturea41714c2019-09-25 16:59:41 -0700932 uint8_t enabled = 0;
933 uint8_t assertionEnabledLsb = 0;
934 uint8_t assertionEnabledMsb = 0;
935 uint8_t deassertionEnabledLsb = 0;
936 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000937
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000938 if (sensorNum == reservedSensorNumber)
939 {
940 return ipmi::responseInvalidFieldRequest();
941 }
942
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700943 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700944 if (status)
945 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000946 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700947 }
948
949 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700950 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700951 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000952 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700953 }
954
955 auto warningInterface =
956 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
957 auto criticalInterface =
958 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700959 if ((warningInterface != sensorMap.end()) ||
960 (criticalInterface != sensorMap.end()))
961 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000962 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700963 IPMISensorEventEnableByte2::sensorScanningEnable);
964 if (warningInterface != sensorMap.end())
965 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700966 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700967
968 auto warningHigh = warningMap.find("WarningHigh");
969 auto warningLow = warningMap.find("WarningLow");
970 if (warningHigh != warningMap.end())
971 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000972 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700973 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000974 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700975 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
976 }
977 if (warningLow != warningMap.end())
978 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000979 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700980 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000981 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700982 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
983 }
984 }
985 if (criticalInterface != sensorMap.end())
986 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700987 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700988
989 auto criticalHigh = criticalMap.find("CriticalHigh");
990 auto criticalLow = criticalMap.find("CriticalLow");
991
992 if (criticalHigh != criticalMap.end())
993 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000994 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700995 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000996 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700997 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
998 }
999 if (criticalLow != criticalMap.end())
1000 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001001 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001002 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001003 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001004 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1005 }
1006 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001007 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001008
1009 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1010 assertionEnabledMsb, deassertionEnabledLsb,
1011 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001012}
1013
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001014/** @brief implements the get Sensor event status command
1015 * @param sensorNumber - sensor number, FFh = reserved
1016 *
1017 * @returns IPMI completion code plus response data
1018 * - sensorEventStatus - Sensor Event messages state
1019 * - assertions - Assertion event messages
1020 * - deassertions - Deassertion event messages
1021 */
1022ipmi::RspType<uint8_t, // sensorEventStatus
1023 std::bitset<16>, // assertions
1024 std::bitset<16> // deassertion
1025 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001026 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001027{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001028 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001029 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001030 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001031 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001032
1033 std::string connection;
1034 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001035 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001036 if (status)
1037 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001038 phosphor::logging::log<phosphor::logging::level::ERR>(
1039 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1040 phosphor::logging::entry("SENSOR=%d", sensorNum));
1041 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001042 }
1043
1044 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001045 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001046 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001047 phosphor::logging::log<phosphor::logging::level::ERR>(
1048 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1049 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1050 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001051 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001052 auto warningInterface =
1053 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1054 auto criticalInterface =
1055 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1056
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001057 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001058 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1059
James Feist392786a2019-03-19 13:36:10 -07001060 std::optional<bool> criticalDeassertHigh =
1061 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1062 std::optional<bool> criticalDeassertLow =
1063 thresholdDeassertMap[path]["CriticalAlarmLow"];
1064 std::optional<bool> warningDeassertHigh =
1065 thresholdDeassertMap[path]["WarningAlarmHigh"];
1066 std::optional<bool> warningDeassertLow =
1067 thresholdDeassertMap[path]["WarningAlarmLow"];
1068
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001069 std::bitset<16> assertions = 0;
1070 std::bitset<16> deassertions = 0;
1071
James Feist392786a2019-03-19 13:36:10 -07001072 if (criticalDeassertHigh && !*criticalDeassertHigh)
1073 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001074 deassertions.set(static_cast<size_t>(
1075 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001076 }
1077 if (criticalDeassertLow && !*criticalDeassertLow)
1078 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001079 deassertions.set(static_cast<size_t>(
1080 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001081 }
1082 if (warningDeassertHigh && !*warningDeassertHigh)
1083 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001084 deassertions.set(static_cast<size_t>(
1085 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001086 }
1087 if (warningDeassertLow && !*warningDeassertLow)
1088 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001089 deassertions.set(static_cast<size_t>(
1090 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001091 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001092 if ((warningInterface != sensorMap.end()) ||
1093 (criticalInterface != sensorMap.end()))
1094 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001095 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001096 IPMISensorEventEnableByte2::eventMessagesEnable);
1097 if (warningInterface != sensorMap.end())
1098 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001099 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001100
1101 auto warningHigh = warningMap.find("WarningAlarmHigh");
1102 auto warningLow = warningMap.find("WarningAlarmLow");
1103 auto warningHighAlarm = false;
1104 auto warningLowAlarm = false;
1105
1106 if (warningHigh != warningMap.end())
1107 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001108 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001109 }
1110 if (warningLow != warningMap.end())
1111 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001112 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001113 }
1114 if (warningHighAlarm)
1115 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001116 assertions.set(
1117 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1118 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001119 }
1120 if (warningLowAlarm)
1121 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001122 assertions.set(
1123 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1124 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001125 }
1126 }
1127 if (criticalInterface != sensorMap.end())
1128 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001129 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001130
1131 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1132 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1133 auto criticalHighAlarm = false;
1134 auto criticalLowAlarm = false;
1135
1136 if (criticalHigh != criticalMap.end())
1137 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001138 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139 }
1140 if (criticalLow != criticalMap.end())
1141 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001142 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143 }
1144 if (criticalHighAlarm)
1145 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001146 assertions.set(
1147 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1148 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149 }
1150 if (criticalLowAlarm)
1151 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001152 assertions.set(static_cast<size_t>(
1153 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 }
1155 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001156 }
1157
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001158 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159}
1160
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001161static inline uint16_t getNumberOfSensors(void)
1162{
1163 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1164 : sensorTree.size();
1165}
1166
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001167static int getSensorDataRecord(ipmi::Context::ptr ctx,
1168 std::vector<uint8_t>& recordData,
1169 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001170{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001171 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001172 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1173 if (ret != ipmi::ccSuccess)
1174 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001175 phosphor::logging::log<phosphor::logging::level::ERR>(
1176 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001177 return GENERAL_ERROR;
1178 }
1179
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001180 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001181 ipmi::storage::type12Count +
1182 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001183 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001184 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001185 recordID = lastRecord;
1186 }
1187 if (recordID > lastRecord)
1188 {
1189 phosphor::logging::log<phosphor::logging::level::ERR>(
1190 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001191 return GENERAL_ERROR;
1192 }
1193
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001194 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001195 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001196 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001197 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001198
1199 if (fruIndex >= type12End)
1200 {
1201 // NM discovery SDR
1202 size_t nmDiscoveryIndex = fruIndex - type12End;
1203 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1204 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001205 phosphor::logging::log<phosphor::logging::level::ERR>(
1206 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001207 return GENERAL_ERROR;
1208 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001209 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001210 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001211 }
1212 else if (fruIndex >= fruCount)
1213 {
1214 // handle type 12 hardcoded records
1215 size_t type12Index = fruIndex - fruCount;
1216 if (type12Index >= ipmi::storage::type12Count)
1217 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001218 phosphor::logging::log<phosphor::logging::level::ERR>(
1219 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001220 return GENERAL_ERROR;
1221 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001222 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001223 }
1224 else
1225 {
1226 // handle fru records
1227 get_sdr::SensorDataFruRecord data;
1228 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1229 if (ret != IPMI_CC_OK)
1230 {
1231 return GENERAL_ERROR;
1232 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001233 data.header.record_id_msb = recordID >> 8;
1234 data.header.record_id_lsb = recordID & 0xFF;
1235 recordData.insert(recordData.end(), (uint8_t*)&data,
1236 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001237 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001238
1239 return 0;
1240 }
1241
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001242 // Perform a incremental scan of the SDR Record ID's and translate the
1243 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1244 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1245 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1246 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001247 std::string connection;
1248 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001249 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001250 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001251 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001252 // LUN 0 has one reserved sensor number. Compensate here by adding one
1253 // to the record ID
1254 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001255 ctx->lun = 1;
1256 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001257 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001258 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001259 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1260 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1261 // rules governing its use.
1262 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001263 ctx->lun = 3;
1264 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001265
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001266 auto status = getSensorConnection(
1267 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001268 if (status)
1269 {
1270 phosphor::logging::log<phosphor::logging::level::ERR>(
1271 "getSensorDataRecord: getSensorConnection error");
1272 return GENERAL_ERROR;
1273 }
1274 SensorMap sensorMap;
1275 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1276 sensorMapUpdatePeriod))
1277 {
1278 phosphor::logging::log<phosphor::logging::level::ERR>(
1279 "getSensorDataRecord: getSensorMap error");
1280 return GENERAL_ERROR;
1281 }
1282 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001283 // Return an error on LUN 2 assingments, and any sensor number beyond the
1284 // range of LUN 3
1285 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1286 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001287 {
1288 phosphor::logging::log<phosphor::logging::level::ERR>(
1289 "getSensorDataRecord: invalidSensorNumber");
1290 return GENERAL_ERROR;
1291 }
1292 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1293 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1294
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001295 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1296 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001297 {
1298 phosphor::logging::log<phosphor::logging::level::ERR>(
1299 "getSensorDataRecord: sensor record mismatch");
1300 return GENERAL_ERROR;
1301 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001302 get_sdr::SensorDataFullRecord record = {0};
1303
1304 get_sdr::header::set_record_id(
1305 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1306
1307 record.header.sdr_version = ipmiSdrVersion;
1308 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1309 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1310 sizeof(get_sdr::SensorDataRecordHeader);
1311 record.key.owner_id = 0x20;
1312 record.key.owner_lun = lun;
1313 record.key.sensor_number = sensornumber;
1314
1315 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1316 record.body.sensor_type = getSensorTypeFromPath(path);
1317 std::string type = getSensorTypeStringFromPath(path);
1318 auto typeCstr = type.c_str();
1319 auto findUnits = sensorUnits.find(typeCstr);
1320 if (findUnits != sensorUnits.end())
1321 {
1322 record.body.sensor_units_2_base =
1323 static_cast<uint8_t>(findUnits->second);
1324 } // else default 0x0 unspecified
1325
1326 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1327
1328 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1329 if (sensorObject == sensorMap.end())
1330 {
1331 phosphor::logging::log<phosphor::logging::level::ERR>(
1332 "getSensorDataRecord: sensorObject error");
1333 return GENERAL_ERROR;
1334 }
1335
1336 uint8_t entityId = 0;
1337 uint8_t entityInstance = 0x01;
1338
1339 // follow the association chain to get the parent board's entityid and
1340 // entityInstance
1341 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1342
1343 record.body.entity_id = entityId;
1344 record.body.entity_instance = entityInstance;
1345
1346 auto maxObject = sensorObject->second.find("MaxValue");
1347 auto minObject = sensorObject->second.find("MinValue");
1348
1349 // If min and/or max are left unpopulated,
1350 // then default to what a signed byte would be, namely (-128,127) range.
1351 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1352 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1353 if (maxObject != sensorObject->second.end())
1354 {
1355 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1356 }
1357
1358 if (minObject != sensorObject->second.end())
1359 {
1360 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1361 }
1362
1363 int16_t mValue = 0;
1364 int8_t rExp = 0;
1365 int16_t bValue = 0;
1366 int8_t bExp = 0;
1367 bool bSigned = false;
1368
1369 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1370 {
1371 phosphor::logging::log<phosphor::logging::level::ERR>(
1372 "getSensorDataRecord: getSensorAttributes error");
1373 return GENERAL_ERROR;
1374 }
1375
1376 // The record.body is a struct SensorDataFullRecordBody
1377 // from sensorhandler.hpp in phosphor-ipmi-host.
1378 // The meaning of these bits appears to come from
1379 // table 43.1 of the IPMI spec.
1380 // The above 5 sensor attributes are stuffed in as follows:
1381 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1382 // Byte 22-24 are for other purposes
1383 // Byte 25 = MMMMMMMM = LSB of M
1384 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1385 // Byte 27 = BBBBBBBB = LSB of B
1386 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1387 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1388 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1389
1390 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1391 record.body.m_lsb = mValue & 0xFF;
1392
1393 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1394 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1395
1396 // move the smallest bit of the MSB into place (bit 9)
1397 // the MSbs are bits 7:8 in m_msb_and_tolerance
1398 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1399
1400 record.body.b_lsb = bValue & 0xFF;
1401
1402 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1403 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1404
1405 // move the smallest bit of the MSB into place (bit 9)
1406 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1407 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1408
1409 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1410 uint8_t rExpBits = rExp & 0x07;
1411
1412 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1413 uint8_t bExpBits = bExp & 0x07;
1414
1415 // move rExp and bExp into place
1416 record.body.r_b_exponents =
1417 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1418
1419 // Set the analog reading byte interpretation accordingly
1420 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1421
1422 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1423 // These seem redundant, but derivable from the above 5 attributes
1424 // Original comment said "todo fill out rest of units"
1425
1426 // populate sensor name from path
1427 std::string name;
1428 size_t nameStart = path.rfind("/");
1429 if (nameStart != std::string::npos)
1430 {
1431 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1432 }
1433
1434 std::replace(name.begin(), name.end(), '_', ' ');
1435 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1436 {
1437 // try to not truncate by replacing common words
1438 constexpr std::array<std::pair<const char*, const char*>, 2>
1439 replaceWords = {std::make_pair("Output", "Out"),
1440 std::make_pair("Input", "In")};
1441 for (const auto& [find, replace] : replaceWords)
1442 {
1443 boost::replace_all(name, find, replace);
1444 }
1445
1446 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1447 }
1448 record.body.id_string_info = name.size();
1449 std::strncpy(record.body.id_string, name.c_str(),
1450 sizeof(record.body.id_string));
1451
Josh Lehan06aa21a2020-10-28 21:59:06 -07001452 // Remember the sensor name, as determined for this sensor number
1453 details::sdrStatsTable.updateName(sensornumber, name);
1454
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001455 IPMIThresholds thresholdData;
1456 try
1457 {
1458 thresholdData = getIPMIThresholds(sensorMap);
1459 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001460 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001461 {
1462 phosphor::logging::log<phosphor::logging::level::ERR>(
1463 "getSensorDataRecord: getIPMIThresholds error");
1464 return GENERAL_ERROR;
1465 }
1466
1467 if (thresholdData.criticalHigh)
1468 {
1469 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1470 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1471 IPMISensorEventEnableThresholds::criticalThreshold);
1472 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1473 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1474 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1475 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1476 record.body.discrete_reading_setting_mask[0] |=
1477 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1478 }
1479 if (thresholdData.warningHigh)
1480 {
1481 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1482 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1483 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1484 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1485 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1486 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1487 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1488 record.body.discrete_reading_setting_mask[0] |=
1489 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1490 }
1491 if (thresholdData.criticalLow)
1492 {
1493 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1494 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1495 IPMISensorEventEnableThresholds::criticalThreshold);
1496 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1497 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1498 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1499 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1500 record.body.discrete_reading_setting_mask[0] |=
1501 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1502 }
1503 if (thresholdData.warningLow)
1504 {
1505 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1506 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1507 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1508 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1509 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1510 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1511 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1512 record.body.discrete_reading_setting_mask[0] |=
1513 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1514 }
1515
1516 // everything that is readable is setable
1517 record.body.discrete_reading_setting_mask[1] =
1518 record.body.discrete_reading_setting_mask[0];
1519 recordData.insert(recordData.end(), (uint8_t*)&record,
1520 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001521 return 0;
1522}
1523
1524/** @brief implements the get SDR Info command
1525 * @param count - Operation
1526 *
1527 * @returns IPMI completion code plus response data
1528 * - sdrCount - sensor/SDR count
1529 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1530 */
1531static ipmi::RspType<uint8_t, // respcount
1532 uint8_t, // dynamic population flags
1533 uint32_t // last time a sensor was added
1534 >
1535 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1536 std::optional<uint8_t> count)
1537{
1538 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001539 uint16_t recordID = 0;
1540 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001541 // Sensors are dynamically allocated, and there is at least one LUN
1542 uint8_t lunsAndDynamicPopulation = 0x80;
1543 constexpr uint8_t getSdrCount = 0x01;
1544 constexpr uint8_t getSensorCount = 0x00;
1545
1546 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1547 {
1548 return ipmi::responseResponseError();
1549 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001550 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001551 if (count.value_or(0) == getSdrCount)
1552 {
1553 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001554 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001555 {
1556 get_sdr::SensorDataRecordHeader* hdr =
1557 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001558 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001559 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1560 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001561 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001562 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001563 record.data());
1564 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001565 {
1566 sdrCount++;
1567 }
1568 }
1569 }
1570 }
1571 else if (count.value_or(0) == getSensorCount)
1572 {
1573 // Return the number of sensors attached to the LUN
1574 if ((ctx->lun == 0) && (numSensors > 0))
1575 {
1576 sdrCount =
1577 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1578 }
1579 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1580 {
1581 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1582 ? maxSensorsPerLUN
1583 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1584 }
1585 else if (ctx->lun == 3)
1586 {
1587 if (numSensors <= maxIPMISensors)
1588 {
1589 sdrCount =
1590 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1591 }
1592 else
1593 {
1594 // error
1595 throw std::out_of_range(
1596 "Maximum number of IPMI sensors exceeded.");
1597 }
1598 }
1599 }
1600 else
1601 {
1602 return ipmi::responseInvalidFieldRequest();
1603 }
1604
1605 // Get Sensor count. This returns the number of sensors
1606 if (numSensors > 0)
1607 {
1608 lunsAndDynamicPopulation |= 1;
1609 }
1610 if (numSensors > maxSensorsPerLUN)
1611 {
1612 lunsAndDynamicPopulation |= 2;
1613 }
1614 if (numSensors >= (maxSensorsPerLUN * 2))
1615 {
1616 lunsAndDynamicPopulation |= 8;
1617 }
1618 if (numSensors > maxIPMISensors)
1619 {
1620 // error
1621 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1622 }
1623
1624 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1625 sdrLastAdd);
1626}
1627
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001628/* end sensor commands */
1629
1630/* storage commands */
1631
James Feist74c50c62019-08-14 14:18:41 -07001632ipmi::RspType<uint8_t, // sdr version
1633 uint16_t, // record count
1634 uint16_t, // free space
1635 uint32_t, // most recent addition
1636 uint32_t, // most recent erase
1637 uint8_t // operationSupport
1638 >
James Feist25690252019-12-23 12:25:49 -08001639 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001640{
James Feist74c50c62019-08-14 14:18:41 -07001641 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001642 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001643 {
James Feist74c50c62019-08-14 14:18:41 -07001644 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001645 }
1646
James Feist74c50c62019-08-14 14:18:41 -07001647 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001648 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001649 if (ret != ipmi::ccSuccess)
1650 {
1651 return ipmi::response(ret);
1652 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001653
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301654 uint16_t recordCount = getNumberOfSensors() + fruCount +
1655 ipmi::storage::type12Count +
1656 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001657
James Feist74c50c62019-08-14 14:18:41 -07001658 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001659 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001660
1661 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001662 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001663 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001664 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001665 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1666 unspecifiedFreeSpace, sdrLastAdd,
1667 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001668}
1669
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001670/** @brief implements the get SDR allocation info command
1671 *
1672 * @returns IPMI completion code plus response data
1673 * - allocUnits - Number of possible allocation units
1674 * - allocUnitSize - Allocation unit size in bytes.
1675 * - allocUnitFree - Number of free allocation units
1676 * - allocUnitLargestFree - Largest free block in allocation units
1677 * - maxRecordSize - Maximum record size in allocation units.
1678 */
1679ipmi::RspType<uint16_t, // allocUnits
1680 uint16_t, // allocUnitSize
1681 uint16_t, // allocUnitFree
1682 uint16_t, // allocUnitLargestFree
1683 uint8_t // maxRecordSize
1684 >
1685 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001686{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001687 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001688 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001689
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001690 constexpr uint16_t allocUnitFree = 0;
1691 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001692 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001693 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001695 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1696 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001697}
1698
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001699/** @brief implements the reserve SDR command
1700 * @returns IPMI completion code plus response data
1701 * - sdrReservationID
1702 */
1703ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001704{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001705 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001706 if (sdrReservationID == 0)
1707 {
1708 sdrReservationID++;
1709 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001710
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001711 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001712}
1713
James Feistb49a98a2019-04-16 13:48:09 -07001714ipmi::RspType<uint16_t, // next record ID
1715 std::vector<uint8_t> // payload
1716 >
James Feist25690252019-12-23 12:25:49 -08001717 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1718 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001719{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001720 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001721 // reservation required for partial reads with non zero offset into
1722 // record
James Feistb49a98a2019-04-16 13:48:09 -07001723 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001724 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001725 phosphor::logging::log<phosphor::logging::level::ERR>(
1726 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001727 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001728 }
James Feist25690252019-12-23 12:25:49 -08001729 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001730 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001731 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001732 phosphor::logging::log<phosphor::logging::level::ERR>(
1733 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001734 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001735 }
1736
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001737 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001738 ipmi::storage::type12Count +
1739 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001740 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1741
1742 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001743 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001744 phosphor::logging::log<phosphor::logging::level::ERR>(
1745 "ipmiStorageGetSDR: getSensorSubtree error");
1746 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001747 }
1748
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001749 std::vector<uint8_t> record;
1750 if (getSensorDataRecord(ctx, record, recordID))
1751 {
1752 phosphor::logging::log<phosphor::logging::level::ERR>(
1753 "ipmiStorageGetSDR: fail to get SDR");
1754 return ipmi::responseInvalidFieldRequest();
1755 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001756 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001757 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001758 if (!hdr)
1759 {
1760 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001761 "ipmiStorageGetSDR: record header is null");
1762 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001763 }
1764
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001765 size_t sdrLength =
1766 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1767 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001768 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001769 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001770 }
1771
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001772 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001773 if (!respStart)
1774 {
1775 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001776 "ipmiStorageGetSDR: record is null");
1777 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001778 }
James Feistb49a98a2019-04-16 13:48:09 -07001779 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001780
James Feistb49a98a2019-04-16 13:48:09 -07001781 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001782}
1783/* end storage commands */
1784
1785void registerSensorFunctions()
1786{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001787 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001788 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1789 ipmi::sensor_event::cmdPlatformEvent,
1790 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001791
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001792 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001793 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1794 ipmi::sensor_event::cmdGetSensorReading,
1795 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001796
1797 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001798 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1799 ipmi::sensor_event::cmdGetSensorThreshold,
1800 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001801
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001802 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001803 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1804 ipmi::sensor_event::cmdSetSensorThreshold,
1805 ipmi::Privilege::Operator,
1806 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001807
1808 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001809 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1810 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001811 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001812
1813 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001814 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1815 ipmi::sensor_event::cmdGetSensorEventStatus,
1816 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001817
1818 // register all storage commands for both Sensor and Storage command
1819 // versions
1820
1821 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001822 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1823 ipmi::storage::cmdGetSdrRepositoryInfo,
1824 ipmi::Privilege::User,
1825 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001826
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001827 // <Get Device SDR Info>
1828 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1829 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1830 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1831
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001832 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001833 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1834 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1835 ipmi::Privilege::User,
1836 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001837
1838 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001839 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1840 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001841 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001842
Vernon Mauery98bbf692019-09-16 11:14:59 -07001843 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1844 ipmi::storage::cmdReserveSdrRepository,
1845 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001846
1847 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001848 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1849 ipmi::sensor_event::cmdGetDeviceSdr,
1850 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001851
Vernon Mauery98bbf692019-09-16 11:14:59 -07001852 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1853 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1854 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001855}
1856} // namespace ipmi