blob: a226cb9212dd911f0b251bd9eadbdc21dba405cd [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);
James Feist1ee6ed82020-06-17 16:16:50 -0700436 bool notReading = std::isnan(reading);
437
438 if (!notReading)
439 {
440 auto availableObject =
441 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
442 if (availableObject != sensorMap.end())
443 {
444 auto findAvailable = availableObject->second.find("Available");
445 if (findAvailable != availableObject->second.end())
446 {
447 bool* available = std::get_if<bool>(&(findAvailable->second));
448 if (available && !(*available))
449 {
450 notReading = true;
451 }
452 }
453 }
454 }
455
456 if (notReading)
457 {
458 operation |= static_cast<uint8_t>(
459 IPMISensorReadingByte2::readingStateUnavailable);
460 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700461
James Feist0cd014a2019-04-08 15:04:33 -0700462 uint8_t thresholds = 0;
463
464 auto warningObject =
465 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
466 if (warningObject != sensorMap.end())
467 {
468 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
469 auto alarmLow = warningObject->second.find("WarningAlarmLow");
470 if (alarmHigh != warningObject->second.end())
471 {
472 if (std::get<bool>(alarmHigh->second))
473 {
474 thresholds |= static_cast<uint8_t>(
475 IPMISensorReadingByte3::upperNonCritical);
476 }
477 }
478 if (alarmLow != warningObject->second.end())
479 {
480 if (std::get<bool>(alarmLow->second))
481 {
482 thresholds |= static_cast<uint8_t>(
483 IPMISensorReadingByte3::lowerNonCritical);
484 }
485 }
486 }
487
488 auto criticalObject =
489 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
490 if (criticalObject != sensorMap.end())
491 {
492 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
493 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
494 if (alarmHigh != criticalObject->second.end())
495 {
496 if (std::get<bool>(alarmHigh->second))
497 {
498 thresholds |=
499 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
500 }
501 }
502 if (alarmLow != criticalObject->second.end())
503 {
504 if (std::get<bool>(alarmLow->second))
505 {
506 thresholds |=
507 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
508 }
509 }
510 }
511
512 // no discrete as of today so optional byte is never returned
513 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700514}
515
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000516/** @brief implements the Set Sensor threshold command
517 * @param sensorNumber - sensor number
518 * @param lowerNonCriticalThreshMask
519 * @param lowerCriticalThreshMask
520 * @param lowerNonRecovThreshMask
521 * @param upperNonCriticalThreshMask
522 * @param upperCriticalThreshMask
523 * @param upperNonRecovThreshMask
524 * @param reserved
525 * @param lowerNonCritical - lower non-critical threshold
526 * @param lowerCritical - Lower critical threshold
527 * @param lowerNonRecoverable - Lower non recovarable threshold
528 * @param upperNonCritical - Upper non-critical threshold
529 * @param upperCritical - Upper critical
530 * @param upperNonRecoverable - Upper Non-recoverable
531 *
532 * @returns IPMI completion code
533 */
534ipmi::RspType<> ipmiSenSetSensorThresholds(
James Feist25690252019-12-23 12:25:49 -0800535 boost::asio::yield_context yield, uint8_t sensorNum,
536 bool lowerNonCriticalThreshMask, bool lowerCriticalThreshMask,
537 bool lowerNonRecovThreshMask, bool upperNonCriticalThreshMask,
538 bool upperCriticalThreshMask, bool upperNonRecovThreshMask,
539 uint2_t reserved, uint8_t lowerNonCritical, uint8_t lowerCritical,
540 uint8_t lowerNonRecoverable, uint8_t upperNonCritical,
541 uint8_t upperCritical, uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700542{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000543 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700544
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000545 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700546 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000547 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700548 }
549
550 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000551 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700552 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000553 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700554 }
555
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000556 // if none of the threshold mask are set, nothing to do
557 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
558 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
559 upperCriticalThreshMask | upperNonRecovThreshMask))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700560 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000561 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700562 }
563
564 std::string connection;
565 std::string path;
566
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000567 ipmi::Cc status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700568 if (status)
569 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000570 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700571 }
572 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800573 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700574 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000575 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700576 }
577
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700578 double max = 0;
579 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700580 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700581
582 int16_t mValue = 0;
583 int16_t bValue = 0;
584 int8_t rExp = 0;
585 int8_t bExp = 0;
586 bool bSigned = false;
587
588 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
589 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000590 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700591 }
592
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700593 // store a vector of property name, value to set, and interface
594 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
595
596 // define the indexes of the tuple
597 constexpr uint8_t propertyName = 0;
598 constexpr uint8_t thresholdValue = 1;
599 constexpr uint8_t interface = 2;
600 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000601 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700602 {
603 auto findThreshold =
604 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
605 if (findThreshold == sensorMap.end())
606 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000607 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700608 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000609 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700610 {
611 auto findLower = findThreshold->second.find("CriticalLow");
612 if (findLower == findThreshold->second.end())
613 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000614 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700615 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000616 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700617 findThreshold->first);
618 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000619 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700620 {
621 auto findUpper = findThreshold->second.find("CriticalHigh");
622 if (findUpper == findThreshold->second.end())
623 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000624 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700625 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000626 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700627 findThreshold->first);
628 }
629 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000630 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700631 {
632 auto findThreshold =
633 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
634 if (findThreshold == sensorMap.end())
635 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000636 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700637 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700639 {
640 auto findLower = findThreshold->second.find("WarningLow");
641 if (findLower == findThreshold->second.end())
642 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000643 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700644 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000645 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700646 findThreshold->first);
647 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000648 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700649 {
650 auto findUpper = findThreshold->second.find("WarningHigh");
651 if (findUpper == findThreshold->second.end())
652 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000653 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700654 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000655 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700656 findThreshold->first);
657 }
658 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700659 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660 {
661 // from section 36.3 in the IPMI Spec, assume all linear
662 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800663 (bValue * std::pow(10.0, bExp))) *
664 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700665 setDbusProperty(
666 *getSdBus(), connection, path, std::get<interface>(property),
667 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700668 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000669 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700670}
671
James Feistfcd2d3a2020-05-28 10:38:15 -0700672IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700673{
James Feist902c4c52019-04-16 14:51:31 -0700674 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700675 auto warningInterface =
676 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
677 auto criticalInterface =
678 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
679
680 if ((warningInterface != sensorMap.end()) ||
681 (criticalInterface != sensorMap.end()))
682 {
683 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
684
685 if (sensorPair == sensorMap.end())
686 {
687 // should not have been able to find a sensor not implementing
688 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700689 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700690 }
691
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800692 double max = 0;
693 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700694 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700695
696 int16_t mValue = 0;
697 int16_t bValue = 0;
698 int8_t rExp = 0;
699 int8_t bExp = 0;
700 bool bSigned = false;
701
702 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
703 {
James Feist902c4c52019-04-16 14:51:31 -0700704 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700705 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700706 if (warningInterface != sensorMap.end())
707 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700708 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700709
710 auto warningHigh = warningMap.find("WarningHigh");
711 auto warningLow = warningMap.find("WarningLow");
712
713 if (warningHigh != warningMap.end())
714 {
James Feist902c4c52019-04-16 14:51:31 -0700715
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700716 double value =
717 std::visit(VariantToDoubleVisitor(), warningHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700718 resp.warningHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700719 value, mValue, rExp, bValue, bExp, bSigned);
720 }
721 if (warningLow != warningMap.end())
722 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700723 double value =
724 std::visit(VariantToDoubleVisitor(), warningLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700725 resp.warningLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700726 value, mValue, rExp, bValue, bExp, bSigned);
727 }
728 }
729 if (criticalInterface != sensorMap.end())
730 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700731 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700732
733 auto criticalHigh = criticalMap.find("CriticalHigh");
734 auto criticalLow = criticalMap.find("CriticalLow");
735
736 if (criticalHigh != criticalMap.end())
737 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700738 double value =
739 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
James Feist902c4c52019-04-16 14:51:31 -0700740 resp.criticalHigh = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700741 value, mValue, rExp, bValue, bExp, bSigned);
742 }
743 if (criticalLow != criticalMap.end())
744 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700745 double value =
746 std::visit(VariantToDoubleVisitor(), criticalLow->second);
James Feist902c4c52019-04-16 14:51:31 -0700747 resp.criticalLow = scaleIPMIValueFromDouble(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700748 value, mValue, rExp, bValue, bExp, bSigned);
749 }
750 }
751 }
James Feist902c4c52019-04-16 14:51:31 -0700752 return resp;
753}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700754
James Feist902c4c52019-04-16 14:51:31 -0700755ipmi::RspType<uint8_t, // readable
756 uint8_t, // lowerNCrit
757 uint8_t, // lowerCrit
758 uint8_t, // lowerNrecoverable
759 uint8_t, // upperNC
760 uint8_t, // upperCrit
761 uint8_t> // upperNRecoverable
James Feist25690252019-12-23 12:25:49 -0800762 ipmiSenGetSensorThresholds(boost::asio::yield_context yield,
763 uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700764{
765 std::string connection;
766 std::string path;
767
768 auto status = getSensorConnection(sensorNumber, connection, path);
769 if (status)
770 {
771 return ipmi::response(status);
772 }
773
774 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800775 if (!getSensorMap(yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700776 {
777 return ipmi::responseResponseError();
778 }
779
780 IPMIThresholds thresholdData;
781 try
782 {
783 thresholdData = getIPMIThresholds(sensorMap);
784 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700785 catch (std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700786 {
787 return ipmi::responseResponseError();
788 }
789
790 uint8_t readable = 0;
791 uint8_t lowerNC = 0;
792 uint8_t lowerCritical = 0;
793 uint8_t lowerNonRecoverable = 0;
794 uint8_t upperNC = 0;
795 uint8_t upperCritical = 0;
796 uint8_t upperNonRecoverable = 0;
797
798 if (thresholdData.warningHigh)
799 {
800 readable |=
801 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
802 upperNC = *thresholdData.warningHigh;
803 }
804 if (thresholdData.warningLow)
805 {
806 readable |=
807 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
808 lowerNC = *thresholdData.warningLow;
809 }
810
811 if (thresholdData.criticalHigh)
812 {
813 readable |=
814 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
815 upperCritical = *thresholdData.criticalHigh;
816 }
817 if (thresholdData.criticalLow)
818 {
819 readable |=
820 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
821 lowerCritical = *thresholdData.criticalLow;
822 }
823
824 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
825 lowerNonRecoverable, upperNC, upperCritical,
826 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700827}
828
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000829/** @brief implements the get Sensor event enable command
830 * @param sensorNumber - sensor number
831 *
832 * @returns IPMI completion code plus response data
833 * - enabled - Sensor Event messages
834 * - assertionEnabledLsb - Assertion event messages
835 * - assertionEnabledMsb - Assertion event messages
836 * - deassertionEnabledLsb - Deassertion event messages
837 * - deassertionEnabledMsb - Deassertion event messages
838 */
839
840ipmi::RspType<uint8_t, // enabled
841 uint8_t, // assertionEnabledLsb
842 uint8_t, // assertionEnabledMsb
843 uint8_t, // deassertionEnabledLsb
844 uint8_t> // deassertionEnabledMsb
James Feist25690252019-12-23 12:25:49 -0800845 ipmiSenGetSensorEventEnable(boost::asio::yield_context yield,
846 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700847{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700848 std::string connection;
849 std::string path;
850
Patrick Venturea41714c2019-09-25 16:59:41 -0700851 uint8_t enabled = 0;
852 uint8_t assertionEnabledLsb = 0;
853 uint8_t assertionEnabledMsb = 0;
854 uint8_t deassertionEnabledLsb = 0;
855 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000856
857 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700858 if (status)
859 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000860 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700861 }
862
863 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800864 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700865 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000866 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700867 }
868
869 auto warningInterface =
870 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
871 auto criticalInterface =
872 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700873 if ((warningInterface != sensorMap.end()) ||
874 (criticalInterface != sensorMap.end()))
875 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000876 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700877 IPMISensorEventEnableByte2::sensorScanningEnable);
878 if (warningInterface != sensorMap.end())
879 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700880 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700881
882 auto warningHigh = warningMap.find("WarningHigh");
883 auto warningLow = warningMap.find("WarningLow");
884 if (warningHigh != warningMap.end())
885 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000886 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700887 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000888 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700889 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
890 }
891 if (warningLow != warningMap.end())
892 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000893 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700894 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000895 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700896 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
897 }
898 }
899 if (criticalInterface != sensorMap.end())
900 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700901 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700902
903 auto criticalHigh = criticalMap.find("CriticalHigh");
904 auto criticalLow = criticalMap.find("CriticalLow");
905
906 if (criticalHigh != criticalMap.end())
907 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000908 assertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700909 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000910 deassertionEnabledMsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700911 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
912 }
913 if (criticalLow != criticalMap.end())
914 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000915 assertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700916 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000917 deassertionEnabledLsb |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700918 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
919 }
920 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700921 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000922
923 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
924 assertionEnabledMsb, deassertionEnabledLsb,
925 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700926}
927
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000928/** @brief implements the get Sensor event status command
929 * @param sensorNumber - sensor number, FFh = reserved
930 *
931 * @returns IPMI completion code plus response data
932 * - sensorEventStatus - Sensor Event messages state
933 * - assertions - Assertion event messages
934 * - deassertions - Deassertion event messages
935 */
936ipmi::RspType<uint8_t, // sensorEventStatus
937 std::bitset<16>, // assertions
938 std::bitset<16> // deassertion
939 >
James Feist25690252019-12-23 12:25:49 -0800940 ipmiSenGetSensorEventStatus(boost::asio::yield_context yield,
941 uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700942{
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000943 if (sensorNum == 0xFF)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700944 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000945 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700946 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700947
948 std::string connection;
949 std::string path;
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000950 auto status = getSensorConnection(sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700951 if (status)
952 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000953 phosphor::logging::log<phosphor::logging::level::ERR>(
954 "ipmiSenGetSensorEventStatus: Sensor connection Error",
955 phosphor::logging::entry("SENSOR=%d", sensorNum));
956 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700957 }
958
959 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -0800960 if (!getSensorMap(yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700961 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000962 phosphor::logging::log<phosphor::logging::level::ERR>(
963 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
964 phosphor::logging::entry("SENSOR=%s", path.c_str()));
965 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700966 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700967 auto warningInterface =
968 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
969 auto criticalInterface =
970 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
971
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000972 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700973 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
974
James Feist392786a2019-03-19 13:36:10 -0700975 std::optional<bool> criticalDeassertHigh =
976 thresholdDeassertMap[path]["CriticalAlarmHigh"];
977 std::optional<bool> criticalDeassertLow =
978 thresholdDeassertMap[path]["CriticalAlarmLow"];
979 std::optional<bool> warningDeassertHigh =
980 thresholdDeassertMap[path]["WarningAlarmHigh"];
981 std::optional<bool> warningDeassertLow =
982 thresholdDeassertMap[path]["WarningAlarmLow"];
983
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000984 std::bitset<16> assertions = 0;
985 std::bitset<16> deassertions = 0;
986
James Feist392786a2019-03-19 13:36:10 -0700987 if (criticalDeassertHigh && !*criticalDeassertHigh)
988 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000989 deassertions.set(static_cast<size_t>(
990 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -0700991 }
992 if (criticalDeassertLow && !*criticalDeassertLow)
993 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000994 deassertions.set(static_cast<size_t>(
995 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -0700996 }
997 if (warningDeassertHigh && !*warningDeassertHigh)
998 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +0000999 deassertions.set(static_cast<size_t>(
1000 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001001 }
1002 if (warningDeassertLow && !*warningDeassertLow)
1003 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001004 deassertions.set(static_cast<size_t>(
1005 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001006 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001007 if ((warningInterface != sensorMap.end()) ||
1008 (criticalInterface != sensorMap.end()))
1009 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001010 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001011 IPMISensorEventEnableByte2::eventMessagesEnable);
1012 if (warningInterface != sensorMap.end())
1013 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001014 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001015
1016 auto warningHigh = warningMap.find("WarningAlarmHigh");
1017 auto warningLow = warningMap.find("WarningAlarmLow");
1018 auto warningHighAlarm = false;
1019 auto warningLowAlarm = false;
1020
1021 if (warningHigh != warningMap.end())
1022 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001023 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001024 }
1025 if (warningLow != warningMap.end())
1026 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001027 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001028 }
1029 if (warningHighAlarm)
1030 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001031 assertions.set(
1032 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1033 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001034 }
1035 if (warningLowAlarm)
1036 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001037 assertions.set(
1038 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1039 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001040 }
1041 }
1042 if (criticalInterface != sensorMap.end())
1043 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001044 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001045
1046 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1047 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1048 auto criticalHighAlarm = false;
1049 auto criticalLowAlarm = false;
1050
1051 if (criticalHigh != criticalMap.end())
1052 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001053 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001054 }
1055 if (criticalLow != criticalMap.end())
1056 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001057 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001058 }
1059 if (criticalHighAlarm)
1060 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001061 assertions.set(
1062 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1063 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001064 }
1065 if (criticalLowAlarm)
1066 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001067 assertions.set(static_cast<size_t>(
1068 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001069 }
1070 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071 }
1072
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001073 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001074}
1075
1076/* end sensor commands */
1077
1078/* storage commands */
1079
James Feist74c50c62019-08-14 14:18:41 -07001080ipmi::RspType<uint8_t, // sdr version
1081 uint16_t, // record count
1082 uint16_t, // free space
1083 uint32_t, // most recent addition
1084 uint32_t, // most recent erase
1085 uint8_t // operationSupport
1086 >
James Feist25690252019-12-23 12:25:49 -08001087 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088{
James Feist74c50c62019-08-14 14:18:41 -07001089 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1091 {
James Feist74c50c62019-08-14 14:18:41 -07001092 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001093 }
1094
James Feist74c50c62019-08-14 14:18:41 -07001095 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001096 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001097 if (ret != ipmi::ccSuccess)
1098 {
1099 return ipmi::response(ret);
1100 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001101
James Feist74c50c62019-08-14 14:18:41 -07001102 uint16_t recordCount =
1103 sensorTree.size() + fruCount + ipmi::storage::type12Count;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001104
James Feist74c50c62019-08-14 14:18:41 -07001105 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001106 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001107
1108 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001109 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001110 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001111 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001112 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1113 unspecifiedFreeSpace, sdrLastAdd,
1114 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115}
1116
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001117/** @brief implements the get SDR allocation info command
1118 *
1119 * @returns IPMI completion code plus response data
1120 * - allocUnits - Number of possible allocation units
1121 * - allocUnitSize - Allocation unit size in bytes.
1122 * - allocUnitFree - Number of free allocation units
1123 * - allocUnitLargestFree - Largest free block in allocation units
1124 * - maxRecordSize - Maximum record size in allocation units.
1125 */
1126ipmi::RspType<uint16_t, // allocUnits
1127 uint16_t, // allocUnitSize
1128 uint16_t, // allocUnitFree
1129 uint16_t, // allocUnitLargestFree
1130 uint8_t // maxRecordSize
1131 >
1132 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001133{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001135 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001136
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001137 constexpr uint16_t allocUnitFree = 0;
1138 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001139 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001140 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001141
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001142 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1143 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001144}
1145
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001146/** @brief implements the reserve SDR command
1147 * @returns IPMI completion code plus response data
1148 * - sdrReservationID
1149 */
1150ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001152 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001153 if (sdrReservationID == 0)
1154 {
1155 sdrReservationID++;
1156 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001157
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001158 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001159}
1160
James Feistb49a98a2019-04-16 13:48:09 -07001161ipmi::RspType<uint16_t, // next record ID
1162 std::vector<uint8_t> // payload
1163 >
James Feist25690252019-12-23 12:25:49 -08001164 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1165 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001166{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 constexpr uint16_t lastRecordIndex = 0xFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001168
1169 // reservation required for partial reads with non zero offset into
1170 // record
James Feistb49a98a2019-04-16 13:48:09 -07001171 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172 {
James Feistb49a98a2019-04-16 13:48:09 -07001173 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001174 }
1175
1176 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
1177 {
James Feistb49a98a2019-04-16 13:48:09 -07001178 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001179 }
1180
1181 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001182 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001183 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001184 {
James Feistb49a98a2019-04-16 13:48:09 -07001185 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001186 }
1187
Yong Lifee5e4c2020-01-17 19:36:29 +08001188 size_t lastRecord = sensorTree.size() + fruCount +
1189 ipmi::storage::type12Count +
1190 ipmi::storage::nmDiscoverySDRCount - 1;
James Feistb49a98a2019-04-16 13:48:09 -07001191 if (recordID == lastRecordIndex)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001192 {
James Feistb49a98a2019-04-16 13:48:09 -07001193 recordID = lastRecord;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001194 }
James Feistb49a98a2019-04-16 13:48:09 -07001195 if (recordID > lastRecord)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001196 {
James Feistb49a98a2019-04-16 13:48:09 -07001197 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001198 }
1199
James Feistb49a98a2019-04-16 13:48:09 -07001200 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001201
James Feistb49a98a2019-04-16 13:48:09 -07001202 if (recordID >= sensorTree.size())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001203 {
James Feist74c50c62019-08-14 14:18:41 -07001204 std::vector<uint8_t> recordData;
James Feistb49a98a2019-04-16 13:48:09 -07001205 size_t fruIndex = recordID - sensorTree.size();
Yong Lifee5e4c2020-01-17 19:36:29 +08001206 size_t type12End = fruCount + ipmi::storage::type12Count;
1207
1208 if (fruIndex >= type12End)
1209 {
1210 // NM discovery SDR
1211 size_t nmDiscoveryIndex = fruIndex - type12End;
1212 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount ||
1213 offset > sizeof(NMDiscoveryRecord))
1214 {
1215 return ipmi::responseInvalidFieldRequest();
1216 }
1217
1218 std::vector<uint8_t> record =
1219 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
1220 if (record.size() < (offset + bytesToRead))
1221 {
1222 bytesToRead = record.size() - offset;
1223 }
1224 recordData.insert(recordData.end(), record.begin() + offset,
1225 record.begin() + offset + bytesToRead);
1226 }
1227 else if (fruIndex >= fruCount)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001228 {
James Feist74c50c62019-08-14 14:18:41 -07001229 // handle type 12 hardcoded records
1230 size_t type12Index = fruIndex - fruCount;
1231 if (type12Index >= ipmi::storage::type12Count ||
1232 offset > sizeof(Type12Record))
1233 {
1234 return ipmi::responseInvalidFieldRequest();
1235 }
1236 std::vector<uint8_t> record =
1237 ipmi::storage::getType12SDRs(type12Index, recordID);
1238 if (record.size() < (offset + bytesToRead))
1239 {
1240 bytesToRead = record.size() - offset;
1241 }
James Feistb49a98a2019-04-16 13:48:09 -07001242
James Feist74c50c62019-08-14 14:18:41 -07001243 recordData.insert(recordData.end(), record.begin() + offset,
1244 record.begin() + offset + bytesToRead);
1245 }
1246 else
1247 {
1248 // handle fru records
1249 get_sdr::SensorDataFruRecord data;
1250 if (offset > sizeof(data))
1251 {
1252 return ipmi::responseInvalidFieldRequest();
1253 }
James Feist25690252019-12-23 12:25:49 -08001254 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
James Feist74c50c62019-08-14 14:18:41 -07001255 if (ret != IPMI_CC_OK)
1256 {
1257 return ipmi::response(ret);
1258 }
1259 data.header.record_id_msb = recordID << 8;
1260 data.header.record_id_lsb = recordID & 0xFF;
1261 if (sizeof(data) < (offset + bytesToRead))
1262 {
1263 bytesToRead = sizeof(data) - offset;
1264 }
1265
James Feistfcd2d3a2020-05-28 10:38:15 -07001266 uint8_t* respStart = reinterpret_cast<uint8_t*>(&data) + offset;
James Feist74c50c62019-08-14 14:18:41 -07001267 recordData.insert(recordData.end(), respStart,
1268 respStart + bytesToRead);
1269 }
James Feistb49a98a2019-04-16 13:48:09 -07001270
1271 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001272 }
1273
1274 std::string connection;
1275 std::string path;
James Feistb49a98a2019-04-16 13:48:09 -07001276 uint16_t sensorIndex = recordID;
James Feistfcd2d3a2020-05-28 10:38:15 -07001277 for (const auto& sensor : sensorTree)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001278 {
1279 if (sensorIndex-- == 0)
1280 {
1281 if (!sensor.second.size())
1282 {
James Feistb49a98a2019-04-16 13:48:09 -07001283 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001284 }
1285 connection = sensor.second.begin()->first;
1286 path = sensor.first;
1287 break;
1288 }
1289 }
1290
1291 SensorMap sensorMap;
James Feist25690252019-12-23 12:25:49 -08001292 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001293 {
James Feistb49a98a2019-04-16 13:48:09 -07001294 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001295 }
James Feistb49a98a2019-04-16 13:48:09 -07001296 uint8_t sensornumber = (recordID & 0xFF);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001297 get_sdr::SensorDataFullRecord record = {0};
1298
James Feistb49a98a2019-04-16 13:48:09 -07001299 record.header.record_id_msb = recordID << 8;
1300 record.header.record_id_lsb = recordID & 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001301 record.header.sdr_version = ipmiSdrVersion;
1302 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1303 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1304 sizeof(get_sdr::SensorDataRecordHeader);
1305 record.key.owner_id = 0x20;
1306 record.key.owner_lun = 0x0;
1307 record.key.sensor_number = sensornumber;
1308
James Feist7086a882019-03-13 10:46:00 -07001309 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001310 record.body.sensor_type = getSensorTypeFromPath(path);
1311 std::string type = getSensorTypeStringFromPath(path);
1312 auto typeCstr = type.c_str();
1313 auto findUnits = sensorUnits.find(typeCstr);
1314 if (findUnits != sensorUnits.end())
1315 {
1316 record.body.sensor_units_2_base =
1317 static_cast<uint8_t>(findUnits->second);
1318 } // else default 0x0 unspecified
1319
1320 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1321
1322 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1323 if (sensorObject == sensorMap.end())
1324 {
James Feistb49a98a2019-04-16 13:48:09 -07001325 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001326 }
1327
Patrick Venture262276f2019-10-18 13:27:59 -07001328 uint8_t entityId = 0;
1329 uint8_t entityInstance = 0x01;
1330
1331 // follow the association chain to get the parent board's entityid and
1332 // entityInstance
1333 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1334
1335 record.body.entity_id = entityId;
1336 record.body.entity_instance = entityInstance;
1337
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001338 auto maxObject = sensorObject->second.find("MaxValue");
1339 auto minObject = sensorObject->second.find("MinValue");
Josh Lehanca9dcbd2019-11-18 15:59:59 -08001340
1341 // If min and/or max are left unpopulated,
1342 // then default to what a signed byte would be, namely (-128,127) range.
1343 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1344 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001345 if (maxObject != sensorObject->second.end())
1346 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001347 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001348 }
1349
1350 if (minObject != sensorObject->second.end())
1351 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001352 min = std::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001353 }
1354
Yong Li1f2eb5e2019-05-23 14:07:17 +08001355 int16_t mValue = 0;
1356 int8_t rExp = 0;
1357 int16_t bValue = 0;
1358 int8_t bExp = 0;
1359 bool bSigned = false;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001360
1361 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1362 {
James Feistb49a98a2019-04-16 13:48:09 -07001363 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001364 }
1365
Josh Lehan7cc9e472019-11-18 16:09:26 -08001366 // The record.body is a struct SensorDataFullRecordBody
1367 // from sensorhandler.hpp in phosphor-ipmi-host.
1368 // The meaning of these bits appears to come from
1369 // table 43.1 of the IPMI spec.
1370 // The above 5 sensor attributes are stuffed in as follows:
1371 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1372 // Byte 22-24 are for other purposes
1373 // Byte 25 = MMMMMMMM = LSB of M
1374 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1375 // Byte 27 = BBBBBBBB = LSB of B
1376 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1377 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1378 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1379
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001380 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1381 record.body.m_lsb = mValue & 0xFF;
1382
Josh Lehan7cc9e472019-11-18 16:09:26 -08001383 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1384 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1385
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001386 // move the smallest bit of the MSB into place (bit 9)
1387 // the MSbs are bits 7:8 in m_msb_and_tolerance
Josh Lehan7cc9e472019-11-18 16:09:26 -08001388 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001389
1390 record.body.b_lsb = bValue & 0xFF;
1391
Josh Lehan7cc9e472019-11-18 16:09:26 -08001392 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1393 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1394
1395 // move the smallest bit of the MSB into place (bit 9)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001396 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
Josh Lehan7cc9e472019-11-18 16:09:26 -08001397 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001398
Josh Lehan7cc9e472019-11-18 16:09:26 -08001399 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1400 uint8_t rExpBits = rExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001401
Josh Lehan7cc9e472019-11-18 16:09:26 -08001402 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1403 uint8_t bExpBits = bExp & 0x07;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001404
Josh Lehan7cc9e472019-11-18 16:09:26 -08001405 // move rExp and bExp into place
1406 record.body.r_b_exponents =
1407 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1408
1409 // Set the analog reading byte interpretation accordingly
1410 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1411
1412 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1413 // These seem redundant, but derivable from the above 5 attributes
1414 // Original comment said "todo fill out rest of units"
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001415
1416 // populate sensor name from path
1417 std::string name;
1418 size_t nameStart = path.rfind("/");
1419 if (nameStart != std::string::npos)
1420 {
1421 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1422 }
1423
1424 std::replace(name.begin(), name.end(), '_', ' ');
1425 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1426 {
James Feist979a2322019-05-15 09:06:54 -07001427 // try to not truncate by replacing common words
James Feistfcd2d3a2020-05-28 10:38:15 -07001428 constexpr std::array<std::pair<const char*, const char*>, 2>
James Feist979a2322019-05-15 09:06:54 -07001429 replaceWords = {std::make_pair("Output", "Out"),
1430 std::make_pair("Input", "In")};
James Feistfcd2d3a2020-05-28 10:38:15 -07001431 for (const auto& [find, replace] : replaceWords)
James Feist979a2322019-05-15 09:06:54 -07001432 {
1433 boost::replace_all(name, find, replace);
1434 }
1435
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001436 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1437 }
1438 record.body.id_string_info = name.size();
1439 std::strncpy(record.body.id_string, name.c_str(),
1440 sizeof(record.body.id_string));
1441
James Feistc4b15bc2019-04-16 15:41:39 -07001442 IPMIThresholds thresholdData;
1443 try
1444 {
1445 thresholdData = getIPMIThresholds(sensorMap);
1446 }
James Feistfcd2d3a2020-05-28 10:38:15 -07001447 catch (std::exception&)
James Feistc4b15bc2019-04-16 15:41:39 -07001448 {
1449 return ipmi::responseResponseError();
1450 }
1451
1452 if (thresholdData.criticalHigh)
1453 {
1454 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1455 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
Rashmi RV963a95b2020-01-27 15:09:17 +05301456 IPMISensorEventEnableThresholds::criticalThreshold);
1457 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
James Feistc4b15bc2019-04-16 15:41:39 -07001458 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1459 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1460 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1461 record.body.discrete_reading_setting_mask[0] |=
1462 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1463 }
1464 if (thresholdData.warningHigh)
1465 {
1466 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
Rashmi RV963a95b2020-01-27 15:09:17 +05301467 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1468 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001469 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1470 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1471 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1472 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1473 record.body.discrete_reading_setting_mask[0] |=
1474 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1475 }
1476 if (thresholdData.criticalLow)
1477 {
1478 record.body.lower_critical_threshold = *thresholdData.criticalLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301479 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1480 IPMISensorEventEnableThresholds::criticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001481 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1482 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1483 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1484 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1485 record.body.discrete_reading_setting_mask[0] |=
1486 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1487 }
1488 if (thresholdData.warningLow)
1489 {
1490 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
Rashmi RV963a95b2020-01-27 15:09:17 +05301491 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1492 IPMISensorEventEnableThresholds::nonCriticalThreshold);
James Feistc4b15bc2019-04-16 15:41:39 -07001493 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1494 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1495 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1496 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1497 record.body.discrete_reading_setting_mask[0] |=
1498 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1499 }
1500
1501 // everything that is readable is setable
1502 record.body.discrete_reading_setting_mask[1] =
1503 record.body.discrete_reading_setting_mask[0];
1504
James Feistb49a98a2019-04-16 13:48:09 -07001505 if (sizeof(get_sdr::SensorDataFullRecord) < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001506 {
James Feistb49a98a2019-04-16 13:48:09 -07001507 bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001508 }
1509
James Feistfcd2d3a2020-05-28 10:38:15 -07001510 uint8_t* respStart = reinterpret_cast<uint8_t*>(&record) + offset;
James Feistb49a98a2019-04-16 13:48:09 -07001511 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001512
James Feistb49a98a2019-04-16 13:48:09 -07001513 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001514}
1515/* end storage commands */
1516
1517void registerSensorFunctions()
1518{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001519 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001520 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1521 ipmi::sensor_event::cmdPlatformEvent,
1522 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001523
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001524 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001525 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1526 ipmi::sensor_event::cmdGetSensorReading,
1527 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001528
1529 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001530 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1531 ipmi::sensor_event::cmdGetSensorThreshold,
1532 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001533
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001534 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001535 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1536 ipmi::sensor_event::cmdSetSensorThreshold,
1537 ipmi::Privilege::Operator,
1538 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001539
1540 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001541 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1542 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001543 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001544
1545 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001546 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1547 ipmi::sensor_event::cmdGetSensorEventStatus,
1548 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001549
1550 // register all storage commands for both Sensor and Storage command
1551 // versions
1552
1553 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001554 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1555 ipmi::storage::cmdGetSdrRepositoryInfo,
1556 ipmi::Privilege::User,
1557 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001558
1559 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001560 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1561 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1562 ipmi::Privilege::User,
1563 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001564
1565 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001566 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1567 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001568 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001569
Vernon Mauery98bbf692019-09-16 11:14:59 -07001570 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1571 ipmi::storage::cmdReserveSdrRepository,
1572 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001573
1574 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001575 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1576 ipmi::sensor_event::cmdGetDeviceSdr,
1577 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001578
Vernon Mauery98bbf692019-09-16 11:14:59 -07001579 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1580 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1581 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001582}
1583} // namespace ipmi