blob: 0c1840ce36015246fc899cbb343d639968aa3f9a [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
Patrick Venturef777e1b2019-09-25 17:45:44 -070025#include <algorithm>
Patrick Venture44ec88e2019-09-25 17:48:29 -070026#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070027#include <boost/algorithm/string.hpp>
28#include <boost/container/flat_map.hpp>
29#include <chrono>
30#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070031#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070032#include <iostream>
James Feist2a265d52019-04-08 11:16:27 -070033#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070034#include <ipmid/utils.hpp>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070035#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070036#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070037#include <optional>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <phosphor-logging/log.hpp>
39#include <sdbusplus/bus.hpp>
Patrick Venturee6154022019-09-25 17:50:25 -070040#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070041#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070042#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070043#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070044
45namespace ipmi
46{
47using ManagedObjectType =
48 std::map<sdbusplus::message::object_path,
49 std::map<std::string, std::map<std::string, DbusVariant>>>;
50
James Feist25690252019-12-23 12:25:49 -080051static constexpr int sensorMapUpdatePeriod = 10;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070052
53constexpr size_t maxSDRTotalSize =
54 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
55constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
56
57static uint16_t sdrReservationID;
58static uint32_t sdrLastAdd = noTimestamp;
59static uint32_t sdrLastRemove = noTimestamp;
60
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053061SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070062static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
63
Jason M. Bills17add592018-11-12 14:30:12 -080064// Specify the comparison required to sort and find char* map objects
65struct CmpStr
66{
67 bool operator()(const char *a, const char *b) const
68 {
69 return std::strcmp(a, b) < 0;
70 }
71};
72const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
73 sensorUnits{{{"temperature", SensorUnits::degreesC},
74 {"voltage", SensorUnits::volts},
75 {"current", SensorUnits::amps},
76 {"fan_tach", SensorUnits::rpm},
77 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070078
79void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070080
81static sdbusplus::bus::match::match sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070082 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070083 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
84 "sensors/'",
85 [](sdbusplus::message::message &m) {
86 sensorTree.clear();
87 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
88 std::chrono::system_clock::now().time_since_epoch())
89 .count();
90 });
91
92static sdbusplus::bus::match::match sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -070093 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070094 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
95 "sensors/'",
96 [](sdbusplus::message::message &m) {
97 sensorTree.clear();
98 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
99 std::chrono::system_clock::now().time_since_epoch())
100 .count();
101 });
102
James Feist392786a2019-03-19 13:36:10 -0700103// this keeps track of deassertions for sensor event status command. A
104// deasertion can only happen if an assertion was seen first.
105static boost::container::flat_map<
106 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
107 thresholdDeassertMap;
108
109static sdbusplus::bus::match::match thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700110 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700111 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
112 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
113 [](sdbusplus::message::message &m) {
114 boost::container::flat_map<std::string, std::variant<bool, double>>
115 values;
116 m.read(std::string(), values);
117
118 auto findAssert =
119 std::find_if(values.begin(), values.end(), [](const auto &pair) {
120 return pair.first.find("Alarm") != std::string::npos;
121 });
122 if (findAssert != values.end())
123 {
124 auto ptr = std::get_if<bool>(&(findAssert->second));
125 if (ptr == nullptr)
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "thresholdChanged: Assert non bool");
129 return;
130 }
131 if (*ptr)
132 {
133 phosphor::logging::log<phosphor::logging::level::INFO>(
134 "thresholdChanged: Assert",
135 phosphor::logging::entry("SENSOR=%s", m.get_path()));
136 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
137 }
138 else
139 {
140 auto &value =
141 thresholdDeassertMap[m.get_path()][findAssert->first];
142 if (value)
143 {
144 phosphor::logging::log<phosphor::logging::level::INFO>(
145 "thresholdChanged: deassert",
146 phosphor::logging::entry("SENSOR=%s", m.get_path()));
147 value = *ptr;
148 }
149 }
150 }
151 });
152
James Feistaecaef72019-04-26 10:30:32 -0700153static void getSensorMaxMin(const SensorMap &sensorMap, double &max,
154 double &min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700155{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700156 max = 127;
157 min = -128;
158
James Feistaecaef72019-04-26 10:30:32 -0700159 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
160 auto critical =
161 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
162 auto warning =
163 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
164
165 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700166 {
James Feistaecaef72019-04-26 10:30:32 -0700167 auto maxMap = sensorObject->second.find("MaxValue");
168 auto minMap = sensorObject->second.find("MinValue");
169
170 if (maxMap != sensorObject->second.end())
171 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700172 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700173 }
174 if (minMap != sensorObject->second.end())
175 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700176 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700177 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700178 }
James Feistaecaef72019-04-26 10:30:32 -0700179 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700180 {
James Feistaecaef72019-04-26 10:30:32 -0700181 auto lower = critical->second.find("CriticalLow");
182 auto upper = critical->second.find("CriticalHigh");
183 if (lower != critical->second.end())
184 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700185 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700186 min = std::min(value, min);
187 }
188 if (upper != critical->second.end())
189 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700190 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700191 max = std::max(value, max);
192 }
193 }
194 if (warning != sensorMap.end())
195 {
196
197 auto lower = warning->second.find("WarningLow");
198 auto upper = warning->second.find("WarningHigh");
199 if (lower != warning->second.end())
200 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700201 double value = std::visit(VariantToDoubleVisitor(), lower->second);
James Feistaecaef72019-04-26 10:30:32 -0700202 min = std::min(value, min);
203 }
204 if (upper != warning->second.end())
205 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700206 double value = std::visit(VariantToDoubleVisitor(), upper->second);
James Feistaecaef72019-04-26 10:30:32 -0700207 max = std::max(value, max);
208 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700209 }
210}
211
James Feist25690252019-12-23 12:25:49 -0800212static bool getSensorMap(boost::asio::yield_context yield,
213 std::string sensorConnection, std::string sensorPath,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700214 SensorMap &sensorMap)
215{
216 static boost::container::flat_map<
217 std::string, std::chrono::time_point<std::chrono::steady_clock>>
218 updateTimeMap;
219
220 auto updateFind = updateTimeMap.find(sensorConnection);
221 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
222 if (updateFind != updateTimeMap.end())
223 {
224 lastUpdate = updateFind->second;
225 }
226
227 auto now = std::chrono::steady_clock::now();
228
229 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
230 .count() > sensorMapUpdatePeriod)
231 {
232 updateTimeMap[sensorConnection] = now;
233
Vernon Mauery15419dd2019-05-24 09:40:30 -0700234 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800235 boost::system::error_code ec;
236 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
237 yield, ec, sensorConnection.c_str(), "/",
238 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
239 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700240 {
241 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800242 "GetMangagedObjects for getSensorMap failed",
243 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
244
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700245 return false;
246 }
247
248 SensorCache[sensorConnection] = managedObjects;
249 }
250 auto connection = SensorCache.find(sensorConnection);
251 if (connection == SensorCache.end())
252 {
253 return false;
254 }
255 auto path = connection->second.find(sensorPath);
256 if (path == connection->second.end())
257 {
258 return false;
259 }
260 sensorMap = path->second;
261
262 return true;
263}
264
265/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700266namespace meHealth
267{
268constexpr const char *busname = "xyz.openbmc_project.NodeManagerProxy";
269constexpr const char *path = "/xyz/openbmc_project/status/me";
270constexpr const char *interface = "xyz.openbmc_project.SetHealth";
271constexpr const char *method = "SetHealth";
272constexpr const char *critical = "critical";
273constexpr const char *warning = "warning";
274constexpr const char *ok = "ok";
275} // namespace meHealth
276
277static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
278{
279 constexpr const std::array<uint8_t, 10> critical = {
280 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
281 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
282 0x1A};
283
284 std::string state;
285 if (std::find(critical.begin(), critical.end(), eventData2) !=
286 critical.end())
287 {
288 state = meHealth::critical;
289 }
290 // special case 0x3 as we only care about a few states
291 else if (eventData2 == 0x3)
292 {
293 if (eventData3 <= 0x2)
294 {
295 state = meHealth::warning;
296 }
297 else
298 {
299 return;
300 }
301 }
302 else if (std::find(warning.begin(), warning.end(), eventData2) !=
303 warning.end())
304 {
305 state = meHealth::warning;
306 }
307 else
308 {
309 return;
310 }
311 if (disable)
312 {
313 state = meHealth::ok;
314 }
315
316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
317 auto setHealth =
318 dbus->new_method_call(meHealth::busname, meHealth::path,
319 meHealth::interface, meHealth::method);
320 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
321 try
322 {
323 dbus->call(setHealth);
324 }
325 catch (sdbusplus::exception_t &)
326 {
327 phosphor::logging::log<phosphor::logging::level::ERR>(
328 "Failed to set ME Health");
329 }
330}
331
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700332ipmi::RspType<> ipmiSenPlatformEvent(ipmi::message::Payload &p)
333{
James Feist7aaf3fe2019-06-25 11:52:11 -0700334 constexpr const uint8_t meId = 0x2C;
335 constexpr const uint8_t meSensorNum = 0x17;
336 constexpr const uint8_t disabled = 0x80;
337
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700338 uint8_t generatorID = 0;
339 uint8_t evmRev = 0;
340 uint8_t sensorType = 0;
341 uint8_t sensorNum = 0;
342 uint8_t eventType = 0;
343 uint8_t eventData1 = 0;
344 std::optional<uint8_t> eventData2 = 0;
345 std::optional<uint8_t> eventData3 = 0;
346
347 // todo: This check is supposed to be based on the incoming channel.
348 // e.g. system channel will provide upto 8 bytes including generator
349 // ID, but ipmb channel will provide only up to 7 bytes without the
350 // generator ID.
351 // Support for this check is coming in future patches, so for now just base
352 // it on if the first byte is the EvMRev (0x04).
353 if (p.size() && p.data()[0] == 0x04)
354 {
355 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
356 eventData2, eventData3);
357 // todo: the generator ID for this channel is supposed to come from the
358 // IPMB requesters slave address. Support for this is coming in future
359 // patches, so for now just assume it is coming from the ME (0x2C).
360 generatorID = 0x2C;
361 }
362 else
363 {
364 p.unpack(generatorID, evmRev, sensorType, sensorNum, eventType,
365 eventData1, eventData2, eventData3);
366 }
367 if (!p.fullyUnpacked())
368 {
369 return ipmi::responseReqDataLenInvalid();
370 }
371
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700372 // Send this request to the Redfish hooks to log it as a Redfish message
373 // instead. There is no need to add it to the SEL, so just return success.
374 intel_oem::ipmi::sel::checkRedfishHooks(
375 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
376 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700377
James Feist7aaf3fe2019-06-25 11:52:11 -0700378 if (generatorID == meId && sensorNum == meSensorNum && eventData2 &&
379 eventData3)
380 {
381 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
382 }
383
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700384 return ipmi::responseSuccess();
385}
386
James Feist0cd014a2019-04-08 15:04:33 -0700387ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
James Feist25690252019-12-23 12:25:49 -0800388 ipmiSenGetSensorReading(boost::asio::yield_context yield, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700389{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700390 std::string connection;
391 std::string path;
392
393 auto status = getSensorConnection(sensnum, connection, path);
394 if (status)
395 {
James Feist0cd014a2019-04-08 15:04:33 -0700396 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700397 }
398
399 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800400 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700401 {
James Feist0cd014a2019-04-08 15:04:33 -0700402 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700403 }
404 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
405
406 if (sensorObject == sensorMap.end() ||
407 sensorObject->second.find("Value") == sensorObject->second.end())
408 {
James Feist0cd014a2019-04-08 15:04:33 -0700409 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700410 }
James Feist0cd014a2019-04-08 15:04:33 -0700411 auto &valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700412 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700413
Yong Li1f2eb5e2019-05-23 14:07:17 +0800414 double max = 0;
415 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700416 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700417
418 int16_t mValue = 0;
419 int16_t bValue = 0;
420 int8_t rExp = 0;
421 int8_t bExp = 0;
422 bool bSigned = false;
423
424 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
425 {
James Feist0cd014a2019-04-08 15:04:33 -0700426 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700427 }
428
James Feist0cd014a2019-04-08 15:04:33 -0700429 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700430 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700431 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700432 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700433 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800434 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700435
James Feist0cd014a2019-04-08 15:04:33 -0700436 uint8_t thresholds = 0;
437
438 auto warningObject =
439 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
440 if (warningObject != sensorMap.end())
441 {
442 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
443 auto alarmLow = warningObject->second.find("WarningAlarmLow");
444 if (alarmHigh != warningObject->second.end())
445 {
446 if (std::get<bool>(alarmHigh->second))
447 {
448 thresholds |= static_cast<uint8_t>(
449 IPMISensorReadingByte3::upperNonCritical);
450 }
451 }
452 if (alarmLow != warningObject->second.end())
453 {
454 if (std::get<bool>(alarmLow->second))
455 {
456 thresholds |= static_cast<uint8_t>(
457 IPMISensorReadingByte3::lowerNonCritical);
458 }
459 }
460 }
461
462 auto criticalObject =
463 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
464 if (criticalObject != sensorMap.end())
465 {
466 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
467 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
468 if (alarmHigh != criticalObject->second.end())
469 {
470 if (std::get<bool>(alarmHigh->second))
471 {
472 thresholds |=
473 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
474 }
475 }
476 if (alarmLow != criticalObject->second.end())
477 {
478 if (std::get<bool>(alarmLow->second))
479 {
480 thresholds |=
481 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
482 }
483 }
484 }
485
486 // no discrete as of today so optional byte is never returned
487 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700488}
489
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000490/** @brief implements the Set Sensor threshold command
491 * @param sensorNumber - sensor number
492 * @param lowerNonCriticalThreshMask
493 * @param lowerCriticalThreshMask
494 * @param lowerNonRecovThreshMask
495 * @param upperNonCriticalThreshMask
496 * @param upperCriticalThreshMask
497 * @param upperNonRecovThreshMask
498 * @param reserved
499 * @param lowerNonCritical - lower non-critical threshold
500 * @param lowerCritical - Lower critical threshold
501 * @param lowerNonRecoverable - Lower non recovarable threshold
502 * @param upperNonCritical - Upper non-critical threshold
503 * @param upperCritical - Upper critical
504 * @param upperNonRecoverable - Upper Non-recoverable
505 *
506 * @returns IPMI completion code
507 */
508ipmi::RspType<> ipmiSenSetSensorThresholds(
James Feist25690252019-12-23 12:25:49 -0800509 boost::asio::yield_context yield, uint8_t sensorNum,
510 bool lowerNonCriticalThreshMask, bool lowerCriticalThreshMask,
511 bool lowerNonRecovThreshMask, bool upperNonCriticalThreshMask,
512 bool upperCriticalThreshMask, bool upperNonRecovThreshMask,
513 uint2_t reserved, uint8_t lowerNonCritical, uint8_t lowerCritical,
514 uint8_t lowerNonRecoverable, uint8_t upperNonCritical,
515 uint8_t upperCritical, uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700516{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000517 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700518
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000519 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700520 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000521 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700522 }
523
524 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000525 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700526 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000527 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700528 }
529
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000530 // if none of the threshold mask are set, nothing to do
531 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
532 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
533 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700534 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000535 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700536 }
537
538 std::string connection;
539 std::string path;
540
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000541 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700542 if (status)
543 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000544 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700545 }
546 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800547 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700548 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000549 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700550 }
551
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700552 double max = 0;
553 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700554 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700555
556 int16_t mValue = 0;
557 int16_t bValue = 0;
558 int8_t rExp = 0;
559 int8_t bExp = 0;
560 bool bSigned = false;
561
562 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
563 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000564 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700565 }
566
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700567 // store a vector of property name, value to set, and interface
568 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
569
570 // define the indexes of the tuple
571 constexpr uint8_t propertyName = 0;
572 constexpr uint8_t thresholdValue = 1;
573 constexpr uint8_t interface = 2;
574 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000575 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700576 {
577 auto findThreshold =
578 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
579 if (findThreshold == sensorMap.end())
580 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000581 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700582 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000583 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700584 {
585 auto findLower = findThreshold->second.find("CriticalLow");
586 if (findLower == findThreshold->second.end())
587 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000588 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700589 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000590 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700591 findThreshold->first);
592 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000593 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700594 {
595 auto findUpper = findThreshold->second.find("CriticalHigh");
596 if (findUpper == findThreshold->second.end())
597 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000598 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700599 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000600 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700601 findThreshold->first);
602 }
603 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000604 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700605 {
606 auto findThreshold =
607 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
608 if (findThreshold == sensorMap.end())
609 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000610 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700611 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000612 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700613 {
614 auto findLower = findThreshold->second.find("WarningLow");
615 if (findLower == findThreshold->second.end())
616 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000617 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700618 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 findThreshold->first);
621 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000622 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700623 {
624 auto findUpper = findThreshold->second.find("WarningHigh");
625 if (findUpper == findThreshold->second.end())
626 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 findThreshold->first);
631 }
632 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700633 for (const auto &property : thresholdsToSet)
634 {
635 // from section 36.3 in the IPMI Spec, assume all linear
636 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800637 (bValue * std::pow(10.0, bExp))) *
638 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700639 setDbusProperty(
640 *getSdBus(), connection, path, std::get<interface>(property),
641 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700642 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000643 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644}
645
James Feist902c4c52019-04-16 14:51:31 -0700646IPMIThresholds getIPMIThresholds(const SensorMap &sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700647{
James Feist902c4c52019-04-16 14:51:31 -0700648 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700649 auto warningInterface =
650 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
651 auto criticalInterface =
652 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
653
654 if ((warningInterface != sensorMap.end()) ||
655 (criticalInterface != sensorMap.end()))
656 {
657 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
658
659 if (sensorPair == sensorMap.end())
660 {
661 // should not have been able to find a sensor not implementing
662 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700663 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700664 }
665
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800666 double max = 0;
667 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700668 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700669
670 int16_t mValue = 0;
671 int16_t bValue = 0;
672 int8_t rExp = 0;
673 int8_t bExp = 0;
674 bool bSigned = false;
675
676 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
677 {
James Feist902c4c52019-04-16 14:51:31 -0700678 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700679 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700680 if (warningInterface != sensorMap.end())
681 {
682 auto &warningMap = warningInterface->second;
683
684 auto warningHigh = warningMap.find("WarningHigh");
685 auto warningLow = warningMap.find("WarningLow");
686
687 if (warningHigh != warningMap.end())
688 {
James Feist902c4c52019-04-16 14:51:31 -0700689
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700690 double value =
691 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700692 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700693 value, mValue, rExp, bValue, bExp, bSigned);
694 }
695 if (warningLow != warningMap.end())
696 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700697 double value =
698 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700699 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700700 value, mValue, rExp, bValue, bExp, bSigned);
701 }
702 }
703 if (criticalInterface != sensorMap.end())
704 {
705 auto &criticalMap = criticalInterface->second;
706
707 auto criticalHigh = criticalMap.find("CriticalHigh");
708 auto criticalLow = criticalMap.find("CriticalLow");
709
710 if (criticalHigh != criticalMap.end())
711 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700712 double value =
713 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700714 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700715 value, mValue, rExp, bValue, bExp, bSigned);
716 }
717 if (criticalLow != criticalMap.end())
718 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700719 double value =
720 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700721 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700722 value, mValue, rExp, bValue, bExp, bSigned);
723 }
724 }
725 }
James Feist902c4c52019-04-16 14:51:31 -0700726 return resp;
727}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700728
James Feist902c4c52019-04-16 14:51:31 -0700729ipmi::RspType<uint8_t, // readable
730 uint8_t, // lowerNCrit
731 uint8_t, // lowerCrit
732 uint8_t, // lowerNrecoverable
733 uint8_t, // upperNC
734 uint8_t, // upperCrit
735 uint8_t> // upperNRecoverable
James Feist25690252019-12-23 12:25:49 -0800736 ipmiSenGetSensorThresholds(boost::asio::yield_context yield,
737 uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700738{
739 std::string connection;
740 std::string path;
741
742 auto status = getSensorConnection(sensorNumber, connection, path);
743 if (status)
744 {
745 return ipmi::response(status);
746 }
747
748 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800749 if (!getSensorMap(yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700750 {
751 return ipmi::responseResponseError();
752 }
753
754 IPMIThresholds thresholdData;
755 try
756 {
757 thresholdData = getIPMIThresholds(sensorMap);
758 }
759 catch (std::exception &)
760 {
761 return ipmi::responseResponseError();
762 }
763
764 uint8_t readable = 0;
765 uint8_t lowerNC = 0;
766 uint8_t lowerCritical = 0;
767 uint8_t lowerNonRecoverable = 0;
768 uint8_t upperNC = 0;
769 uint8_t upperCritical = 0;
770 uint8_t upperNonRecoverable = 0;
771
772 if (thresholdData.warningHigh)
773 {
774 readable |=
775 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
776 upperNC = *thresholdData.warningHigh;
777 }
778 if (thresholdData.warningLow)
779 {
780 readable |=
781 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
782 lowerNC = *thresholdData.warningLow;
783 }
784
785 if (thresholdData.criticalHigh)
786 {
787 readable |=
788 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
789 upperCritical = *thresholdData.criticalHigh;
790 }
791 if (thresholdData.criticalLow)
792 {
793 readable |=
794 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
795 lowerCritical = *thresholdData.criticalLow;
796 }
797
798 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
799 lowerNonRecoverable, upperNC, upperCritical,
800 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700801}
802
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000803/** @brief implements the get Sensor event enable command
804 * @param sensorNumber - sensor number
805 *
806 * @returns IPMI completion code plus response data
807 * - enabled - Sensor Event messages
808 * - assertionEnabledLsb - Assertion event messages
809 * - assertionEnabledMsb - Assertion event messages
810 * - deassertionEnabledLsb - Deassertion event messages
811 * - deassertionEnabledMsb - Deassertion event messages
812 */
813
814ipmi::RspType<uint8_t, // enabled
815 uint8_t, // assertionEnabledLsb
816 uint8_t, // assertionEnabledMsb
817 uint8_t, // deassertionEnabledLsb
818 uint8_t> // deassertionEnabledMsb
James Feist25690252019-12-23 12:25:49 -0800819 ipmiSenGetSensorEventEnable(boost::asio::yield_context yield,
820 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700821{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700822 std::string connection;
823 std::string path;
824
Patrick Venturea41714c2019-09-25 16:59:41 -0700825 uint8_t enabled = 0;
826 uint8_t assertionEnabledLsb = 0;
827 uint8_t assertionEnabledMsb = 0;
828 uint8_t deassertionEnabledLsb = 0;
829 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000830
831 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700832 if (status)
833 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000834 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700835 }
836
837 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800838 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700839 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000840 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700841 }
842
843 auto warningInterface =
844 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
845 auto criticalInterface =
846 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700847 if ((warningInterface != sensorMap.end()) ||
848 (criticalInterface != sensorMap.end()))
849 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000850 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700851 IPMISensorEventEnableByte2::sensorScanningEnable);
852 if (warningInterface != sensorMap.end())
853 {
854 auto &warningMap = warningInterface->second;
855
856 auto warningHigh = warningMap.find("WarningHigh");
857 auto warningLow = warningMap.find("WarningLow");
858 if (warningHigh != warningMap.end())
859 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000860 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700861 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000862 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700863 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
864 }
865 if (warningLow != warningMap.end())
866 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000867 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700868 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000869 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700870 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
871 }
872 }
873 if (criticalInterface != sensorMap.end())
874 {
875 auto &criticalMap = criticalInterface->second;
876
877 auto criticalHigh = criticalMap.find("CriticalHigh");
878 auto criticalLow = criticalMap.find("CriticalLow");
879
880 if (criticalHigh != criticalMap.end())
881 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000882 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700883 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000884 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700885 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
886 }
887 if (criticalLow != criticalMap.end())
888 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000889 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700890 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000891 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700892 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
893 }
894 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700895 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000896
897 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
898 assertionEnabledMsb, deassertionEnabledLsb,
899 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700900}
901
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000902/** @brief implements the get Sensor event status command
903 * @param sensorNumber - sensor number, FFh = reserved
904 *
905 * @returns IPMI completion code plus response data
906 * - sensorEventStatus - Sensor Event messages state
907 * - assertions - Assertion event messages
908 * - deassertions - Deassertion event messages
909 */
910ipmi::RspType<uint8_t, // sensorEventStatus
911 std::bitset<16>, // assertions
912 std::bitset<16> // deassertion
913 >
James Feist25690252019-12-23 12:25:49 -0800914 ipmiSenGetSensorEventStatus(boost::asio::yield_context yield,
915 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700916{
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000917 if (sensorNum == 0xFF)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700918 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000919 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700920 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700921
922 std::string connection;
923 std::string path;
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000924 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700925 if (status)
926 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000927 phosphor::logging::log<phosphor::logging::level::ERR>(
928 "ipmiSenGetSensorEventStatus: Sensor connection Error",
929 phosphor::logging::entry("SENSOR=%d", sensorNum));
930 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700931 }
932
933 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800934 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700935 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000936 phosphor::logging::log<phosphor::logging::level::ERR>(
937 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
938 phosphor::logging::entry("SENSOR=%s", path.c_str()));
939 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700940 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700941 auto warningInterface =
942 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
943 auto criticalInterface =
944 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
945
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000946 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700947 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
948
James Feist392786a2019-03-19 13:36:10 -0700949 std::optional<bool> criticalDeassertHigh =
950 thresholdDeassertMap[path]["CriticalAlarmHigh"];
951 std::optional<bool> criticalDeassertLow =
952 thresholdDeassertMap[path]["CriticalAlarmLow"];
953 std::optional<bool> warningDeassertHigh =
954 thresholdDeassertMap[path]["WarningAlarmHigh"];
955 std::optional<bool> warningDeassertLow =
956 thresholdDeassertMap[path]["WarningAlarmLow"];
957
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000958 std::bitset<16> assertions = 0;
959 std::bitset<16> deassertions = 0;
960
James Feist392786a2019-03-19 13:36:10 -0700961 if (criticalDeassertHigh && !*criticalDeassertHigh)
962 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000963 deassertions.set(static_cast<size_t>(
964 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700965 }
966 if (criticalDeassertLow && !*criticalDeassertLow)
967 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000968 deassertions.set(static_cast<size_t>(
969 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -0700970 }
971 if (warningDeassertHigh && !*warningDeassertHigh)
972 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000973 deassertions.set(static_cast<size_t>(
974 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700975 }
976 if (warningDeassertLow && !*warningDeassertLow)
977 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000978 deassertions.set(static_cast<size_t>(
979 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700980 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700981 if ((warningInterface != sensorMap.end()) ||
982 (criticalInterface != sensorMap.end()))
983 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000984 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700985 IPMISensorEventEnableByte2::eventMessagesEnable);
986 if (warningInterface != sensorMap.end())
987 {
988 auto &warningMap = warningInterface->second;
989
990 auto warningHigh = warningMap.find("WarningAlarmHigh");
991 auto warningLow = warningMap.find("WarningAlarmLow");
992 auto warningHighAlarm = false;
993 auto warningLowAlarm = false;
994
995 if (warningHigh != warningMap.end())
996 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700997 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700998 }
999 if (warningLow != warningMap.end())
1000 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001001 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001002 }
1003 if (warningHighAlarm)
1004 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001005 assertions.set(
1006 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1007 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001008 }
1009 if (warningLowAlarm)
1010 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001011 assertions.set(
1012 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1013 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001014 }
1015 }
1016 if (criticalInterface != sensorMap.end())
1017 {
1018 auto &criticalMap = criticalInterface->second;
1019
1020 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1021 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1022 auto criticalHighAlarm = false;
1023 auto criticalLowAlarm = false;
1024
1025 if (criticalHigh != criticalMap.end())
1026 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001027 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001028 }
1029 if (criticalLow != criticalMap.end())
1030 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001031 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001032 }
1033 if (criticalHighAlarm)
1034 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001035 assertions.set(
1036 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1037 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001038 }
1039 if (criticalLowAlarm)
1040 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001041 assertions.set(static_cast<size_t>(
1042 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001043 }
1044 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001045 }
1046
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001047 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001048}
1049
1050/* end sensor commands */
1051
1052/* storage commands */
1053
James Feist74c50c62019-08-14 14:18:41 -07001054ipmi::RspType<uint8_t, // sdr version
1055 uint16_t, // record count
1056 uint16_t, // free space
1057 uint32_t, // most recent addition
1058 uint32_t, // most recent erase
1059 uint8_t // operationSupport
1060 >
James Feist25690252019-12-23 12:25:49 -08001061 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001062{
James Feist74c50c62019-08-14 14:18:41 -07001063 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001064 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1065 {
James Feist74c50c62019-08-14 14:18:41 -07001066 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001067 }
1068
James Feist74c50c62019-08-14 14:18:41 -07001069 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001070 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001071 if (ret != ipmi::ccSuccess)
1072 {
1073 return ipmi::response(ret);
1074 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001075
James Feist74c50c62019-08-14 14:18:41 -07001076 uint16_t recordCount =
1077 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001078
James Feist74c50c62019-08-14 14:18:41 -07001079 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001080 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001081
1082 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001083 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001084 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001085 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001086 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1087 unspecifiedFreeSpace, sdrLastAdd,
1088 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001089}
1090
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001091/** @brief implements the get SDR allocation info command
1092 *
1093 * @returns IPMI completion code plus response data
1094 * - allocUnits - Number of possible allocation units
1095 * - allocUnitSize - Allocation unit size in bytes.
1096 * - allocUnitFree - Number of free allocation units
1097 * - allocUnitLargestFree - Largest free block in allocation units
1098 * - maxRecordSize - Maximum record size in allocation units.
1099 */
1100ipmi::RspType<uint16_t, // allocUnits
1101 uint16_t, // allocUnitSize
1102 uint16_t, // allocUnitFree
1103 uint16_t, // allocUnitLargestFree
1104 uint8_t // maxRecordSize
1105 >
1106 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001107{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001108 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001109 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001110
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001111 constexpr uint16_t allocUnitFree = 0;
1112 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001113 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001114 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001116 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1117 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001118}
1119
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001120/** @brief implements the reserve SDR command
1121 * @returns IPMI completion code plus response data
1122 * - sdrReservationID
1123 */
1124ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001125{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001126 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001127 if (sdrReservationID == 0)
1128 {
1129 sdrReservationID++;
1130 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001131
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001132 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133}
1134
James Feistb49a98a2019-04-16 13:48:09 -07001135ipmi::RspType<uint16_t, // next record ID
1136 std::vector<uint8_t> // payload
1137 >
James Feist25690252019-12-23 12:25:49 -08001138 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1139 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001140{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001141 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142
1143 // reservation required for partial reads with non zero offset into
1144 // record
James Feistb49a98a2019-04-16 13:48:09 -07001145 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001146 {
James Feistb49a98a2019-04-16 13:48:09 -07001147 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001148 }
1149
1150 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1151 {
James Feistb49a98a2019-04-16 13:48:09 -07001152 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001153 }
1154
1155 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001156 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001157 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001158 {
James Feistb49a98a2019-04-16 13:48:09 -07001159 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001160 }
1161
Yong Lifee5e4c2020-01-17 19:36:29 +08001162 size_t lastRecord = sensorTree.size() + fruCount +
1163 ipmi::storage::type12Count +
1164 ipmi::storage::nmDiscoverySDRCount - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001165 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001166 {
James Feistb49a98a2019-04-16 13:48:09 -07001167 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168 }
James Feistb49a98a2019-04-16 13:48:09 -07001169 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001170 {
James Feistb49a98a2019-04-16 13:48:09 -07001171 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 }
1173
James Feistb49a98a2019-04-16 13:48:09 -07001174 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001175
James Feistb49a98a2019-04-16 13:48:09 -07001176 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001177 {
James Feist74c50c62019-08-14 14:18:41 -07001178 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001179 size_t fruIndex = recordID - sensorTree.size();
Yong Lifee5e4c2020-01-17 19:36:29 +08001180 size_t type12End = fruCount + ipmi::storage::type12Count;
1181
1182 if (fruIndex >= type12End)
1183 {
1184 // NM discovery SDR
1185 size_t nmDiscoveryIndex = fruIndex - type12End;
1186 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount ||
1187 offset > sizeof(NMDiscoveryRecord))
1188 {
1189 return ipmi::responseInvalidFieldRequest();
1190 }
1191
1192 std::vector<uint8_t> record =
1193 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
1194 if (record.size() < (offset + bytesToRead))
1195 {
1196 bytesToRead = record.size() - offset;
1197 }
1198 recordData.insert(recordData.end(), record.begin() + offset,
1199 record.begin() + offset + bytesToRead);
1200 }
1201 else if (fruIndex >= fruCount)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001202 {
James Feist74c50c62019-08-14 14:18:41 -07001203 // handle type 12 hardcoded records
1204 size_t type12Index = fruIndex - fruCount;
1205 if (type12Index >= ipmi::storage::type12Count ||
1206 offset > sizeof(Type12Record))
1207 {
1208 return ipmi::responseInvalidFieldRequest();
1209 }
1210 std::vector<uint8_t> record =
1211 ipmi::storage::getType12SDRs(type12Index, recordID);
1212 if (record.size() < (offset + bytesToRead))
1213 {
1214 bytesToRead = record.size() - offset;
1215 }
James Feistb49a98a2019-04-16 13:48:09 -07001216
James Feist74c50c62019-08-14 14:18:41 -07001217 recordData.insert(recordData.end(), record.begin() + offset,
1218 record.begin() + offset + bytesToRead);
1219 }
1220 else
1221 {
1222 // handle fru records
1223 get_sdr::SensorDataFruRecord data;
1224 if (offset > sizeof(data))
1225 {
1226 return ipmi::responseInvalidFieldRequest();
1227 }
James Feist25690252019-12-23 12:25:49 -08001228 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
James Feist74c50c62019-08-14 14:18:41 -07001229 if (ret != IPMI_CC_OK)
1230 {
1231 return ipmi::response(ret);
1232 }
1233 data.header.record_id_msb = recordID << 8;
1234 data.header.record_id_lsb = recordID & 0xFF;
1235 if (sizeof(data) < (offset + bytesToRead))
1236 {
1237 bytesToRead = sizeof(data) - offset;
1238 }
1239
1240 uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
1241 recordData.insert(recordData.end(), respStart,
1242 respStart + bytesToRead);
1243 }
James Feistb49a98a2019-04-16 13:48:09 -07001244
1245 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001246 }
1247
1248 std::string connection;
1249 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001250 uint16_t sensorIndex = recordID;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001251 for (const auto &sensor : sensorTree)
1252 {
1253 if (sensorIndex-- == 0)
1254 {
1255 if (!sensor.second.size())
1256 {
James Feistb49a98a2019-04-16 13:48:09 -07001257 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001258 }
1259 connection = sensor.second.begin()->first;
1260 path = sensor.first;
1261 break;
1262 }
1263 }
1264
1265 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -08001266 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001267 {
James Feistb49a98a2019-04-16 13:48:09 -07001268 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001269 }
James Feistb49a98a2019-04-16 13:48:09 -07001270 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001271 get_sdr::SensorDataFullRecord record = {0};
1272
James Feistb49a98a2019-04-16 13:48:09 -07001273 record.header.record_id_msb = recordID << 8;
1274 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001275 record.header.sdr_version = ipmiSdrVersion;
1276 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1277 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1278 sizeof(get_sdr::SensorDataRecordHeader);
1279 record.key.owner_id = 0x20;
1280 record.key.owner_lun = 0x0;
1281 record.key.sensor_number = sensornumber;
1282
James Feist7086a882019-03-13 10:46:00 -07001283 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001284 record.body.sensor_type = getSensorTypeFromPath(path);
1285 std::string type = getSensorTypeStringFromPath(path);
1286 auto typeCstr = type.c_str();
1287 auto findUnits = sensorUnits.find(typeCstr);
1288 if (findUnits != sensorUnits.end())
1289 {
1290 record.body.sensor_units_2_base =
1291 static_cast<uint8_t>(findUnits->second);
1292 } // else default 0x0 unspecified
1293
1294 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1295
1296 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1297 if (sensorObject == sensorMap.end())
1298 {
James Feistb49a98a2019-04-16 13:48:09 -07001299 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001300 }
1301
Patrick Venture262276f2019-10-18 13:27:59 -07001302 uint8_t entityId = 0;
1303 uint8_t entityInstance = 0x01;
1304
1305 // follow the association chain to get the parent board's entityid and
1306 // entityInstance
1307 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1308
1309 record.body.entity_id = entityId;
1310 record.body.entity_instance = entityInstance;
1311
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001312 auto maxObject = sensorObject->second.find("MaxValue");
1313 auto minObject = sensorObject->second.find("MinValue");
Josh Lehanca9dcbd2019-11-18 15:59:59 -08001314
1315 // If min and/or max are left unpopulated,
1316 // then default to what a signed byte would be, namely (-128,127) range.
1317 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1318 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001319 if (maxObject != sensorObject->second.end())
1320 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001321 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001322 }
1323
1324 if (minObject != sensorObject->second.end())
1325 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001326 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001327 }
1328
Yong Li1f2eb5e2019-05-23 14:07:17 +08001329 int16_t mValue = 0;
1330 int8_t rExp = 0;
1331 int16_t bValue = 0;
1332 int8_t bExp = 0;
1333 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001334
1335 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1336 {
James Feistb49a98a2019-04-16 13:48:09 -07001337 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001338 }
1339
Josh Lehan7cc9e472019-11-18 16:09:26 -08001340 // The record.body is a struct SensorDataFullRecordBody
1341 // from sensorhandler.hpp in phosphor-ipmi-host.
1342 // The meaning of these bits appears to come from
1343 // table 43.1 of the IPMI spec.
1344 // The above 5 sensor attributes are stuffed in as follows:
1345 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1346 // Byte 22-24 are for other purposes
1347 // Byte 25 = MMMMMMMM = LSB of M
1348 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1349 // Byte 27 = BBBBBBBB = LSB of B
1350 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1351 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1352 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1353
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001354 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1355 record.body.m_lsb = mValue & 0xFF;
1356
Josh Lehan7cc9e472019-11-18 16:09:26 -08001357 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1358 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1359
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001360 // move the smallest bit of the MSB into place (bit 9)
1361 // the MSbs are bits 7:8 in m_msb_and_tolerance
Josh Lehan7cc9e472019-11-18 16:09:26 -08001362 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001363
1364 record.body.b_lsb = bValue & 0xFF;
1365
Josh Lehan7cc9e472019-11-18 16:09:26 -08001366 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1367 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1368
1369 // move the smallest bit of the MSB into place (bit 9)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001370 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
Josh Lehan7cc9e472019-11-18 16:09:26 -08001371 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001372
Josh Lehan7cc9e472019-11-18 16:09:26 -08001373 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1374 uint8_t rExpBits = rExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001375
Josh Lehan7cc9e472019-11-18 16:09:26 -08001376 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1377 uint8_t bExpBits = bExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001378
Josh Lehan7cc9e472019-11-18 16:09:26 -08001379 // move rExp and bExp into place
1380 record.body.r_b_exponents =
1381 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1382
1383 // Set the analog reading byte interpretation accordingly
1384 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1385
1386 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1387 // These seem redundant, but derivable from the above 5 attributes
1388 // Original comment said "todo fill out rest of units"
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001389
1390 // populate sensor name from path
1391 std::string name;
1392 size_t nameStart = path.rfind("/");
1393 if (nameStart != std::string::npos)
1394 {
1395 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1396 }
1397
1398 std::replace(name.begin(), name.end(), '_', ' ');
1399 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1400 {
James Feist979a2322019-05-15 09:06:54 -07001401 // try to not truncate by replacing common words
1402 constexpr std::array<std::pair<const char *, const char *>, 2>
1403 replaceWords = {std::make_pair("Output", "Out"),
1404 std::make_pair("Input", "In")};
1405 for (const auto &[find, replace] : replaceWords)
1406 {
1407 boost::replace_all(name, find, replace);
1408 }
1409
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001410 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1411 }
1412 record.body.id_string_info = name.size();
1413 std::strncpy(record.body.id_string, name.c_str(),
1414 sizeof(record.body.id_string));
1415
James Feistc4b15bc2019-04-16 15:41:39 -07001416 IPMIThresholds thresholdData;
1417 try
1418 {
1419 thresholdData = getIPMIThresholds(sensorMap);
1420 }
1421 catch (std::exception &)
1422 {
1423 return ipmi::responseResponseError();
1424 }
1425
1426 if (thresholdData.criticalHigh)
1427 {
1428 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1429 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
Rashmi RV963a95b2020-01-27 15:09:17 +05301430 IPMISensorEventEnableThresholds::criticalThreshold);
1431 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
James Feistc4b15bc2019-04-16 15:41:39 -07001432 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1433 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1434 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1435 record.body.discrete_reading_setting_mask[0] |=
1436 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1437 }
1438 if (thresholdData.warningHigh)
1439 {
1440 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
Rashmi RV963a95b2020-01-27 15:09:17 +05301441 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1442 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001443 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1444 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1445 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1446 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1447 record.body.discrete_reading_setting_mask[0] |=
1448 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1449 }
1450 if (thresholdData.criticalLow)
1451 {
1452 record.body.lower_critical_threshold = *thresholdData.criticalLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301453 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1454 IPMISensorEventEnableThresholds::criticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001455 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1456 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1457 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1458 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1459 record.body.discrete_reading_setting_mask[0] |=
1460 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1461 }
1462 if (thresholdData.warningLow)
1463 {
1464 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301465 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1466 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001467 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1468 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1469 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1470 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1471 record.body.discrete_reading_setting_mask[0] |=
1472 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1473 }
1474
1475 // everything that is readable is setable
1476 record.body.discrete_reading_setting_mask[1] =
1477 record.body.discrete_reading_setting_mask[0];
1478
James Feistb49a98a2019-04-16 13:48:09 -07001479 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001480 {
James Feistb49a98a2019-04-16 13:48:09 -07001481 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001482 }
1483
James Feistb49a98a2019-04-16 13:48:09 -07001484 uint8_t *respStart = reinterpret_cast<uint8_t *>(&record) + offset;
1485 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001486
James Feistb49a98a2019-04-16 13:48:09 -07001487 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001488}
1489/* end storage commands */
1490
1491void registerSensorFunctions()
1492{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001493 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001494 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1495 ipmi::sensor_event::cmdPlatformEvent,
1496 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001497
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001498 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001499 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1500 ipmi::sensor_event::cmdGetSensorReading,
1501 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001502
1503 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001504 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1505 ipmi::sensor_event::cmdGetSensorThreshold,
1506 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001507
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001508 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001509 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1510 ipmi::sensor_event::cmdSetSensorThreshold,
1511 ipmi::Privilege::Operator,
1512 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001513
1514 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001515 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1516 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001517 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001518
1519 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001520 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1521 ipmi::sensor_event::cmdGetSensorEventStatus,
1522 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001523
1524 // register all storage commands for both Sensor and Storage command
1525 // versions
1526
1527 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001528 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1529 ipmi::storage::cmdGetSdrRepositoryInfo,
1530 ipmi::Privilege::User,
1531 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001532
1533 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001534 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1535 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1536 ipmi::Privilege::User,
1537 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001538
1539 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001540 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1541 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001542 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001543
Vernon Mauery98bbf692019-09-16 11:14:59 -07001544 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1545 ipmi::storage::cmdReserveSdrRepository,
1546 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001547
1548 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001549 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1550 ipmi::sensor_event::cmdGetDeviceSdr,
1551 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001552
Vernon Mauery98bbf692019-09-16 11:14:59 -07001553 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1554 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1555 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001556}
1557} // namespace ipmi