blob: 91a83b8a014119dac1b0653bc7ce1d871d8f1cbf [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);
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);
James Feist902c4c52019-04-16 14:51:31 -0700801 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700802 value, mValue, rExp, bValue, bExp, bSigned);
803 }
804 if (warningLow != warningMap.end())
805 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700806 double value =
807 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700808 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700809 value, mValue, rExp, bValue, bExp, bSigned);
810 }
811 }
812 if (criticalInterface != sensorMap.end())
813 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700814 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700815
816 auto criticalHigh = criticalMap.find("CriticalHigh");
817 auto criticalLow = criticalMap.find("CriticalLow");
818
819 if (criticalHigh != criticalMap.end())
820 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700821 double value =
822 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700823 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700824 value, mValue, rExp, bValue, bExp, bSigned);
825 }
826 if (criticalLow != criticalMap.end())
827 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700828 double value =
829 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700830 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700831 value, mValue, rExp, bValue, bExp, bSigned);
832 }
833 }
834 }
James Feist902c4c52019-04-16 14:51:31 -0700835 return resp;
836}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700837
James Feist902c4c52019-04-16 14:51:31 -0700838ipmi::RspType<uint8_t, // readable
839 uint8_t, // lowerNCrit
840 uint8_t, // lowerCrit
841 uint8_t, // lowerNrecoverable
842 uint8_t, // upperNC
843 uint8_t, // upperCrit
844 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700845 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700846{
847 std::string connection;
848 std::string path;
849
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000850 if (sensorNumber == reservedSensorNumber)
851 {
852 return ipmi::responseInvalidFieldRequest();
853 }
854
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700855 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700856 if (status)
857 {
858 return ipmi::response(status);
859 }
860
861 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700862 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700863 {
864 return ipmi::responseResponseError();
865 }
866
867 IPMIThresholds thresholdData;
868 try
869 {
870 thresholdData = getIPMIThresholds(sensorMap);
871 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500872 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700873 {
874 return ipmi::responseResponseError();
875 }
876
877 uint8_t readable = 0;
878 uint8_t lowerNC = 0;
879 uint8_t lowerCritical = 0;
880 uint8_t lowerNonRecoverable = 0;
881 uint8_t upperNC = 0;
882 uint8_t upperCritical = 0;
883 uint8_t upperNonRecoverable = 0;
884
885 if (thresholdData.warningHigh)
886 {
887 readable |=
888 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
889 upperNC = *thresholdData.warningHigh;
890 }
891 if (thresholdData.warningLow)
892 {
893 readable |=
894 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
895 lowerNC = *thresholdData.warningLow;
896 }
897
898 if (thresholdData.criticalHigh)
899 {
900 readable |=
901 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
902 upperCritical = *thresholdData.criticalHigh;
903 }
904 if (thresholdData.criticalLow)
905 {
906 readable |=
907 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
908 lowerCritical = *thresholdData.criticalLow;
909 }
910
911 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
912 lowerNonRecoverable, upperNC, upperCritical,
913 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700914}
915
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000916/** @brief implements the get Sensor event enable command
917 * @param sensorNumber - sensor number
918 *
919 * @returns IPMI completion code plus response data
920 * - enabled - Sensor Event messages
921 * - assertionEnabledLsb - Assertion event messages
922 * - assertionEnabledMsb - Assertion event messages
923 * - deassertionEnabledLsb - Deassertion event messages
924 * - deassertionEnabledMsb - Deassertion event messages
925 */
926
927ipmi::RspType<uint8_t, // enabled
928 uint8_t, // assertionEnabledLsb
929 uint8_t, // assertionEnabledMsb
930 uint8_t, // deassertionEnabledLsb
931 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700932 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700933{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700934 std::string connection;
935 std::string path;
936
Patrick Venturea41714c2019-09-25 16:59:41 -0700937 uint8_t enabled = 0;
938 uint8_t assertionEnabledLsb = 0;
939 uint8_t assertionEnabledMsb = 0;
940 uint8_t deassertionEnabledLsb = 0;
941 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000942
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000943 if (sensorNum == reservedSensorNumber)
944 {
945 return ipmi::responseInvalidFieldRequest();
946 }
947
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700948 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700949 if (status)
950 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000951 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700952 }
953
954 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700955 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700956 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000957 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700958 }
959
960 auto warningInterface =
961 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
962 auto criticalInterface =
963 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700964 if ((warningInterface != sensorMap.end()) ||
965 (criticalInterface != sensorMap.end()))
966 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000967 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700968 IPMISensorEventEnableByte2::sensorScanningEnable);
969 if (warningInterface != sensorMap.end())
970 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700971 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700972
973 auto warningHigh = warningMap.find("WarningHigh");
974 auto warningLow = warningMap.find("WarningLow");
975 if (warningHigh != warningMap.end())
976 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000977 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700978 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000979 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700980 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
981 }
982 if (warningLow != warningMap.end())
983 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000984 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700985 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000986 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700987 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
988 }
989 }
990 if (criticalInterface != sensorMap.end())
991 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700992 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700993
994 auto criticalHigh = criticalMap.find("CriticalHigh");
995 auto criticalLow = criticalMap.find("CriticalLow");
996
997 if (criticalHigh != criticalMap.end())
998 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000999 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001000 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001001 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001002 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1003 }
1004 if (criticalLow != criticalMap.end())
1005 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001006 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001007 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001008 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001009 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1010 }
1011 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001012 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001013
1014 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1015 assertionEnabledMsb, deassertionEnabledLsb,
1016 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001017}
1018
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001019/** @brief implements the get Sensor event status command
1020 * @param sensorNumber - sensor number, FFh = reserved
1021 *
1022 * @returns IPMI completion code plus response data
1023 * - sensorEventStatus - Sensor Event messages state
1024 * - assertions - Assertion event messages
1025 * - deassertions - Deassertion event messages
1026 */
1027ipmi::RspType<uint8_t, // sensorEventStatus
1028 std::bitset<16>, // assertions
1029 std::bitset<16> // deassertion
1030 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001031 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001032{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001033 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001034 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001035 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001036 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001037
1038 std::string connection;
1039 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001040 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001041 if (status)
1042 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001043 phosphor::logging::log<phosphor::logging::level::ERR>(
1044 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1045 phosphor::logging::entry("SENSOR=%d", sensorNum));
1046 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001047 }
1048
1049 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001050 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001051 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001052 phosphor::logging::log<phosphor::logging::level::ERR>(
1053 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1054 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1055 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001056 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001057 auto warningInterface =
1058 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1059 auto criticalInterface =
1060 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1061
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001062 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001063 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1064
James Feist392786a2019-03-19 13:36:10 -07001065 std::optional<bool> criticalDeassertHigh =
1066 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1067 std::optional<bool> criticalDeassertLow =
1068 thresholdDeassertMap[path]["CriticalAlarmLow"];
1069 std::optional<bool> warningDeassertHigh =
1070 thresholdDeassertMap[path]["WarningAlarmHigh"];
1071 std::optional<bool> warningDeassertLow =
1072 thresholdDeassertMap[path]["WarningAlarmLow"];
1073
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001074 std::bitset<16> assertions = 0;
1075 std::bitset<16> deassertions = 0;
1076
James Feist392786a2019-03-19 13:36:10 -07001077 if (criticalDeassertHigh && !*criticalDeassertHigh)
1078 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001079 deassertions.set(static_cast<size_t>(
1080 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001081 }
1082 if (criticalDeassertLow && !*criticalDeassertLow)
1083 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001084 deassertions.set(static_cast<size_t>(
1085 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001086 }
1087 if (warningDeassertHigh && !*warningDeassertHigh)
1088 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001089 deassertions.set(static_cast<size_t>(
1090 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001091 }
1092 if (warningDeassertLow && !*warningDeassertLow)
1093 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001094 deassertions.set(static_cast<size_t>(
1095 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001096 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001097 if ((warningInterface != sensorMap.end()) ||
1098 (criticalInterface != sensorMap.end()))
1099 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001100 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001101 IPMISensorEventEnableByte2::eventMessagesEnable);
1102 if (warningInterface != sensorMap.end())
1103 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001104 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001105
1106 auto warningHigh = warningMap.find("WarningAlarmHigh");
1107 auto warningLow = warningMap.find("WarningAlarmLow");
1108 auto warningHighAlarm = false;
1109 auto warningLowAlarm = false;
1110
1111 if (warningHigh != warningMap.end())
1112 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001113 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001114 }
1115 if (warningLow != warningMap.end())
1116 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001117 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118 }
1119 if (warningHighAlarm)
1120 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001121 assertions.set(
1122 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1123 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001124 }
1125 if (warningLowAlarm)
1126 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001127 assertions.set(
1128 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1129 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001130 }
1131 }
1132 if (criticalInterface != sensorMap.end())
1133 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001134 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001135
1136 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1137 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1138 auto criticalHighAlarm = false;
1139 auto criticalLowAlarm = false;
1140
1141 if (criticalHigh != criticalMap.end())
1142 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001143 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144 }
1145 if (criticalLow != criticalMap.end())
1146 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001147 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148 }
1149 if (criticalHighAlarm)
1150 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001151 assertions.set(
1152 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1153 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 }
1155 if (criticalLowAlarm)
1156 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001157 assertions.set(static_cast<size_t>(
1158 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159 }
1160 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001161 }
1162
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001163 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001164}
1165
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001166static inline uint16_t getNumberOfSensors(void)
1167{
1168 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1169 : sensorTree.size();
1170}
1171
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001172static int getSensorDataRecord(ipmi::Context::ptr ctx,
1173 std::vector<uint8_t>& recordData,
1174 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001175{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001176 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001177 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1178 if (ret != ipmi::ccSuccess)
1179 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001180 phosphor::logging::log<phosphor::logging::level::ERR>(
1181 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001182 return GENERAL_ERROR;
1183 }
1184
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001185 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001186 ipmi::storage::type12Count +
1187 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001188 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001189 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001190 recordID = lastRecord;
1191 }
1192 if (recordID > lastRecord)
1193 {
1194 phosphor::logging::log<phosphor::logging::level::ERR>(
1195 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001196 return GENERAL_ERROR;
1197 }
1198
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001199 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001200 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001201 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001202 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001203
1204 if (fruIndex >= type12End)
1205 {
1206 // NM discovery SDR
1207 size_t nmDiscoveryIndex = fruIndex - type12End;
1208 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1209 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001210 phosphor::logging::log<phosphor::logging::level::ERR>(
1211 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001212 return GENERAL_ERROR;
1213 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001214 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001215 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001216 }
1217 else if (fruIndex >= fruCount)
1218 {
1219 // handle type 12 hardcoded records
1220 size_t type12Index = fruIndex - fruCount;
1221 if (type12Index >= ipmi::storage::type12Count)
1222 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001223 phosphor::logging::log<phosphor::logging::level::ERR>(
1224 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001225 return GENERAL_ERROR;
1226 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001227 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001228 }
1229 else
1230 {
1231 // handle fru records
1232 get_sdr::SensorDataFruRecord data;
1233 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1234 if (ret != IPMI_CC_OK)
1235 {
1236 return GENERAL_ERROR;
1237 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001238 data.header.record_id_msb = recordID >> 8;
1239 data.header.record_id_lsb = recordID & 0xFF;
1240 recordData.insert(recordData.end(), (uint8_t*)&data,
1241 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001242 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001243
1244 return 0;
1245 }
1246
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001247 // Perform a incremental scan of the SDR Record ID's and translate the
1248 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1249 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1250 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1251 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001252 std::string connection;
1253 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001254 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001255 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001256 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001257 // LUN 0 has one reserved sensor number. Compensate here by adding one
1258 // to the record ID
1259 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001260 ctx->lun = 1;
1261 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001262 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001263 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001264 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1265 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1266 // rules governing its use.
1267 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001268 ctx->lun = 3;
1269 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001270
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001271 auto status = getSensorConnection(
1272 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001273 if (status)
1274 {
1275 phosphor::logging::log<phosphor::logging::level::ERR>(
1276 "getSensorDataRecord: getSensorConnection error");
1277 return GENERAL_ERROR;
1278 }
1279 SensorMap sensorMap;
1280 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1281 sensorMapUpdatePeriod))
1282 {
1283 phosphor::logging::log<phosphor::logging::level::ERR>(
1284 "getSensorDataRecord: getSensorMap error");
1285 return GENERAL_ERROR;
1286 }
1287 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001288 // Return an error on LUN 2 assingments, and any sensor number beyond the
1289 // range of LUN 3
1290 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1291 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001292 {
1293 phosphor::logging::log<phosphor::logging::level::ERR>(
1294 "getSensorDataRecord: invalidSensorNumber");
1295 return GENERAL_ERROR;
1296 }
1297 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1298 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1299
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001300 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1301 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001302 {
1303 phosphor::logging::log<phosphor::logging::level::ERR>(
1304 "getSensorDataRecord: sensor record mismatch");
1305 return GENERAL_ERROR;
1306 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001307 get_sdr::SensorDataFullRecord record = {0};
1308
1309 get_sdr::header::set_record_id(
1310 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1311
1312 record.header.sdr_version = ipmiSdrVersion;
1313 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1314 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1315 sizeof(get_sdr::SensorDataRecordHeader);
1316 record.key.owner_id = 0x20;
1317 record.key.owner_lun = lun;
1318 record.key.sensor_number = sensornumber;
1319
1320 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1321 record.body.sensor_type = getSensorTypeFromPath(path);
1322 std::string type = getSensorTypeStringFromPath(path);
1323 auto typeCstr = type.c_str();
1324 auto findUnits = sensorUnits.find(typeCstr);
1325 if (findUnits != sensorUnits.end())
1326 {
1327 record.body.sensor_units_2_base =
1328 static_cast<uint8_t>(findUnits->second);
1329 } // else default 0x0 unspecified
1330
1331 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1332
1333 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1334 if (sensorObject == sensorMap.end())
1335 {
1336 phosphor::logging::log<phosphor::logging::level::ERR>(
1337 "getSensorDataRecord: sensorObject error");
1338 return GENERAL_ERROR;
1339 }
1340
1341 uint8_t entityId = 0;
1342 uint8_t entityInstance = 0x01;
1343
1344 // follow the association chain to get the parent board's entityid and
1345 // entityInstance
1346 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1347
1348 record.body.entity_id = entityId;
1349 record.body.entity_instance = entityInstance;
1350
1351 auto maxObject = sensorObject->second.find("MaxValue");
1352 auto minObject = sensorObject->second.find("MinValue");
1353
1354 // If min and/or max are left unpopulated,
1355 // then default to what a signed byte would be, namely (-128,127) range.
1356 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1357 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1358 if (maxObject != sensorObject->second.end())
1359 {
1360 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1361 }
1362
1363 if (minObject != sensorObject->second.end())
1364 {
1365 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1366 }
1367
1368 int16_t mValue = 0;
1369 int8_t rExp = 0;
1370 int16_t bValue = 0;
1371 int8_t bExp = 0;
1372 bool bSigned = false;
1373
1374 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1375 {
1376 phosphor::logging::log<phosphor::logging::level::ERR>(
1377 "getSensorDataRecord: getSensorAttributes error");
1378 return GENERAL_ERROR;
1379 }
1380
1381 // The record.body is a struct SensorDataFullRecordBody
1382 // from sensorhandler.hpp in phosphor-ipmi-host.
1383 // The meaning of these bits appears to come from
1384 // table 43.1 of the IPMI spec.
1385 // The above 5 sensor attributes are stuffed in as follows:
1386 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1387 // Byte 22-24 are for other purposes
1388 // Byte 25 = MMMMMMMM = LSB of M
1389 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1390 // Byte 27 = BBBBBBBB = LSB of B
1391 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1392 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1393 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1394
1395 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1396 record.body.m_lsb = mValue & 0xFF;
1397
1398 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1399 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1400
1401 // move the smallest bit of the MSB into place (bit 9)
1402 // the MSbs are bits 7:8 in m_msb_and_tolerance
1403 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1404
1405 record.body.b_lsb = bValue & 0xFF;
1406
1407 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1408 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1409
1410 // move the smallest bit of the MSB into place (bit 9)
1411 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1412 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1413
1414 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1415 uint8_t rExpBits = rExp & 0x07;
1416
1417 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1418 uint8_t bExpBits = bExp & 0x07;
1419
1420 // move rExp and bExp into place
1421 record.body.r_b_exponents =
1422 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1423
1424 // Set the analog reading byte interpretation accordingly
1425 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1426
1427 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1428 // These seem redundant, but derivable from the above 5 attributes
1429 // Original comment said "todo fill out rest of units"
1430
1431 // populate sensor name from path
1432 std::string name;
1433 size_t nameStart = path.rfind("/");
1434 if (nameStart != std::string::npos)
1435 {
1436 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1437 }
1438
1439 std::replace(name.begin(), name.end(), '_', ' ');
1440 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1441 {
1442 // try to not truncate by replacing common words
1443 constexpr std::array<std::pair<const char*, const char*>, 2>
1444 replaceWords = {std::make_pair("Output", "Out"),
1445 std::make_pair("Input", "In")};
1446 for (const auto& [find, replace] : replaceWords)
1447 {
1448 boost::replace_all(name, find, replace);
1449 }
1450
1451 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1452 }
1453 record.body.id_string_info = name.size();
1454 std::strncpy(record.body.id_string, name.c_str(),
1455 sizeof(record.body.id_string));
1456
Josh Lehan06aa21a2020-10-28 21:59:06 -07001457 // Remember the sensor name, as determined for this sensor number
1458 details::sdrStatsTable.updateName(sensornumber, name);
1459
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001460 IPMIThresholds thresholdData;
1461 try
1462 {
1463 thresholdData = getIPMIThresholds(sensorMap);
1464 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001465 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001466 {
1467 phosphor::logging::log<phosphor::logging::level::ERR>(
1468 "getSensorDataRecord: getIPMIThresholds error");
1469 return GENERAL_ERROR;
1470 }
1471
1472 if (thresholdData.criticalHigh)
1473 {
1474 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1475 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1476 IPMISensorEventEnableThresholds::criticalThreshold);
1477 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1478 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1479 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1480 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1481 record.body.discrete_reading_setting_mask[0] |=
1482 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1483 }
1484 if (thresholdData.warningHigh)
1485 {
1486 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1487 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1488 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1489 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1490 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1491 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1492 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1493 record.body.discrete_reading_setting_mask[0] |=
1494 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1495 }
1496 if (thresholdData.criticalLow)
1497 {
1498 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1499 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1500 IPMISensorEventEnableThresholds::criticalThreshold);
1501 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1502 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1503 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1504 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1505 record.body.discrete_reading_setting_mask[0] |=
1506 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1507 }
1508 if (thresholdData.warningLow)
1509 {
1510 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1511 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1512 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1513 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1514 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1515 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1516 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1517 record.body.discrete_reading_setting_mask[0] |=
1518 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1519 }
1520
1521 // everything that is readable is setable
1522 record.body.discrete_reading_setting_mask[1] =
1523 record.body.discrete_reading_setting_mask[0];
1524 recordData.insert(recordData.end(), (uint8_t*)&record,
1525 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001526 return 0;
1527}
1528
1529/** @brief implements the get SDR Info command
1530 * @param count - Operation
1531 *
1532 * @returns IPMI completion code plus response data
1533 * - sdrCount - sensor/SDR count
1534 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1535 */
1536static ipmi::RspType<uint8_t, // respcount
1537 uint8_t, // dynamic population flags
1538 uint32_t // last time a sensor was added
1539 >
1540 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1541 std::optional<uint8_t> count)
1542{
1543 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001544 uint16_t recordID = 0;
1545 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001546 // Sensors are dynamically allocated, and there is at least one LUN
1547 uint8_t lunsAndDynamicPopulation = 0x80;
1548 constexpr uint8_t getSdrCount = 0x01;
1549 constexpr uint8_t getSensorCount = 0x00;
1550
1551 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1552 {
1553 return ipmi::responseResponseError();
1554 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001555 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001556 if (count.value_or(0) == getSdrCount)
1557 {
1558 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001559 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001560 {
1561 get_sdr::SensorDataRecordHeader* hdr =
1562 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001563 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001564 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1565 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001566 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001567 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001568 record.data());
1569 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001570 {
1571 sdrCount++;
1572 }
1573 }
1574 }
1575 }
1576 else if (count.value_or(0) == getSensorCount)
1577 {
1578 // Return the number of sensors attached to the LUN
1579 if ((ctx->lun == 0) && (numSensors > 0))
1580 {
1581 sdrCount =
1582 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1583 }
1584 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1585 {
1586 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1587 ? maxSensorsPerLUN
1588 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1589 }
1590 else if (ctx->lun == 3)
1591 {
1592 if (numSensors <= maxIPMISensors)
1593 {
1594 sdrCount =
1595 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1596 }
1597 else
1598 {
1599 // error
1600 throw std::out_of_range(
1601 "Maximum number of IPMI sensors exceeded.");
1602 }
1603 }
1604 }
1605 else
1606 {
1607 return ipmi::responseInvalidFieldRequest();
1608 }
1609
1610 // Get Sensor count. This returns the number of sensors
1611 if (numSensors > 0)
1612 {
1613 lunsAndDynamicPopulation |= 1;
1614 }
1615 if (numSensors > maxSensorsPerLUN)
1616 {
1617 lunsAndDynamicPopulation |= 2;
1618 }
1619 if (numSensors >= (maxSensorsPerLUN * 2))
1620 {
1621 lunsAndDynamicPopulation |= 8;
1622 }
1623 if (numSensors > maxIPMISensors)
1624 {
1625 // error
1626 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1627 }
1628
1629 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1630 sdrLastAdd);
1631}
1632
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001633/* end sensor commands */
1634
1635/* storage commands */
1636
James Feist74c50c62019-08-14 14:18:41 -07001637ipmi::RspType<uint8_t, // sdr version
1638 uint16_t, // record count
1639 uint16_t, // free space
1640 uint32_t, // most recent addition
1641 uint32_t, // most recent erase
1642 uint8_t // operationSupport
1643 >
James Feist25690252019-12-23 12:25:49 -08001644 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001645{
James Feist74c50c62019-08-14 14:18:41 -07001646 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001647 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001648 {
James Feist74c50c62019-08-14 14:18:41 -07001649 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001650 }
1651
James Feist74c50c62019-08-14 14:18:41 -07001652 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001653 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001654 if (ret != ipmi::ccSuccess)
1655 {
1656 return ipmi::response(ret);
1657 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001658
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301659 uint16_t recordCount = getNumberOfSensors() + fruCount +
1660 ipmi::storage::type12Count +
1661 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001662
James Feist74c50c62019-08-14 14:18:41 -07001663 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001664 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001665
1666 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001667 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001668 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001669 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001670 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1671 unspecifiedFreeSpace, sdrLastAdd,
1672 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001673}
1674
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001675/** @brief implements the get SDR allocation info command
1676 *
1677 * @returns IPMI completion code plus response data
1678 * - allocUnits - Number of possible allocation units
1679 * - allocUnitSize - Allocation unit size in bytes.
1680 * - allocUnitFree - Number of free allocation units
1681 * - allocUnitLargestFree - Largest free block in allocation units
1682 * - maxRecordSize - Maximum record size in allocation units.
1683 */
1684ipmi::RspType<uint16_t, // allocUnits
1685 uint16_t, // allocUnitSize
1686 uint16_t, // allocUnitFree
1687 uint16_t, // allocUnitLargestFree
1688 uint8_t // maxRecordSize
1689 >
1690 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001691{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001692 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001693 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001694
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001695 constexpr uint16_t allocUnitFree = 0;
1696 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001697 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001698 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001699
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001700 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1701 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001702}
1703
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001704/** @brief implements the reserve SDR command
1705 * @returns IPMI completion code plus response data
1706 * - sdrReservationID
1707 */
1708ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001709{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001710 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001711 if (sdrReservationID == 0)
1712 {
1713 sdrReservationID++;
1714 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001715
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001716 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001717}
1718
James Feistb49a98a2019-04-16 13:48:09 -07001719ipmi::RspType<uint16_t, // next record ID
1720 std::vector<uint8_t> // payload
1721 >
James Feist25690252019-12-23 12:25:49 -08001722 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1723 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001724{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001725 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001726 // reservation required for partial reads with non zero offset into
1727 // record
James Feistb49a98a2019-04-16 13:48:09 -07001728 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001729 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001730 phosphor::logging::log<phosphor::logging::level::ERR>(
1731 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001732 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001733 }
James Feist25690252019-12-23 12:25:49 -08001734 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001735 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001736 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001737 phosphor::logging::log<phosphor::logging::level::ERR>(
1738 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001739 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001740 }
1741
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001742 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001743 ipmi::storage::type12Count +
1744 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001745 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1746
1747 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001748 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001749 phosphor::logging::log<phosphor::logging::level::ERR>(
1750 "ipmiStorageGetSDR: getSensorSubtree error");
1751 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001752 }
1753
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001754 std::vector<uint8_t> record;
1755 if (getSensorDataRecord(ctx, record, recordID))
1756 {
1757 phosphor::logging::log<phosphor::logging::level::ERR>(
1758 "ipmiStorageGetSDR: fail to get SDR");
1759 return ipmi::responseInvalidFieldRequest();
1760 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001761 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001762 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001763 if (!hdr)
1764 {
1765 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001766 "ipmiStorageGetSDR: record header is null");
1767 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001768 }
1769
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001770 size_t sdrLength =
1771 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1772 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001773 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001774 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001775 }
1776
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001777 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001778 if (!respStart)
1779 {
1780 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001781 "ipmiStorageGetSDR: record is null");
1782 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001783 }
James Feistb49a98a2019-04-16 13:48:09 -07001784 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001785
James Feistb49a98a2019-04-16 13:48:09 -07001786 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001787}
1788/* end storage commands */
1789
1790void registerSensorFunctions()
1791{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001792 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001793 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1794 ipmi::sensor_event::cmdPlatformEvent,
1795 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001796
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001797 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001798 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1799 ipmi::sensor_event::cmdGetSensorReading,
1800 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001801
1802 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001803 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1804 ipmi::sensor_event::cmdGetSensorThreshold,
1805 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001806
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001807 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001808 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1809 ipmi::sensor_event::cmdSetSensorThreshold,
1810 ipmi::Privilege::Operator,
1811 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001812
1813 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001814 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1815 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001816 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001817
1818 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001819 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1820 ipmi::sensor_event::cmdGetSensorEventStatus,
1821 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001822
1823 // register all storage commands for both Sensor and Storage command
1824 // versions
1825
1826 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001827 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1828 ipmi::storage::cmdGetSdrRepositoryInfo,
1829 ipmi::Privilege::User,
1830 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001831
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001832 // <Get Device SDR Info>
1833 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1834 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1835 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1836
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001837 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001838 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1839 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1840 ipmi::Privilege::User,
1841 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001842
1843 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001844 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1845 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001846 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001847
Vernon Mauery98bbf692019-09-16 11:14:59 -07001848 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1849 ipmi::storage::cmdReserveSdrRepository,
1850 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001851
1852 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001853 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1854 ipmi::sensor_event::cmdGetDeviceSdr,
1855 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001856
Vernon Mauery98bbf692019-09-16 11:14:59 -07001857 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1858 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1859 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001860}
1861} // namespace ipmi