blob: 811cd911c1b4cb8ad9a1b15ce16541c619c2e036 [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"
24
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070025#include <boost/algorithm/string.hpp>
26#include <boost/container/flat_map.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070027#include <ipmid/api.hpp>
28#include <ipmid/utils.hpp>
29#include <phosphor-logging/log.hpp>
30#include <sdbusplus/bus.hpp>
31
32#include <algorithm>
33#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070034#include <chrono>
35#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070036#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070037#include <iostream>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070038#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070039#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070040#include <optional>
Patrick Venturee6154022019-09-25 17:50:25 -070041#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070042#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070043#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070044#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070045
46namespace ipmi
47{
48using ManagedObjectType =
49 std::map<sdbusplus::message::object_path,
50 std::map<std::string, std::map<std::string, DbusVariant>>>;
51
James Feist25690252019-12-23 12:25:49 -080052static constexpr int sensorMapUpdatePeriod = 10;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070053
54constexpr size_t maxSDRTotalSize =
55 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
56constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
57
58static uint16_t sdrReservationID;
59static uint32_t sdrLastAdd = noTimestamp;
60static uint32_t sdrLastRemove = noTimestamp;
61
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053062SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070063static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
64
Jason M. Bills17add592018-11-12 14:30:12 -080065// Specify the comparison required to sort and find char* map objects
66struct CmpStr
67{
James Feistfcd2d3a2020-05-28 10:38:15 -070068 bool operator()(const char* a, const char* b) const
Jason M. Bills17add592018-11-12 14:30:12 -080069 {
70 return std::strcmp(a, b) < 0;
71 }
72};
James Feistfcd2d3a2020-05-28 10:38:15 -070073const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
Jason M. Bills17add592018-11-12 14:30:12 -080074 sensorUnits{{{"temperature", SensorUnits::degreesC},
75 {"voltage", SensorUnits::volts},
76 {"current", SensorUnits::amps},
77 {"fan_tach", SensorUnits::rpm},
78 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079
80void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070081
82static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070083 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070084 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
85 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -070086 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070087 sensorTree.clear();
88 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
89 std::chrono::system_clock::now().time_since_epoch())
90 .count();
91 });
92
93static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070094 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070095 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
96 "sensors/'",
James Feistfcd2d3a2020-05-28 10:38:15 -070097 [](sdbusplus::message::message& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070098 sensorTree.clear();
99 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
100 std::chrono::system_clock::now().time_since_epoch())
101 .count();
102 });
103
James Feist392786a2019-03-19 13:36:10 -0700104// this keeps track of deassertions for sensor event status command. A
105// deasertion can only happen if an assertion was seen first.
106static boost::container::flat_map<
107 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
108 thresholdDeassertMap;
109
110static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700111 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700112 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
113 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
James Feistfcd2d3a2020-05-28 10:38:15 -0700114 [](sdbusplus::message::message& m) {
James Feist392786a2019-03-19 13:36:10 -0700115 boost::container::flat_map<std::string, std::variant<bool, double>>
116 values;
117 m.read(std::string(), values);
118
119 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700120 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700121 return pair.first.find("Alarm") != std::string::npos;
122 });
123 if (findAssert != values.end())
124 {
125 auto ptr = std::get_if<bool>(&(findAssert->second));
126 if (ptr == nullptr)
127 {
128 phosphor::logging::log<phosphor::logging::level::ERR>(
129 "thresholdChanged: Assert non bool");
130 return;
131 }
132 if (*ptr)
133 {
134 phosphor::logging::log<phosphor::logging::level::INFO>(
135 "thresholdChanged: Assert",
136 phosphor::logging::entry("SENSOR=%s", m.get_path()));
137 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
138 }
139 else
140 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700141 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700142 thresholdDeassertMap[m.get_path()][findAssert->first];
143 if (value)
144 {
145 phosphor::logging::log<phosphor::logging::level::INFO>(
146 "thresholdChanged: deassert",
147 phosphor::logging::entry("SENSOR=%s", m.get_path()));
148 value = *ptr;
149 }
150 }
151 }
152 });
153
James Feistfcd2d3a2020-05-28 10:38:15 -0700154static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
155 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700156{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700157 max = 127;
158 min = -128;
159
James Feistaecaef72019-04-26 10:30:32 -0700160 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
161 auto critical =
162 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
163 auto warning =
164 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
165
166 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700167 {
James Feistaecaef72019-04-26 10:30:32 -0700168 auto maxMap = sensorObject->second.find("MaxValue");
169 auto minMap = sensorObject->second.find("MinValue");
170
171 if (maxMap != sensorObject->second.end())
172 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700173 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700174 }
175 if (minMap != sensorObject->second.end())
176 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700177 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700178 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700179 }
James Feistaecaef72019-04-26 10:30:32 -0700180 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700181 {
James Feistaecaef72019-04-26 10:30:32 -0700182 auto lower = critical->second.find("CriticalLow");
183 auto upper = critical->second.find("CriticalHigh");
184 if (lower != critical->second.end())
185 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700186 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700187 min = std::min(value, min);
188 }
189 if (upper != critical->second.end())
190 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700191 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700192 max = std::max(value, max);
193 }
194 }
195 if (warning != sensorMap.end())
196 {
197
198 auto lower = warning->second.find("WarningLow");
199 auto upper = warning->second.find("WarningHigh");
200 if (lower != warning->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 != warning->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 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700210 }
211}
212
James Feist25690252019-12-23 12:25:49 -0800213static bool getSensorMap(boost::asio::yield_context yield,
214 std::string sensorConnection, std::string sensorPath,
James Feistfcd2d3a2020-05-28 10:38:15 -0700215 SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700216{
217 static boost::container::flat_map<
218 std::string, std::chrono::time_point<std::chrono::steady_clock>>
219 updateTimeMap;
220
221 auto updateFind = updateTimeMap.find(sensorConnection);
222 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
223 if (updateFind != updateTimeMap.end())
224 {
225 lastUpdate = updateFind->second;
226 }
227
228 auto now = std::chrono::steady_clock::now();
229
230 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
231 .count() > sensorMapUpdatePeriod)
232 {
233 updateTimeMap[sensorConnection] = now;
234
Vernon Mauery15419dd2019-05-24 09:40:30 -0700235 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800236 boost::system::error_code ec;
237 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
238 yield, ec, sensorConnection.c_str(), "/",
239 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
240 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700241 {
242 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800243 "GetMangagedObjects for getSensorMap failed",
244 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
245
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700246 return false;
247 }
248
249 SensorCache[sensorConnection] = managedObjects;
250 }
251 auto connection = SensorCache.find(sensorConnection);
252 if (connection == SensorCache.end())
253 {
254 return false;
255 }
256 auto path = connection->second.find(sensorPath);
257 if (path == connection->second.end())
258 {
259 return false;
260 }
261 sensorMap = path->second;
262
263 return true;
264}
265
266/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700267namespace meHealth
268{
James Feistfcd2d3a2020-05-28 10:38:15 -0700269constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
270constexpr const char* path = "/xyz/openbmc_project/status/me";
271constexpr const char* interface = "xyz.openbmc_project.SetHealth";
272constexpr const char* method = "SetHealth";
273constexpr const char* critical = "critical";
274constexpr const char* warning = "warning";
275constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700276} // namespace meHealth
277
278static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
279{
280 constexpr const std::array<uint8_t, 10> critical = {
281 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
282 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
283 0x1A};
284
285 std::string state;
286 if (std::find(critical.begin(), critical.end(), eventData2) !=
287 critical.end())
288 {
289 state = meHealth::critical;
290 }
291 // special case 0x3 as we only care about a few states
292 else if (eventData2 == 0x3)
293 {
294 if (eventData3 <= 0x2)
295 {
296 state = meHealth::warning;
297 }
298 else
299 {
300 return;
301 }
302 }
303 else if (std::find(warning.begin(), warning.end(), eventData2) !=
304 warning.end())
305 {
306 state = meHealth::warning;
307 }
308 else
309 {
310 return;
311 }
312 if (disable)
313 {
314 state = meHealth::ok;
315 }
316
317 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
318 auto setHealth =
319 dbus->new_method_call(meHealth::busname, meHealth::path,
320 meHealth::interface, meHealth::method);
321 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
322 try
323 {
324 dbus->call(setHealth);
325 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700326 catch (sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700327 {
328 phosphor::logging::log<phosphor::logging::level::ERR>(
329 "Failed to set ME Health");
330 }
331}
332
James Feistfcd2d3a2020-05-28 10:38:15 -0700333ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700334{
James Feist7aaf3fe2019-06-25 11:52:11 -0700335 constexpr const uint8_t meId = 0x2C;
336 constexpr const uint8_t meSensorNum = 0x17;
337 constexpr const uint8_t disabled = 0x80;
338
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700339 uint8_t generatorID = 0;
340 uint8_t evmRev = 0;
341 uint8_t sensorType = 0;
342 uint8_t sensorNum = 0;
343 uint8_t eventType = 0;
344 uint8_t eventData1 = 0;
345 std::optional<uint8_t> eventData2 = 0;
346 std::optional<uint8_t> eventData3 = 0;
347
348 // todo: This check is supposed to be based on the incoming channel.
349 // e.g. system channel will provide upto 8 bytes including generator
350 // ID, but ipmb channel will provide only up to 7 bytes without the
351 // generator ID.
352 // Support for this check is coming in future patches, so for now just base
353 // it on if the first byte is the EvMRev (0x04).
354 if (p.size() && p.data()[0] == 0x04)
355 {
356 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
357 eventData2, eventData3);
358 // todo: the generator ID for this channel is supposed to come from the
359 // IPMB requesters slave address. Support for this is coming in future
360 // patches, so for now just assume it is coming from the ME (0x2C).
361 generatorID = 0x2C;
362 }
363 else
364 {
365 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
366 eventData1, eventData2, eventData3);
367 }
368 if (!p.fullyUnpacked())
369 {
370 return ipmi::responseReqDataLenInvalid();
371 }
372
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700373 // Send this request to the Redfish hooks to log it as a Redfish message
374 // instead. There is no need to add it to the SEL, so just return success.
375 intel_oem::ipmi::sel::checkRedfishHooks(
376 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
377 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700378
James Feist7aaf3fe2019-06-25 11:52:11 -0700379 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
380 eventData3)
381 {
382 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
383 }
384
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700385 return ipmi::responseSuccess();
386}
387
James Feist0cd014a2019-04-08 15:04:33 -0700388ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
James Feist25690252019-12-23 12:25:49 -0800389 ipmiSenGetSensorReading(boost::asio::yield_context yield, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700390{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700391 std::string connection;
392 std::string path;
393
394 auto status = getSensorConnection(sensnum, connection, path);
395 if (status)
396 {
James Feist0cd014a2019-04-08 15:04:33 -0700397 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700398 }
399
400 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800401 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700402 {
James Feist0cd014a2019-04-08 15:04:33 -0700403 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700404 }
405 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
406
407 if (sensorObject == sensorMap.end() ||
408 sensorObject->second.find("Value") == sensorObject->second.end())
409 {
James Feist0cd014a2019-04-08 15:04:33 -0700410 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700411 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700412 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700413 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700414
Yong Li1f2eb5e2019-05-23 14:07:17 +0800415 double max = 0;
416 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700417 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700418
419 int16_t mValue = 0;
420 int16_t bValue = 0;
421 int8_t rExp = 0;
422 int8_t bExp = 0;
423 bool bSigned = false;
424
425 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
426 {
James Feist0cd014a2019-04-08 15:04:33 -0700427 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700428 }
429
James Feist0cd014a2019-04-08 15:04:33 -0700430 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700431 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700432 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700433 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700434 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800435 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700436
James Feist0cd014a2019-04-08 15:04:33 -0700437 uint8_t thresholds = 0;
438
439 auto warningObject =
440 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
441 if (warningObject != sensorMap.end())
442 {
443 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
444 auto alarmLow = warningObject->second.find("WarningAlarmLow");
445 if (alarmHigh != warningObject->second.end())
446 {
447 if (std::get<bool>(alarmHigh->second))
448 {
449 thresholds |= static_cast<uint8_t>(
450 IPMISensorReadingByte3::upperNonCritical);
451 }
452 }
453 if (alarmLow != warningObject->second.end())
454 {
455 if (std::get<bool>(alarmLow->second))
456 {
457 thresholds |= static_cast<uint8_t>(
458 IPMISensorReadingByte3::lowerNonCritical);
459 }
460 }
461 }
462
463 auto criticalObject =
464 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
465 if (criticalObject != sensorMap.end())
466 {
467 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
468 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
469 if (alarmHigh != criticalObject->second.end())
470 {
471 if (std::get<bool>(alarmHigh->second))
472 {
473 thresholds |=
474 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
475 }
476 }
477 if (alarmLow != criticalObject->second.end())
478 {
479 if (std::get<bool>(alarmLow->second))
480 {
481 thresholds |=
482 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
483 }
484 }
485 }
486
487 // no discrete as of today so optional byte is never returned
488 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700489}
490
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000491/** @brief implements the Set Sensor threshold command
492 * @param sensorNumber - sensor number
493 * @param lowerNonCriticalThreshMask
494 * @param lowerCriticalThreshMask
495 * @param lowerNonRecovThreshMask
496 * @param upperNonCriticalThreshMask
497 * @param upperCriticalThreshMask
498 * @param upperNonRecovThreshMask
499 * @param reserved
500 * @param lowerNonCritical - lower non-critical threshold
501 * @param lowerCritical - Lower critical threshold
502 * @param lowerNonRecoverable - Lower non recovarable threshold
503 * @param upperNonCritical - Upper non-critical threshold
504 * @param upperCritical - Upper critical
505 * @param upperNonRecoverable - Upper Non-recoverable
506 *
507 * @returns IPMI completion code
508 */
509ipmi::RspType<> ipmiSenSetSensorThresholds(
James Feist25690252019-12-23 12:25:49 -0800510 boost::asio::yield_context yield, uint8_t sensorNum,
511 bool lowerNonCriticalThreshMask, bool lowerCriticalThreshMask,
512 bool lowerNonRecovThreshMask, bool upperNonCriticalThreshMask,
513 bool upperCriticalThreshMask, bool upperNonRecovThreshMask,
514 uint2_t reserved, uint8_t lowerNonCritical, uint8_t lowerCritical,
515 uint8_t lowerNonRecoverable, uint8_t upperNonCritical,
516 uint8_t upperCritical, uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700517{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000518 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700519
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000520 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700521 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000522 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700523 }
524
525 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000526 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700527 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000528 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700529 }
530
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000531 // if none of the threshold mask are set, nothing to do
532 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
533 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
534 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700535 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000536 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700537 }
538
539 std::string connection;
540 std::string path;
541
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000542 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700543 if (status)
544 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000545 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700546 }
547 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800548 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700549 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000550 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700551 }
552
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700553 double max = 0;
554 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700555 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700556
557 int16_t mValue = 0;
558 int16_t bValue = 0;
559 int8_t rExp = 0;
560 int8_t bExp = 0;
561 bool bSigned = false;
562
563 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
564 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000565 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700566 }
567
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700568 // store a vector of property name, value to set, and interface
569 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
570
571 // define the indexes of the tuple
572 constexpr uint8_t propertyName = 0;
573 constexpr uint8_t thresholdValue = 1;
574 constexpr uint8_t interface = 2;
575 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000576 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700577 {
578 auto findThreshold =
579 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
580 if (findThreshold == sensorMap.end())
581 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000582 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700583 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000584 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700585 {
586 auto findLower = findThreshold->second.find("CriticalLow");
587 if (findLower == findThreshold->second.end())
588 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000589 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700590 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000591 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700592 findThreshold->first);
593 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000594 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700595 {
596 auto findUpper = findThreshold->second.find("CriticalHigh");
597 if (findUpper == findThreshold->second.end())
598 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000599 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700600 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000601 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 findThreshold->first);
603 }
604 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000605 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700606 {
607 auto findThreshold =
608 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
609 if (findThreshold == sensorMap.end())
610 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000611 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700612 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000613 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700614 {
615 auto findLower = findThreshold->second.find("WarningLow");
616 if (findLower == findThreshold->second.end())
617 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000618 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700619 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621 findThreshold->first);
622 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000623 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700624 {
625 auto findUpper = findThreshold->second.find("WarningHigh");
626 if (findUpper == findThreshold->second.end())
627 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000628 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700629 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 findThreshold->first);
632 }
633 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700634 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700635 {
636 // from section 36.3 in the IPMI Spec, assume all linear
637 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800638 (bValue * std::pow(10.0, bExp))) *
639 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700640 setDbusProperty(
641 *getSdBus(), connection, path, std::get<interface>(property),
642 std::get<propertyName>(property), ipmi::Value(valueToSet));
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
James Feistfcd2d3a2020-05-28 10:38:15 -0700647IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700648{
James Feist902c4c52019-04-16 14:51:31 -0700649 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 auto warningInterface =
651 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
652 auto criticalInterface =
653 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
654
655 if ((warningInterface != sensorMap.end()) ||
656 (criticalInterface != sensorMap.end()))
657 {
658 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
659
660 if (sensorPair == sensorMap.end())
661 {
662 // should not have been able to find a sensor not implementing
663 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700664 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700665 }
666
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800667 double max = 0;
668 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700669 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700670
671 int16_t mValue = 0;
672 int16_t bValue = 0;
673 int8_t rExp = 0;
674 int8_t bExp = 0;
675 bool bSigned = false;
676
677 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
678 {
James Feist902c4c52019-04-16 14:51:31 -0700679 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700681 if (warningInterface != sensorMap.end())
682 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700683 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700684
685 auto warningHigh = warningMap.find("WarningHigh");
686 auto warningLow = warningMap.find("WarningLow");
687
688 if (warningHigh != warningMap.end())
689 {
James Feist902c4c52019-04-16 14:51:31 -0700690
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700691 double value =
692 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700693 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700694 value, mValue, rExp, bValue, bExp, bSigned);
695 }
696 if (warningLow != warningMap.end())
697 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700698 double value =
699 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700700 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700701 value, mValue, rExp, bValue, bExp, bSigned);
702 }
703 }
704 if (criticalInterface != sensorMap.end())
705 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700706 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700707
708 auto criticalHigh = criticalMap.find("CriticalHigh");
709 auto criticalLow = criticalMap.find("CriticalLow");
710
711 if (criticalHigh != criticalMap.end())
712 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700713 double value =
714 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700715 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700716 value, mValue, rExp, bValue, bExp, bSigned);
717 }
718 if (criticalLow != criticalMap.end())
719 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700720 double value =
721 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700722 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700723 value, mValue, rExp, bValue, bExp, bSigned);
724 }
725 }
726 }
James Feist902c4c52019-04-16 14:51:31 -0700727 return resp;
728}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700729
James Feist902c4c52019-04-16 14:51:31 -0700730ipmi::RspType<uint8_t, // readable
731 uint8_t, // lowerNCrit
732 uint8_t, // lowerCrit
733 uint8_t, // lowerNrecoverable
734 uint8_t, // upperNC
735 uint8_t, // upperCrit
736 uint8_t> // upperNRecoverable
James Feist25690252019-12-23 12:25:49 -0800737 ipmiSenGetSensorThresholds(boost::asio::yield_context yield,
738 uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700739{
740 std::string connection;
741 std::string path;
742
743 auto status = getSensorConnection(sensorNumber, connection, path);
744 if (status)
745 {
746 return ipmi::response(status);
747 }
748
749 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800750 if (!getSensorMap(yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700751 {
752 return ipmi::responseResponseError();
753 }
754
755 IPMIThresholds thresholdData;
756 try
757 {
758 thresholdData = getIPMIThresholds(sensorMap);
759 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700760 catch (std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700761 {
762 return ipmi::responseResponseError();
763 }
764
765 uint8_t readable = 0;
766 uint8_t lowerNC = 0;
767 uint8_t lowerCritical = 0;
768 uint8_t lowerNonRecoverable = 0;
769 uint8_t upperNC = 0;
770 uint8_t upperCritical = 0;
771 uint8_t upperNonRecoverable = 0;
772
773 if (thresholdData.warningHigh)
774 {
775 readable |=
776 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
777 upperNC = *thresholdData.warningHigh;
778 }
779 if (thresholdData.warningLow)
780 {
781 readable |=
782 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
783 lowerNC = *thresholdData.warningLow;
784 }
785
786 if (thresholdData.criticalHigh)
787 {
788 readable |=
789 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
790 upperCritical = *thresholdData.criticalHigh;
791 }
792 if (thresholdData.criticalLow)
793 {
794 readable |=
795 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
796 lowerCritical = *thresholdData.criticalLow;
797 }
798
799 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
800 lowerNonRecoverable, upperNC, upperCritical,
801 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700802}
803
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000804/** @brief implements the get Sensor event enable command
805 * @param sensorNumber - sensor number
806 *
807 * @returns IPMI completion code plus response data
808 * - enabled - Sensor Event messages
809 * - assertionEnabledLsb - Assertion event messages
810 * - assertionEnabledMsb - Assertion event messages
811 * - deassertionEnabledLsb - Deassertion event messages
812 * - deassertionEnabledMsb - Deassertion event messages
813 */
814
815ipmi::RspType<uint8_t, // enabled
816 uint8_t, // assertionEnabledLsb
817 uint8_t, // assertionEnabledMsb
818 uint8_t, // deassertionEnabledLsb
819 uint8_t> // deassertionEnabledMsb
James Feist25690252019-12-23 12:25:49 -0800820 ipmiSenGetSensorEventEnable(boost::asio::yield_context yield,
821 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700822{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700823 std::string connection;
824 std::string path;
825
Patrick Venturea41714c2019-09-25 16:59:41 -0700826 uint8_t enabled = 0;
827 uint8_t assertionEnabledLsb = 0;
828 uint8_t assertionEnabledMsb = 0;
829 uint8_t deassertionEnabledLsb = 0;
830 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000831
832 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700833 if (status)
834 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000835 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700836 }
837
838 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800839 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700840 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000841 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700842 }
843
844 auto warningInterface =
845 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
846 auto criticalInterface =
847 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700848 if ((warningInterface != sensorMap.end()) ||
849 (criticalInterface != sensorMap.end()))
850 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000851 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700852 IPMISensorEventEnableByte2::sensorScanningEnable);
853 if (warningInterface != sensorMap.end())
854 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700855 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700856
857 auto warningHigh = warningMap.find("WarningHigh");
858 auto warningLow = warningMap.find("WarningLow");
859 if (warningHigh != warningMap.end())
860 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000861 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700862 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000863 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700864 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
865 }
866 if (warningLow != warningMap.end())
867 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000868 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700869 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000870 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700871 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
872 }
873 }
874 if (criticalInterface != sensorMap.end())
875 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700876 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700877
878 auto criticalHigh = criticalMap.find("CriticalHigh");
879 auto criticalLow = criticalMap.find("CriticalLow");
880
881 if (criticalHigh != criticalMap.end())
882 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000883 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700884 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000885 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700886 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
887 }
888 if (criticalLow != criticalMap.end())
889 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000890 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700891 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000892 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700893 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
894 }
895 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700896 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000897
898 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
899 assertionEnabledMsb, deassertionEnabledLsb,
900 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700901}
902
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000903/** @brief implements the get Sensor event status command
904 * @param sensorNumber - sensor number, FFh = reserved
905 *
906 * @returns IPMI completion code plus response data
907 * - sensorEventStatus - Sensor Event messages state
908 * - assertions - Assertion event messages
909 * - deassertions - Deassertion event messages
910 */
911ipmi::RspType<uint8_t, // sensorEventStatus
912 std::bitset<16>, // assertions
913 std::bitset<16> // deassertion
914 >
James Feist25690252019-12-23 12:25:49 -0800915 ipmiSenGetSensorEventStatus(boost::asio::yield_context yield,
916 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700917{
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000918 if (sensorNum == 0xFF)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700919 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000920 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700921 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700922
923 std::string connection;
924 std::string path;
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000925 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700926 if (status)
927 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000928 phosphor::logging::log<phosphor::logging::level::ERR>(
929 "ipmiSenGetSensorEventStatus: Sensor connection Error",
930 phosphor::logging::entry("SENSOR=%d", sensorNum));
931 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700932 }
933
934 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800935 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700936 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000937 phosphor::logging::log<phosphor::logging::level::ERR>(
938 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
939 phosphor::logging::entry("SENSOR=%s", path.c_str()));
940 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700941 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700942 auto warningInterface =
943 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
944 auto criticalInterface =
945 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
946
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000947 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700948 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
949
James Feist392786a2019-03-19 13:36:10 -0700950 std::optional<bool> criticalDeassertHigh =
951 thresholdDeassertMap[path]["CriticalAlarmHigh"];
952 std::optional<bool> criticalDeassertLow =
953 thresholdDeassertMap[path]["CriticalAlarmLow"];
954 std::optional<bool> warningDeassertHigh =
955 thresholdDeassertMap[path]["WarningAlarmHigh"];
956 std::optional<bool> warningDeassertLow =
957 thresholdDeassertMap[path]["WarningAlarmLow"];
958
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000959 std::bitset<16> assertions = 0;
960 std::bitset<16> deassertions = 0;
961
James Feist392786a2019-03-19 13:36:10 -0700962 if (criticalDeassertHigh && !*criticalDeassertHigh)
963 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000964 deassertions.set(static_cast<size_t>(
965 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700966 }
967 if (criticalDeassertLow && !*criticalDeassertLow)
968 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000969 deassertions.set(static_cast<size_t>(
970 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -0700971 }
972 if (warningDeassertHigh && !*warningDeassertHigh)
973 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000974 deassertions.set(static_cast<size_t>(
975 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700976 }
977 if (warningDeassertLow && !*warningDeassertLow)
978 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000979 deassertions.set(static_cast<size_t>(
980 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700981 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700982 if ((warningInterface != sensorMap.end()) ||
983 (criticalInterface != sensorMap.end()))
984 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000985 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700986 IPMISensorEventEnableByte2::eventMessagesEnable);
987 if (warningInterface != sensorMap.end())
988 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700989 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700990
991 auto warningHigh = warningMap.find("WarningAlarmHigh");
992 auto warningLow = warningMap.find("WarningAlarmLow");
993 auto warningHighAlarm = false;
994 auto warningLowAlarm = false;
995
996 if (warningHigh != warningMap.end())
997 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700998 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700999 }
1000 if (warningLow != warningMap.end())
1001 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001002 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001003 }
1004 if (warningHighAlarm)
1005 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001006 assertions.set(
1007 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1008 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001009 }
1010 if (warningLowAlarm)
1011 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001012 assertions.set(
1013 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1014 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001015 }
1016 }
1017 if (criticalInterface != sensorMap.end())
1018 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001019 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001020
1021 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1022 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1023 auto criticalHighAlarm = false;
1024 auto criticalLowAlarm = false;
1025
1026 if (criticalHigh != criticalMap.end())
1027 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001028 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001029 }
1030 if (criticalLow != criticalMap.end())
1031 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001032 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001033 }
1034 if (criticalHighAlarm)
1035 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001036 assertions.set(
1037 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1038 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001039 }
1040 if (criticalLowAlarm)
1041 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001042 assertions.set(static_cast<size_t>(
1043 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001044 }
1045 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001046 }
1047
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001048 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001049}
1050
1051/* end sensor commands */
1052
1053/* storage commands */
1054
James Feist74c50c62019-08-14 14:18:41 -07001055ipmi::RspType<uint8_t, // sdr version
1056 uint16_t, // record count
1057 uint16_t, // free space
1058 uint32_t, // most recent addition
1059 uint32_t, // most recent erase
1060 uint8_t // operationSupport
1061 >
James Feist25690252019-12-23 12:25:49 -08001062 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001063{
James Feist74c50c62019-08-14 14:18:41 -07001064 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001065 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1066 {
James Feist74c50c62019-08-14 14:18:41 -07001067 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001068 }
1069
James Feist74c50c62019-08-14 14:18:41 -07001070 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001071 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001072 if (ret != ipmi::ccSuccess)
1073 {
1074 return ipmi::response(ret);
1075 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001076
James Feist74c50c62019-08-14 14:18:41 -07001077 uint16_t recordCount =
1078 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001079
James Feist74c50c62019-08-14 14:18:41 -07001080 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001081 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001082
1083 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001084 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001085 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001086 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001087 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1088 unspecifiedFreeSpace, sdrLastAdd,
1089 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090}
1091
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001092/** @brief implements the get SDR allocation info command
1093 *
1094 * @returns IPMI completion code plus response data
1095 * - allocUnits - Number of possible allocation units
1096 * - allocUnitSize - Allocation unit size in bytes.
1097 * - allocUnitFree - Number of free allocation units
1098 * - allocUnitLargestFree - Largest free block in allocation units
1099 * - maxRecordSize - Maximum record size in allocation units.
1100 */
1101ipmi::RspType<uint16_t, // allocUnits
1102 uint16_t, // allocUnitSize
1103 uint16_t, // allocUnitFree
1104 uint16_t, // allocUnitLargestFree
1105 uint8_t // maxRecordSize
1106 >
1107 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001108{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001109 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001110 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001111
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001112 constexpr uint16_t allocUnitFree = 0;
1113 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001114 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001115 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001116
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001117 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1118 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001119}
1120
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001121/** @brief implements the reserve SDR command
1122 * @returns IPMI completion code plus response data
1123 * - sdrReservationID
1124 */
1125ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001126{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001127 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001128 if (sdrReservationID == 0)
1129 {
1130 sdrReservationID++;
1131 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001132
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001133 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134}
1135
James Feistb49a98a2019-04-16 13:48:09 -07001136ipmi::RspType<uint16_t, // next record ID
1137 std::vector<uint8_t> // payload
1138 >
James Feist25690252019-12-23 12:25:49 -08001139 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1140 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001141{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001143
1144 // reservation required for partial reads with non zero offset into
1145 // record
James Feistb49a98a2019-04-16 13:48:09 -07001146 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001147 {
James Feistb49a98a2019-04-16 13:48:09 -07001148 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001149 }
1150
1151 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1152 {
James Feistb49a98a2019-04-16 13:48:09 -07001153 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001154 }
1155
1156 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001157 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001158 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159 {
James Feistb49a98a2019-04-16 13:48:09 -07001160 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001161 }
1162
Yong Lifee5e4c2020-01-17 19:36:29 +08001163 size_t lastRecord = sensorTree.size() + fruCount +
1164 ipmi::storage::type12Count +
1165 ipmi::storage::nmDiscoverySDRCount - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001166 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 {
James Feistb49a98a2019-04-16 13:48:09 -07001168 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001169 }
James Feistb49a98a2019-04-16 13:48:09 -07001170 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001171 {
James Feistb49a98a2019-04-16 13:48:09 -07001172 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001173 }
1174
James Feistb49a98a2019-04-16 13:48:09 -07001175 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001176
James Feistb49a98a2019-04-16 13:48:09 -07001177 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001178 {
James Feist74c50c62019-08-14 14:18:41 -07001179 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001180 size_t fruIndex = recordID - sensorTree.size();
Yong Lifee5e4c2020-01-17 19:36:29 +08001181 size_t type12End = fruCount + ipmi::storage::type12Count;
1182
1183 if (fruIndex >= type12End)
1184 {
1185 // NM discovery SDR
1186 size_t nmDiscoveryIndex = fruIndex - type12End;
1187 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount ||
1188 offset > sizeof(NMDiscoveryRecord))
1189 {
1190 return ipmi::responseInvalidFieldRequest();
1191 }
1192
1193 std::vector<uint8_t> record =
1194 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
1195 if (record.size() < (offset + bytesToRead))
1196 {
1197 bytesToRead = record.size() - offset;
1198 }
1199 recordData.insert(recordData.end(), record.begin() + offset,
1200 record.begin() + offset + bytesToRead);
1201 }
1202 else if (fruIndex >= fruCount)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001203 {
James Feist74c50c62019-08-14 14:18:41 -07001204 // handle type 12 hardcoded records
1205 size_t type12Index = fruIndex - fruCount;
1206 if (type12Index >= ipmi::storage::type12Count ||
1207 offset > sizeof(Type12Record))
1208 {
1209 return ipmi::responseInvalidFieldRequest();
1210 }
1211 std::vector<uint8_t> record =
1212 ipmi::storage::getType12SDRs(type12Index, recordID);
1213 if (record.size() < (offset + bytesToRead))
1214 {
1215 bytesToRead = record.size() - offset;
1216 }
James Feistb49a98a2019-04-16 13:48:09 -07001217
James Feist74c50c62019-08-14 14:18:41 -07001218 recordData.insert(recordData.end(), record.begin() + offset,
1219 record.begin() + offset + bytesToRead);
1220 }
1221 else
1222 {
1223 // handle fru records
1224 get_sdr::SensorDataFruRecord data;
1225 if (offset > sizeof(data))
1226 {
1227 return ipmi::responseInvalidFieldRequest();
1228 }
James Feist25690252019-12-23 12:25:49 -08001229 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
James Feist74c50c62019-08-14 14:18:41 -07001230 if (ret != IPMI_CC_OK)
1231 {
1232 return ipmi::response(ret);
1233 }
1234 data.header.record_id_msb = recordID << 8;
1235 data.header.record_id_lsb = recordID & 0xFF;
1236 if (sizeof(data) < (offset + bytesToRead))
1237 {
1238 bytesToRead = sizeof(data) - offset;
1239 }
1240
James Feistfcd2d3a2020-05-28 10:38:15 -07001241 uint8_t* respStart = reinterpret_cast<uint8_t*>(&data) + offset;
James Feist74c50c62019-08-14 14:18:41 -07001242 recordData.insert(recordData.end(), respStart,
1243 respStart + bytesToRead);
1244 }
James Feistb49a98a2019-04-16 13:48:09 -07001245
1246 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001247 }
1248
1249 std::string connection;
1250 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001251 uint16_t sensorIndex = recordID;
James Feistfcd2d3a2020-05-28 10:38:15 -07001252 for (const auto& sensor : sensorTree)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001253 {
1254 if (sensorIndex-- == 0)
1255 {
1256 if (!sensor.second.size())
1257 {
James Feistb49a98a2019-04-16 13:48:09 -07001258 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001259 }
1260 connection = sensor.second.begin()->first;
1261 path = sensor.first;
1262 break;
1263 }
1264 }
1265
1266 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -08001267 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001268 {
James Feistb49a98a2019-04-16 13:48:09 -07001269 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001270 }
James Feistb49a98a2019-04-16 13:48:09 -07001271 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001272 get_sdr::SensorDataFullRecord record = {0};
1273
James Feistb49a98a2019-04-16 13:48:09 -07001274 record.header.record_id_msb = recordID << 8;
1275 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001276 record.header.sdr_version = ipmiSdrVersion;
1277 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1278 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1279 sizeof(get_sdr::SensorDataRecordHeader);
1280 record.key.owner_id = 0x20;
1281 record.key.owner_lun = 0x0;
1282 record.key.sensor_number = sensornumber;
1283
James Feist7086a882019-03-13 10:46:00 -07001284 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001285 record.body.sensor_type = getSensorTypeFromPath(path);
1286 std::string type = getSensorTypeStringFromPath(path);
1287 auto typeCstr = type.c_str();
1288 auto findUnits = sensorUnits.find(typeCstr);
1289 if (findUnits != sensorUnits.end())
1290 {
1291 record.body.sensor_units_2_base =
1292 static_cast<uint8_t>(findUnits->second);
1293 } // else default 0x0 unspecified
1294
1295 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1296
1297 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1298 if (sensorObject == sensorMap.end())
1299 {
James Feistb49a98a2019-04-16 13:48:09 -07001300 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001301 }
1302
Patrick Venture262276f2019-10-18 13:27:59 -07001303 uint8_t entityId = 0;
1304 uint8_t entityInstance = 0x01;
1305
1306 // follow the association chain to get the parent board's entityid and
1307 // entityInstance
1308 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1309
1310 record.body.entity_id = entityId;
1311 record.body.entity_instance = entityInstance;
1312
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001313 auto maxObject = sensorObject->second.find("MaxValue");
1314 auto minObject = sensorObject->second.find("MinValue");
Josh Lehanca9dcbd2019-11-18 15:59:59 -08001315
1316 // If min and/or max are left unpopulated,
1317 // then default to what a signed byte would be, namely (-128,127) range.
1318 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1319 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001320 if (maxObject != sensorObject->second.end())
1321 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001322 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001323 }
1324
1325 if (minObject != sensorObject->second.end())
1326 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001327 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001328 }
1329
Yong Li1f2eb5e2019-05-23 14:07:17 +08001330 int16_t mValue = 0;
1331 int8_t rExp = 0;
1332 int16_t bValue = 0;
1333 int8_t bExp = 0;
1334 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001335
1336 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1337 {
James Feistb49a98a2019-04-16 13:48:09 -07001338 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001339 }
1340
Josh Lehan7cc9e472019-11-18 16:09:26 -08001341 // The record.body is a struct SensorDataFullRecordBody
1342 // from sensorhandler.hpp in phosphor-ipmi-host.
1343 // The meaning of these bits appears to come from
1344 // table 43.1 of the IPMI spec.
1345 // The above 5 sensor attributes are stuffed in as follows:
1346 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1347 // Byte 22-24 are for other purposes
1348 // Byte 25 = MMMMMMMM = LSB of M
1349 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1350 // Byte 27 = BBBBBBBB = LSB of B
1351 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1352 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1353 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1354
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001355 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1356 record.body.m_lsb = mValue & 0xFF;
1357
Josh Lehan7cc9e472019-11-18 16:09:26 -08001358 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1359 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1360
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001361 // move the smallest bit of the MSB into place (bit 9)
1362 // the MSbs are bits 7:8 in m_msb_and_tolerance
Josh Lehan7cc9e472019-11-18 16:09:26 -08001363 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001364
1365 record.body.b_lsb = bValue & 0xFF;
1366
Josh Lehan7cc9e472019-11-18 16:09:26 -08001367 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1368 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1369
1370 // move the smallest bit of the MSB into place (bit 9)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001371 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
Josh Lehan7cc9e472019-11-18 16:09:26 -08001372 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001373
Josh Lehan7cc9e472019-11-18 16:09:26 -08001374 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1375 uint8_t rExpBits = rExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001376
Josh Lehan7cc9e472019-11-18 16:09:26 -08001377 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1378 uint8_t bExpBits = bExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001379
Josh Lehan7cc9e472019-11-18 16:09:26 -08001380 // move rExp and bExp into place
1381 record.body.r_b_exponents =
1382 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1383
1384 // Set the analog reading byte interpretation accordingly
1385 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1386
1387 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1388 // These seem redundant, but derivable from the above 5 attributes
1389 // Original comment said "todo fill out rest of units"
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001390
1391 // populate sensor name from path
1392 std::string name;
1393 size_t nameStart = path.rfind("/");
1394 if (nameStart != std::string::npos)
1395 {
1396 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1397 }
1398
1399 std::replace(name.begin(), name.end(), '_', ' ');
1400 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1401 {
James Feist979a2322019-05-15 09:06:54 -07001402 // try to not truncate by replacing common words
James Feistfcd2d3a2020-05-28 10:38:15 -07001403 constexpr std::array<std::pair<const char*, const char*>, 2>
James Feist979a2322019-05-15 09:06:54 -07001404 replaceWords = {std::make_pair("Output", "Out"),
1405 std::make_pair("Input", "In")};
James Feistfcd2d3a2020-05-28 10:38:15 -07001406 for (const auto& [find, replace] : replaceWords)
James Feist979a2322019-05-15 09:06:54 -07001407 {
1408 boost::replace_all(name, find, replace);
1409 }
1410
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001411 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1412 }
1413 record.body.id_string_info = name.size();
1414 std::strncpy(record.body.id_string, name.c_str(),
1415 sizeof(record.body.id_string));
1416
James Feistc4b15bc2019-04-16 15:41:39 -07001417 IPMIThresholds thresholdData;
1418 try
1419 {
1420 thresholdData = getIPMIThresholds(sensorMap);
1421 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001422 catch (std::exception&)
James Feistc4b15bc2019-04-16 15:41:39 -07001423 {
1424 return ipmi::responseResponseError();
1425 }
1426
1427 if (thresholdData.criticalHigh)
1428 {
1429 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1430 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
Rashmi RV963a95b2020-01-27 15:09:17 +05301431 IPMISensorEventEnableThresholds::criticalThreshold);
1432 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
James Feistc4b15bc2019-04-16 15:41:39 -07001433 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1434 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1435 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1436 record.body.discrete_reading_setting_mask[0] |=
1437 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1438 }
1439 if (thresholdData.warningHigh)
1440 {
1441 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
Rashmi RV963a95b2020-01-27 15:09:17 +05301442 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1443 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001444 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1445 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1446 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1447 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1448 record.body.discrete_reading_setting_mask[0] |=
1449 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1450 }
1451 if (thresholdData.criticalLow)
1452 {
1453 record.body.lower_critical_threshold = *thresholdData.criticalLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301454 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1455 IPMISensorEventEnableThresholds::criticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001456 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1457 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1458 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1459 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1460 record.body.discrete_reading_setting_mask[0] |=
1461 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1462 }
1463 if (thresholdData.warningLow)
1464 {
1465 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301466 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1467 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001468 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1469 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1470 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1471 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1472 record.body.discrete_reading_setting_mask[0] |=
1473 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1474 }
1475
1476 // everything that is readable is setable
1477 record.body.discrete_reading_setting_mask[1] =
1478 record.body.discrete_reading_setting_mask[0];
1479
James Feistb49a98a2019-04-16 13:48:09 -07001480 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001481 {
James Feistb49a98a2019-04-16 13:48:09 -07001482 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001483 }
1484
James Feistfcd2d3a2020-05-28 10:38:15 -07001485 uint8_t* respStart = reinterpret_cast<uint8_t*>(&record) + offset;
James Feistb49a98a2019-04-16 13:48:09 -07001486 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001487
James Feistb49a98a2019-04-16 13:48:09 -07001488 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001489}
1490/* end storage commands */
1491
1492void registerSensorFunctions()
1493{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001494 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001495 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1496 ipmi::sensor_event::cmdPlatformEvent,
1497 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001498
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001499 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001500 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1501 ipmi::sensor_event::cmdGetSensorReading,
1502 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001503
1504 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001505 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1506 ipmi::sensor_event::cmdGetSensorThreshold,
1507 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001508
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001509 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001510 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1511 ipmi::sensor_event::cmdSetSensorThreshold,
1512 ipmi::Privilege::Operator,
1513 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001514
1515 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001516 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1517 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001518 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001519
1520 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001521 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1522 ipmi::sensor_event::cmdGetSensorEventStatus,
1523 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001524
1525 // register all storage commands for both Sensor and Storage command
1526 // versions
1527
1528 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001529 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1530 ipmi::storage::cmdGetSdrRepositoryInfo,
1531 ipmi::Privilege::User,
1532 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001533
1534 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001535 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1536 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1537 ipmi::Privilege::User,
1538 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001539
1540 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001541 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1542 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001543 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001544
Vernon Mauery98bbf692019-09-16 11:14:59 -07001545 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1546 ipmi::storage::cmdReserveSdrRepository,
1547 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001548
1549 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001550 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1551 ipmi::sensor_event::cmdGetDeviceSdr,
1552 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001553
Vernon Mauery98bbf692019-09-16 11:14:59 -07001554 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1555 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1556 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001557}
1558} // namespace ipmi