blob: 0fb04f72d1e237e2a6c81b93ff3414831e59992b [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venture31b35d52019-10-20 13:25:16 -070017#include "sensorcommands.hpp"
18
19#include "commandutils.hpp"
20#include "ipmi_to_redfish_hooks.hpp"
21#include "sdrutils.hpp"
22#include "sensorutils.hpp"
23#include "storagecommands.hpp"
Patrick Venturec2a07d42020-05-30 16:35:03 -070024#include "types.hpp"
Patrick Venture31b35d52019-10-20 13:25:16 -070025
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070026#include <boost/algorithm/string.hpp>
27#include <boost/container/flat_map.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070028#include <ipmid/api.hpp>
29#include <ipmid/utils.hpp>
30#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
32
33#include <algorithm>
34#include <array>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070035#include <chrono>
36#include <cmath>
Patrick Venture5c2d26e2019-09-25 17:43:53 -070037#include <cstring>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070038#include <iostream>
Patrick Ventureb10ec8b2019-09-25 16:39:14 -070039#include <map>
Patrick Venturefd2a9382019-09-25 17:47:25 -070040#include <memory>
Patrick Venturec4e9de62019-09-25 17:40:54 -070041#include <optional>
Patrick Venturee6154022019-09-25 17:50:25 -070042#include <stdexcept>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070043#include <string>
Patrick Venture38f46f22019-09-25 17:41:26 -070044#include <utility>
Patrick Ventureeb02a5c2019-09-25 17:44:43 -070045#include <variant>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070046
47namespace ipmi
48{
49using ManagedObjectType =
50 std::map<sdbusplus::message::object_path,
51 std::map<std::string, std::map<std::string, DbusVariant>>>;
52
James Feist25690252019-12-23 12:25:49 -080053static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu09701ef2020-07-15 17:56:21 -070054static constexpr int sensorMapSdrUpdatePeriod = 60;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070055
56constexpr size_t maxSDRTotalSize =
57 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
58constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
59
60static uint16_t sdrReservationID;
61static uint32_t sdrLastAdd = noTimestamp;
62static uint32_t sdrLastRemove = noTimestamp;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070063static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey2346b5d2021-08-06 11:21:10 -070064
65// The IPMI spec defines four Logical Units (LUN), each capable of supporting
66// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
67// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
68// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
69// location.
70static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
71
72static constexpr size_t lun0MaxSensorNum = 0xfe;
73static constexpr size_t lun1MaxSensorNum = 0x1fe;
74static constexpr size_t lun3MaxSensorNum = 0x3fe;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070075static constexpr int GENERAL_ERROR = -1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070076
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053077SensorSubTree sensorTree;
Johnathan Mantey308c3a82020-07-22 11:50:54 -070078
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070079static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
80
Jason M. Bills17add592018-11-12 14:30:12 -080081// Specify the comparison required to sort and find char* map objects
82struct CmpStr
83{
James Feistfcd2d3a2020-05-28 10:38:15 -070084 bool operator()(const char* a, const char* b) const
Jason M. Bills17add592018-11-12 14:30:12 -080085 {
86 return std::strcmp(a, b) < 0;
87 }
88};
James Feistfcd2d3a2020-05-28 10:38:15 -070089const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
Jason M. Bills17add592018-11-12 14:30:12 -080090 sensorUnits{{{"temperature", SensorUnits::degreesC},
91 {"voltage", SensorUnits::volts},
92 {"current", SensorUnits::amps},
93 {"fan_tach", SensorUnits::rpm},
94 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070095
96void registerSensorFunctions() __attribute__((constructor));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070097
Patrick Williamsf944d2e2022-07-22 19:26:52 -050098static sdbusplus::bus::match_t sensorAdded(
Vernon Mauery15419dd2019-05-24 09:40:30 -070099 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700100 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
101 "sensors/'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500102 [](sdbusplus::message_t& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700103 sensorTree.clear();
104 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
105 std::chrono::system_clock::now().time_since_epoch())
106 .count();
107 });
108
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500109static sdbusplus::bus::match_t sensorRemoved(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700110 *getSdBus(),
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700111 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
112 "sensors/'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500113 [](sdbusplus::message_t& m) {
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700114 sensorTree.clear();
115 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
116 std::chrono::system_clock::now().time_since_epoch())
117 .count();
118 });
119
James Feist392786a2019-03-19 13:36:10 -0700120// this keeps track of deassertions for sensor event status command. A
121// deasertion can only happen if an assertion was seen first.
122static boost::container::flat_map<
123 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
124 thresholdDeassertMap;
125
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500126static sdbusplus::bus::match_t thresholdChanged(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700127 *getSdBus(),
James Feist392786a2019-03-19 13:36:10 -0700128 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
129 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500130 [](sdbusplus::message_t& m) {
Jason M. Bills0748c692022-09-08 15:34:08 -0700131 boost::container::flat_map<std::string, ipmi::DbusVariant> values;
James Feist392786a2019-03-19 13:36:10 -0700132 m.read(std::string(), values);
133
134 auto findAssert =
James Feistfcd2d3a2020-05-28 10:38:15 -0700135 std::find_if(values.begin(), values.end(), [](const auto& pair) {
James Feist392786a2019-03-19 13:36:10 -0700136 return pair.first.find("Alarm") != std::string::npos;
137 });
138 if (findAssert != values.end())
139 {
140 auto ptr = std::get_if<bool>(&(findAssert->second));
141 if (ptr == nullptr)
142 {
143 phosphor::logging::log<phosphor::logging::level::ERR>(
144 "thresholdChanged: Assert non bool");
145 return;
146 }
147 if (*ptr)
148 {
149 phosphor::logging::log<phosphor::logging::level::INFO>(
150 "thresholdChanged: Assert",
151 phosphor::logging::entry("SENSOR=%s", m.get_path()));
152 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
153 }
154 else
155 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700156 auto& value =
James Feist392786a2019-03-19 13:36:10 -0700157 thresholdDeassertMap[m.get_path()][findAssert->first];
158 if (value)
159 {
160 phosphor::logging::log<phosphor::logging::level::INFO>(
161 "thresholdChanged: deassert",
162 phosphor::logging::entry("SENSOR=%s", m.get_path()));
163 value = *ptr;
164 }
165 }
166 }
167 });
168
James Feistfcd2d3a2020-05-28 10:38:15 -0700169static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
170 double& min)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700171{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700172 max = 127;
173 min = -128;
174
James Feistaecaef72019-04-26 10:30:32 -0700175 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
176 auto critical =
177 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
178 auto warning =
179 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
180
181 if (sensorObject != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700182 {
James Feistaecaef72019-04-26 10:30:32 -0700183 auto maxMap = sensorObject->second.find("MaxValue");
184 auto minMap = sensorObject->second.find("MinValue");
185
186 if (maxMap != sensorObject->second.end())
187 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700188 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700189 }
190 if (minMap != sensorObject->second.end())
191 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700192 min = std::visit(VariantToDoubleVisitor(), minMap->second);
James Feistaecaef72019-04-26 10:30:32 -0700193 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700194 }
James Feistaecaef72019-04-26 10:30:32 -0700195 if (critical != sensorMap.end())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700196 {
James Feistaecaef72019-04-26 10:30:32 -0700197 auto lower = critical->second.find("CriticalLow");
198 auto upper = critical->second.find("CriticalHigh");
199 if (lower != critical->second.end())
200 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700201 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700202 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700203 }
204 if (upper != critical->second.end())
205 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700206 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700207 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700208 }
209 }
210 if (warning != sensorMap.end())
211 {
212
213 auto lower = warning->second.find("WarningLow");
214 auto upper = warning->second.find("WarningHigh");
215 if (lower != warning->second.end())
216 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700217 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700218 min = std::fmin(value, min);
James Feistaecaef72019-04-26 10:30:32 -0700219 }
220 if (upper != warning->second.end())
221 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700222 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700223 max = std::fmax(value, max);
James Feistaecaef72019-04-26 10:30:32 -0700224 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700225 }
226}
227
James Feist25690252019-12-23 12:25:49 -0800228static bool getSensorMap(boost::asio::yield_context yield,
229 std::string sensorConnection, std::string sensorPath,
Alex Qiu09701ef2020-07-15 17:56:21 -0700230 SensorMap& sensorMap,
231 int updatePeriod = sensorMapUpdatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700232{
233 static boost::container::flat_map<
234 std::string, std::chrono::time_point<std::chrono::steady_clock>>
235 updateTimeMap;
236
237 auto updateFind = updateTimeMap.find(sensorConnection);
238 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
239 if (updateFind != updateTimeMap.end())
240 {
241 lastUpdate = updateFind->second;
242 }
243
244 auto now = std::chrono::steady_clock::now();
245
246 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu09701ef2020-07-15 17:56:21 -0700247 .count() > updatePeriod)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700248 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700249 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feist25690252019-12-23 12:25:49 -0800250 boost::system::error_code ec;
251 auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
252 yield, ec, sensorConnection.c_str(), "/",
253 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
254 if (ec)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700255 {
256 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feist25690252019-12-23 12:25:49 -0800257 "GetMangagedObjects for getSensorMap failed",
258 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
259
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700260 return false;
261 }
262
263 SensorCache[sensorConnection] = managedObjects;
Alex Qiu09701ef2020-07-15 17:56:21 -0700264 // Update time after finish building the map which allow the
265 // data to be cached for updatePeriod plus the build time.
266 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700267 }
268 auto connection = SensorCache.find(sensorConnection);
269 if (connection == SensorCache.end())
270 {
271 return false;
272 }
273 auto path = connection->second.find(sensorPath);
274 if (path == connection->second.end())
275 {
276 return false;
277 }
278 sensorMap = path->second;
279
280 return true;
281}
282
283/* sensor commands */
James Feist7aaf3fe2019-06-25 11:52:11 -0700284namespace meHealth
285{
James Feistfcd2d3a2020-05-28 10:38:15 -0700286constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
287constexpr const char* path = "/xyz/openbmc_project/status/me";
288constexpr const char* interface = "xyz.openbmc_project.SetHealth";
289constexpr const char* method = "SetHealth";
290constexpr const char* critical = "critical";
291constexpr const char* warning = "warning";
292constexpr const char* ok = "ok";
James Feist7aaf3fe2019-06-25 11:52:11 -0700293} // namespace meHealth
294
295static void setMeStatus(uint8_t eventData2, uint8_t eventData3, bool disable)
296{
297 constexpr const std::array<uint8_t, 10> critical = {
298 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xD, 0xE};
299 constexpr const std::array<uint8_t, 5> warning = {0x3, 0xA, 0x13, 0x19,
300 0x1A};
301
302 std::string state;
303 if (std::find(critical.begin(), critical.end(), eventData2) !=
304 critical.end())
305 {
306 state = meHealth::critical;
307 }
308 // special case 0x3 as we only care about a few states
309 else if (eventData2 == 0x3)
310 {
311 if (eventData3 <= 0x2)
312 {
313 state = meHealth::warning;
314 }
315 else
316 {
317 return;
318 }
319 }
320 else if (std::find(warning.begin(), warning.end(), eventData2) !=
321 warning.end())
322 {
323 state = meHealth::warning;
324 }
325 else
326 {
327 return;
328 }
329 if (disable)
330 {
331 state = meHealth::ok;
332 }
333
334 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
335 auto setHealth =
336 dbus->new_method_call(meHealth::busname, meHealth::path,
337 meHealth::interface, meHealth::method);
338 setHealth.append(std::to_string(static_cast<size_t>(eventData2)), state);
339 try
340 {
341 dbus->call(setHealth);
342 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500343 catch (const sdbusplus::exception_t&)
James Feist7aaf3fe2019-06-25 11:52:11 -0700344 {
345 phosphor::logging::log<phosphor::logging::level::ERR>(
346 "Failed to set ME Health");
347 }
348}
349
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000350ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
351 ipmi::message::Payload& p)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700352{
James Feist7aaf3fe2019-06-25 11:52:11 -0700353 constexpr const uint8_t meId = 0x2C;
354 constexpr const uint8_t meSensorNum = 0x17;
355 constexpr const uint8_t disabled = 0x80;
356
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700357 uint8_t sysgeneratorID = 0;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700358 uint8_t evmRev = 0;
359 uint8_t sensorType = 0;
360 uint8_t sensorNum = 0;
361 uint8_t eventType = 0;
362 uint8_t eventData1 = 0;
363 std::optional<uint8_t> eventData2 = 0;
364 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700365 uint16_t generatorID = 0;
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000366 ipmi::ChannelInfo chInfo;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700367
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000368 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700369 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000370 phosphor::logging::log<phosphor::logging::level::ERR>(
371 "Failed to get Channel Info",
372 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
373 return ipmi::responseUnspecifiedError();
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700374 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000375
376 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
377 ipmi::EChannelMediumType::systemInterface)
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700378 {
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000379
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700380 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700381 eventData1, eventData2, eventData3);
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700382 constexpr const uint8_t isSoftwareID = 0x01;
383 if (!(sysgeneratorID & isSoftwareID))
384 {
385 return ipmi::responseInvalidFieldRequest();
386 }
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700387 // Refer to IPMI Spec Table 32: SEL Event Records
388 generatorID = (ctx->channel << 12) // Channel
389 | (0x0 << 10) // Reserved
390 | (0x0 << 8) // 0x0 for sys-soft ID
Vernon Mauery5d24dda2022-04-13 15:11:10 -0700391 | sysgeneratorID;
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700392 }
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000393 else
394 {
395
396 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
397 eventData2, eventData3);
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700398 // Refer to IPMI Spec Table 32: SEL Event Records
399 generatorID = (ctx->channel << 12) // Channel
400 | (0x0 << 10) // Reserved
401 | ((ctx->lun & 0x3) << 8) // Lun
402 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000403 }
404
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700405 if (!p.fullyUnpacked())
406 {
407 return ipmi::responseReqDataLenInvalid();
408 }
409
Chalapathi Venkataramashetty989a13b2021-06-20 19:50:33 +0000410 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
411 if (evmRev != 0x04)
412 {
413 return ipmi::responseInvalidFieldRequest();
414 }
415 if ((sensorType > 0x2C) && (sensorType < 0xC0))
416 {
417 return ipmi::responseInvalidFieldRequest();
418 }
419
Jason M. Bills6dd8f042019-04-11 10:39:02 -0700420 // Send this request to the Redfish hooks to log it as a Redfish message
421 // instead. There is no need to add it to the SEL, so just return success.
422 intel_oem::ipmi::sel::checkRedfishHooks(
423 generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
424 eventData2.value_or(0xFF), eventData3.value_or(0xFF));
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700425
Vernon Maueryce3b7572022-04-14 13:16:25 -0700426 if (static_cast<uint8_t>(generatorID) == meId && sensorNum == meSensorNum &&
Sujoy Ray9e58cfe2021-11-01 13:17:27 -0700427 eventData2 && eventData3)
James Feist7aaf3fe2019-06-25 11:52:11 -0700428 {
429 setMeStatus(*eventData2, *eventData3, (eventType & disabled));
430 }
431
Jason M. Billsae6bdb12019-04-02 12:00:04 -0700432 return ipmi::responseSuccess();
433}
434
James Feist0cd014a2019-04-08 15:04:33 -0700435ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700436 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700437{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700438 std::string connection;
439 std::string path;
440
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000441 if (sensnum == reservedSensorNumber)
442 {
443 return ipmi::responseInvalidFieldRequest();
444 }
445
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700446 auto status = getSensorConnection(ctx, sensnum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700447 if (status)
448 {
James Feist0cd014a2019-04-08 15:04:33 -0700449 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700450 }
451
452 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700453 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700454 {
James Feist0cd014a2019-04-08 15:04:33 -0700455 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700456 }
457 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
458
459 if (sensorObject == sensorMap.end() ||
460 sensorObject->second.find("Value") == sensorObject->second.end())
461 {
James Feist0cd014a2019-04-08 15:04:33 -0700462 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700463 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700464 auto& valueVariant = sensorObject->second["Value"];
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700465 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700466
Yong Li1f2eb5e2019-05-23 14:07:17 +0800467 double max = 0;
468 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700469 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700470
471 int16_t mValue = 0;
472 int16_t bValue = 0;
473 int8_t rExp = 0;
474 int8_t bExp = 0;
475 bool bSigned = false;
476
477 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
478 {
James Feist0cd014a2019-04-08 15:04:33 -0700479 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700480 }
481
James Feist0cd014a2019-04-08 15:04:33 -0700482 uint8_t value =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700483 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
James Feist0cd014a2019-04-08 15:04:33 -0700484 uint8_t operation =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700485 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist0cd014a2019-04-08 15:04:33 -0700486 operation |=
James Feist81a95c12019-03-01 15:08:28 -0800487 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
James Feist1ee6ed82020-06-17 16:16:50 -0700488 bool notReading = std::isnan(reading);
489
490 if (!notReading)
491 {
492 auto availableObject =
493 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
494 if (availableObject != sensorMap.end())
495 {
496 auto findAvailable = availableObject->second.find("Available");
497 if (findAvailable != availableObject->second.end())
498 {
499 bool* available = std::get_if<bool>(&(findAvailable->second));
500 if (available && !(*available))
501 {
502 notReading = true;
503 }
504 }
505 }
506 }
507
508 if (notReading)
509 {
510 operation |= static_cast<uint8_t>(
511 IPMISensorReadingByte2::readingStateUnavailable);
512 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700513
Josh Lehan06aa21a2020-10-28 21:59:06 -0700514 int byteValue;
515 if (bSigned)
516 {
517 byteValue = static_cast<int>(static_cast<int8_t>(value));
518 }
519 else
520 {
521 byteValue = static_cast<int>(static_cast<uint8_t>(value));
522 }
523
524 // Keep stats on the reading just obtained, even if it is "NaN"
525 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
526 {
527 // This is the first reading, show the coefficients
528 double step = (max - min) / 255.0;
529 std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
530 << ": Range min=" << min << " max=" << max
531 << ", step=" << step
532 << ", Coefficients mValue=" << static_cast<int>(mValue)
533 << " rExp=" << static_cast<int>(rExp)
534 << " bValue=" << static_cast<int>(bValue)
535 << " bExp=" << static_cast<int>(bExp)
536 << " bSigned=" << static_cast<int>(bSigned) << "\n";
537 };
538
James Feist0cd014a2019-04-08 15:04:33 -0700539 uint8_t thresholds = 0;
540
541 auto warningObject =
542 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
543 if (warningObject != sensorMap.end())
544 {
545 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
546 auto alarmLow = warningObject->second.find("WarningAlarmLow");
547 if (alarmHigh != warningObject->second.end())
548 {
549 if (std::get<bool>(alarmHigh->second))
550 {
551 thresholds |= static_cast<uint8_t>(
552 IPMISensorReadingByte3::upperNonCritical);
553 }
554 }
555 if (alarmLow != warningObject->second.end())
556 {
557 if (std::get<bool>(alarmLow->second))
558 {
559 thresholds |= static_cast<uint8_t>(
560 IPMISensorReadingByte3::lowerNonCritical);
561 }
562 }
563 }
564
565 auto criticalObject =
566 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
567 if (criticalObject != sensorMap.end())
568 {
569 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
570 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
571 if (alarmHigh != criticalObject->second.end())
572 {
573 if (std::get<bool>(alarmHigh->second))
574 {
575 thresholds |=
576 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
577 }
578 }
579 if (alarmLow != criticalObject->second.end())
580 {
581 if (std::get<bool>(alarmLow->second))
582 {
583 thresholds |=
584 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
585 }
586 }
587 }
588
589 // no discrete as of today so optional byte is never returned
590 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700591}
592
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000593/** @brief implements the Set Sensor threshold command
594 * @param sensorNumber - sensor number
595 * @param lowerNonCriticalThreshMask
596 * @param lowerCriticalThreshMask
597 * @param lowerNonRecovThreshMask
598 * @param upperNonCriticalThreshMask
599 * @param upperCriticalThreshMask
600 * @param upperNonRecovThreshMask
601 * @param reserved
602 * @param lowerNonCritical - lower non-critical threshold
603 * @param lowerCritical - Lower critical threshold
604 * @param lowerNonRecoverable - Lower non recovarable threshold
605 * @param upperNonCritical - Upper non-critical threshold
606 * @param upperCritical - Upper critical
607 * @param upperNonRecoverable - Upper Non-recoverable
608 *
609 * @returns IPMI completion code
610 */
611ipmi::RspType<> ipmiSenSetSensorThresholds(
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700612 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
613 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
614 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
615 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
616 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
617 uint8_t upperNonCritical, uint8_t upperCritical,
618 uint8_t upperNonRecoverable)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700619{
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000620 constexpr uint8_t thresholdMask = 0xFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700621
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000622 if (sensorNum == reservedSensorNumber)
623 {
624 return ipmi::responseInvalidFieldRequest();
625 }
626
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000627 if (reserved)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700628 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000629 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700630 }
631
632 // lower nc and upper nc not suppported on any sensor
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000633 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700634 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000635 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700636 }
637
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000638 // if none of the threshold mask are set, nothing to do
639 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
640 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
641 upperCriticalThreshMask | upperNonRecovThreshMask))
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
646 std::string connection;
647 std::string path;
648
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700649 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700650 if (status)
651 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000652 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700653 }
654 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700655 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700656 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000657 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700658 }
659
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700660 double max = 0;
661 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700662 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700663
664 int16_t mValue = 0;
665 int16_t bValue = 0;
666 int8_t rExp = 0;
667 int8_t bExp = 0;
668 bool bSigned = false;
669
670 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
671 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000672 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700673 }
674
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700675 // store a vector of property name, value to set, and interface
676 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
677
678 // define the indexes of the tuple
679 constexpr uint8_t propertyName = 0;
680 constexpr uint8_t thresholdValue = 1;
681 constexpr uint8_t interface = 2;
682 // verifiy all needed fields are present
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000683 if (lowerCriticalThreshMask || upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700684 {
685 auto findThreshold =
686 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
687 if (findThreshold == sensorMap.end())
688 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000689 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700690 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000691 if (lowerCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700692 {
693 auto findLower = findThreshold->second.find("CriticalLow");
694 if (findLower == findThreshold->second.end())
695 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000696 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700697 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000698 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700699 findThreshold->first);
700 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000701 if (upperCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700702 {
703 auto findUpper = findThreshold->second.find("CriticalHigh");
704 if (findUpper == findThreshold->second.end())
705 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000706 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700707 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000708 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700709 findThreshold->first);
710 }
711 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000712 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700713 {
714 auto findThreshold =
715 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
716 if (findThreshold == sensorMap.end())
717 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000718 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700719 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000720 if (lowerNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700721 {
722 auto findLower = findThreshold->second.find("WarningLow");
723 if (findLower == findThreshold->second.end())
724 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000725 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700726 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000727 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700728 findThreshold->first);
729 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000730 if (upperNonCriticalThreshMask)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700731 {
732 auto findUpper = findThreshold->second.find("WarningHigh");
733 if (findUpper == findThreshold->second.end())
734 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000735 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700736 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000737 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700738 findThreshold->first);
739 }
740 }
James Feistfcd2d3a2020-05-28 10:38:15 -0700741 for (const auto& property : thresholdsToSet)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700742 {
743 // from section 36.3 in the IPMI Spec, assume all linear
744 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
Josh Lehan86236a22019-11-18 17:53:33 -0800745 (bValue * std::pow(10.0, bExp))) *
746 std::pow(10.0, rExp);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700747 setDbusProperty(
748 *getSdBus(), connection, path, std::get<interface>(property),
749 std::get<propertyName>(property), ipmi::Value(valueToSet));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700750 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000751 return ipmi::responseSuccess();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700752}
753
James Feistfcd2d3a2020-05-28 10:38:15 -0700754IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700755{
James Feist902c4c52019-04-16 14:51:31 -0700756 IPMIThresholds resp;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700757 auto warningInterface =
758 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
759 auto criticalInterface =
760 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
761
762 if ((warningInterface != sensorMap.end()) ||
763 (criticalInterface != sensorMap.end()))
764 {
765 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
766
767 if (sensorPair == sensorMap.end())
768 {
769 // should not have been able to find a sensor not implementing
770 // the sensor object
James Feist902c4c52019-04-16 14:51:31 -0700771 throw std::runtime_error("Invalid sensor map");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700772 }
773
Chen,Yugang606dd9f2019-07-01 10:37:30 +0800774 double max = 0;
775 double min = 0;
James Feistaecaef72019-04-26 10:30:32 -0700776 getSensorMaxMin(sensorMap, max, min);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700777
778 int16_t mValue = 0;
779 int16_t bValue = 0;
780 int8_t rExp = 0;
781 int8_t bExp = 0;
782 bool bSigned = false;
783
784 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
785 {
James Feist902c4c52019-04-16 14:51:31 -0700786 throw std::runtime_error("Invalid sensor atrributes");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700787 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700788 if (warningInterface != sensorMap.end())
789 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700790 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700791
792 auto warningHigh = warningMap.find("WarningHigh");
793 auto warningLow = warningMap.find("WarningLow");
794
795 if (warningHigh != warningMap.end())
796 {
James Feist902c4c52019-04-16 14:51:31 -0700797
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700798 double value =
799 std::visit(VariantToDoubleVisitor(), warningHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700800 if (std::isfinite(value))
801 {
802 resp.warningHigh = scaleIPMIValueFromDouble(
803 value, mValue, rExp, bValue, bExp, bSigned);
804 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700805 }
806 if (warningLow != warningMap.end())
807 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700808 double value =
809 std::visit(VariantToDoubleVisitor(), warningLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700810 if (std::isfinite(value))
811 {
812 resp.warningLow = scaleIPMIValueFromDouble(
813 value, mValue, rExp, bValue, bExp, bSigned);
814 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700815 }
816 }
817 if (criticalInterface != sensorMap.end())
818 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700819 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700820
821 auto criticalHigh = criticalMap.find("CriticalHigh");
822 auto criticalLow = criticalMap.find("CriticalLow");
823
824 if (criticalHigh != criticalMap.end())
825 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700826 double value =
827 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700828 if (std::isfinite(value))
829 {
830 resp.criticalHigh = scaleIPMIValueFromDouble(
831 value, mValue, rExp, bValue, bExp, bSigned);
832 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700833 }
834 if (criticalLow != criticalMap.end())
835 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700836 double value =
837 std::visit(VariantToDoubleVisitor(), criticalLow->second);
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700838 if (std::isfinite(value))
839 {
840 resp.criticalLow = scaleIPMIValueFromDouble(
841 value, mValue, rExp, bValue, bExp, bSigned);
842 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700843 }
844 }
845 }
James Feist902c4c52019-04-16 14:51:31 -0700846 return resp;
847}
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700848
James Feist902c4c52019-04-16 14:51:31 -0700849ipmi::RspType<uint8_t, // readable
850 uint8_t, // lowerNCrit
851 uint8_t, // lowerCrit
852 uint8_t, // lowerNrecoverable
853 uint8_t, // upperNC
854 uint8_t, // upperCrit
855 uint8_t> // upperNRecoverable
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700856 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
James Feist902c4c52019-04-16 14:51:31 -0700857{
858 std::string connection;
859 std::string path;
860
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000861 if (sensorNumber == reservedSensorNumber)
862 {
863 return ipmi::responseInvalidFieldRequest();
864 }
865
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700866 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
James Feist902c4c52019-04-16 14:51:31 -0700867 if (status)
868 {
869 return ipmi::response(status);
870 }
871
872 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700873 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
James Feist902c4c52019-04-16 14:51:31 -0700874 {
875 return ipmi::responseResponseError();
876 }
877
878 IPMIThresholds thresholdData;
879 try
880 {
881 thresholdData = getIPMIThresholds(sensorMap);
882 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500883 catch (const std::exception&)
James Feist902c4c52019-04-16 14:51:31 -0700884 {
885 return ipmi::responseResponseError();
886 }
887
888 uint8_t readable = 0;
889 uint8_t lowerNC = 0;
890 uint8_t lowerCritical = 0;
891 uint8_t lowerNonRecoverable = 0;
892 uint8_t upperNC = 0;
893 uint8_t upperCritical = 0;
894 uint8_t upperNonRecoverable = 0;
895
896 if (thresholdData.warningHigh)
897 {
898 readable |=
899 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
900 upperNC = *thresholdData.warningHigh;
901 }
902 if (thresholdData.warningLow)
903 {
904 readable |=
905 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
906 lowerNC = *thresholdData.warningLow;
907 }
908
909 if (thresholdData.criticalHigh)
910 {
911 readable |=
912 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
913 upperCritical = *thresholdData.criticalHigh;
914 }
915 if (thresholdData.criticalLow)
916 {
917 readable |=
918 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
919 lowerCritical = *thresholdData.criticalLow;
920 }
921
922 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
923 lowerNonRecoverable, upperNC, upperCritical,
924 upperNonRecoverable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700925}
926
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000927/** @brief implements the get Sensor event enable command
928 * @param sensorNumber - sensor number
929 *
930 * @returns IPMI completion code plus response data
931 * - enabled - Sensor Event messages
932 * - assertionEnabledLsb - Assertion event messages
933 * - assertionEnabledMsb - Assertion event messages
934 * - deassertionEnabledLsb - Deassertion event messages
935 * - deassertionEnabledMsb - Deassertion event messages
936 */
937
938ipmi::RspType<uint8_t, // enabled
939 uint8_t, // assertionEnabledLsb
940 uint8_t, // assertionEnabledMsb
941 uint8_t, // deassertionEnabledLsb
942 uint8_t> // deassertionEnabledMsb
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700943 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700944{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700945 std::string connection;
946 std::string path;
947
Patrick Venturea41714c2019-09-25 16:59:41 -0700948 uint8_t enabled = 0;
949 uint8_t assertionEnabledLsb = 0;
950 uint8_t assertionEnabledMsb = 0;
951 uint8_t deassertionEnabledLsb = 0;
952 uint8_t deassertionEnabledMsb = 0;
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000953
Chalapathi Venkataramashetty339fc562021-06-13 19:51:17 +0000954 if (sensorNum == reservedSensorNumber)
955 {
956 return ipmi::responseInvalidFieldRequest();
957 }
958
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700959 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700960 if (status)
961 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000962 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700963 }
964
965 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -0700966 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700967 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000968 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700969 }
970
971 auto warningInterface =
972 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
973 auto criticalInterface =
974 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700975 if ((warningInterface != sensorMap.end()) ||
976 (criticalInterface != sensorMap.end()))
977 {
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +0000978 enabled = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700979 IPMISensorEventEnableByte2::sensorScanningEnable);
980 if (warningInterface != sensorMap.end())
981 {
James Feistfcd2d3a2020-05-28 10:38:15 -0700982 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700983
984 auto warningHigh = warningMap.find("WarningHigh");
985 auto warningLow = warningMap.find("WarningLow");
986 if (warningHigh != warningMap.end())
987 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -0700988 double value =
989 std::visit(VariantToDoubleVisitor(), warningHigh->second);
990 if (std::isfinite(value))
991 {
992 assertionEnabledLsb |=
993 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
994 upperNonCriticalGoingHigh);
995 deassertionEnabledLsb |=
996 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
997 upperNonCriticalGoingLow);
998 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700999 }
1000 if (warningLow != warningMap.end())
1001 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001002 double value =
1003 std::visit(VariantToDoubleVisitor(), warningLow->second);
1004 if (std::isfinite(value))
1005 {
1006 assertionEnabledLsb |=
1007 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1008 lowerNonCriticalGoingLow);
1009 deassertionEnabledLsb |=
1010 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1011 lowerNonCriticalGoingHigh);
1012 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001013 }
1014 }
1015 if (criticalInterface != sensorMap.end())
1016 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001017 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001018
1019 auto criticalHigh = criticalMap.find("CriticalHigh");
1020 auto criticalLow = criticalMap.find("CriticalLow");
1021
1022 if (criticalHigh != criticalMap.end())
1023 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001024 double value =
1025 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
1026 if (std::isfinite(value))
1027 {
1028 assertionEnabledMsb |=
1029 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1030 upperCriticalGoingHigh);
1031 deassertionEnabledMsb |= static_cast<uint8_t>(
1032 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1033 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001034 }
1035 if (criticalLow != criticalMap.end())
1036 {
Zhikui Ren41a6e9f2022-05-23 16:06:10 -07001037 double value =
1038 std::visit(VariantToDoubleVisitor(), criticalLow->second);
1039 if (std::isfinite(value))
1040 {
1041 assertionEnabledLsb |= static_cast<uint8_t>(
1042 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1043 deassertionEnabledLsb |=
1044 static_cast<uint8_t>(IPMISensorEventEnableThresholds::
1045 lowerCriticalGoingHigh);
1046 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001047 }
1048 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001049 }
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001050
1051 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1052 assertionEnabledMsb, deassertionEnabledLsb,
1053 deassertionEnabledMsb);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001054}
1055
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001056/** @brief implements the get Sensor event status command
1057 * @param sensorNumber - sensor number, FFh = reserved
1058 *
1059 * @returns IPMI completion code plus response data
1060 * - sensorEventStatus - Sensor Event messages state
1061 * - assertions - Assertion event messages
1062 * - deassertions - Deassertion event messages
1063 */
1064ipmi::RspType<uint8_t, // sensorEventStatus
1065 std::bitset<16>, // assertions
1066 std::bitset<16> // deassertion
1067 >
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001068 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001069{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001070 if (sensorNum == reservedSensorNumber)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001071 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001072 return ipmi::responseInvalidFieldRequest();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001073 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001074
1075 std::string connection;
1076 std::string path;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001077 auto status = getSensorConnection(ctx, sensorNum, connection, path);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001078 if (status)
1079 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001080 phosphor::logging::log<phosphor::logging::level::ERR>(
1081 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1082 phosphor::logging::entry("SENSOR=%d", sensorNum));
1083 return ipmi::response(status);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001084 }
1085
1086 SensorMap sensorMap;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001087 if (!getSensorMap(ctx->yield, connection, path, sensorMap))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001088 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001089 phosphor::logging::log<phosphor::logging::level::ERR>(
1090 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1091 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1092 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001093 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001094 auto warningInterface =
1095 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1096 auto criticalInterface =
1097 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1098
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001099 uint8_t sensorEventStatus =
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001100 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1101
James Feist392786a2019-03-19 13:36:10 -07001102 std::optional<bool> criticalDeassertHigh =
1103 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1104 std::optional<bool> criticalDeassertLow =
1105 thresholdDeassertMap[path]["CriticalAlarmLow"];
1106 std::optional<bool> warningDeassertHigh =
1107 thresholdDeassertMap[path]["WarningAlarmHigh"];
1108 std::optional<bool> warningDeassertLow =
1109 thresholdDeassertMap[path]["WarningAlarmLow"];
1110
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001111 std::bitset<16> assertions = 0;
1112 std::bitset<16> deassertions = 0;
1113
James Feist392786a2019-03-19 13:36:10 -07001114 if (criticalDeassertHigh && !*criticalDeassertHigh)
1115 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001116 deassertions.set(static_cast<size_t>(
1117 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001118 }
1119 if (criticalDeassertLow && !*criticalDeassertLow)
1120 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001121 deassertions.set(static_cast<size_t>(
1122 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
James Feist392786a2019-03-19 13:36:10 -07001123 }
1124 if (warningDeassertHigh && !*warningDeassertHigh)
1125 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001126 deassertions.set(static_cast<size_t>(
1127 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001128 }
1129 if (warningDeassertLow && !*warningDeassertLow)
1130 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001131 deassertions.set(static_cast<size_t>(
1132 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
James Feist392786a2019-03-19 13:36:10 -07001133 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001134 if ((warningInterface != sensorMap.end()) ||
1135 (criticalInterface != sensorMap.end()))
1136 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001137 sensorEventStatus = static_cast<size_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001138 IPMISensorEventEnableByte2::eventMessagesEnable);
1139 if (warningInterface != sensorMap.end())
1140 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001141 auto& warningMap = warningInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001142
1143 auto warningHigh = warningMap.find("WarningAlarmHigh");
1144 auto warningLow = warningMap.find("WarningAlarmLow");
1145 auto warningHighAlarm = false;
1146 auto warningLowAlarm = false;
1147
1148 if (warningHigh != warningMap.end())
1149 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001150 warningHighAlarm = std::get<bool>(warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001151 }
1152 if (warningLow != warningMap.end())
1153 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001154 warningLowAlarm = std::get<bool>(warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001155 }
1156 if (warningHighAlarm)
1157 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001158 assertions.set(
1159 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1160 upperNonCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001161 }
1162 if (warningLowAlarm)
1163 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001164 assertions.set(
1165 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1166 lowerNonCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001167 }
1168 }
1169 if (criticalInterface != sensorMap.end())
1170 {
James Feistfcd2d3a2020-05-28 10:38:15 -07001171 auto& criticalMap = criticalInterface->second;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001172
1173 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1174 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1175 auto criticalHighAlarm = false;
1176 auto criticalLowAlarm = false;
1177
1178 if (criticalHigh != criticalMap.end())
1179 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001180 criticalHighAlarm = std::get<bool>(criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001181 }
1182 if (criticalLow != criticalMap.end())
1183 {
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001184 criticalLowAlarm = std::get<bool>(criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001185 }
1186 if (criticalHighAlarm)
1187 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001188 assertions.set(
1189 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1190 upperCriticalGoingHigh));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001191 }
1192 if (criticalLowAlarm)
1193 {
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001194 assertions.set(static_cast<size_t>(
1195 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001196 }
1197 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001198 }
1199
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001200 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001201}
1202
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001203static inline uint16_t getNumberOfSensors(void)
1204{
1205 return sensorTree.size() > maxIPMISensors ? maxIPMISensors
1206 : sensorTree.size();
1207}
1208
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001209static int getSensorDataRecord(ipmi::Context::ptr ctx,
1210 std::vector<uint8_t>& recordData,
1211 uint16_t recordID)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001212{
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001213 size_t fruCount = 0;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001214 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1215 if (ret != ipmi::ccSuccess)
1216 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001217 phosphor::logging::log<phosphor::logging::level::ERR>(
1218 "getSensorDataRecord: getFruSdrCount error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001219 return GENERAL_ERROR;
1220 }
1221
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001222 size_t lastRecord = getNumberOfSensors() + fruCount +
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001223 ipmi::storage::type12Count +
1224 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001225 if (recordID == lastRecordIndex)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001226 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001227 recordID = lastRecord;
1228 }
1229 if (recordID > lastRecord)
1230 {
1231 phosphor::logging::log<phosphor::logging::level::ERR>(
1232 "getSensorDataRecord: recordID > lastRecord error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001233 return GENERAL_ERROR;
1234 }
1235
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001236 if (recordID >= getNumberOfSensors())
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001237 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001238 size_t fruIndex = recordID - getNumberOfSensors();
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001239 size_t type12End = fruCount + ipmi::storage::type12Count;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001240
1241 if (fruIndex >= type12End)
1242 {
1243 // NM discovery SDR
1244 size_t nmDiscoveryIndex = fruIndex - type12End;
1245 if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
1246 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001247 phosphor::logging::log<phosphor::logging::level::ERR>(
1248 "getSensorDataRecord: NM DiscoveryIndex error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001249 return GENERAL_ERROR;
1250 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001251 recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001252 ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001253 }
1254 else if (fruIndex >= fruCount)
1255 {
1256 // handle type 12 hardcoded records
1257 size_t type12Index = fruIndex - fruCount;
1258 if (type12Index >= ipmi::storage::type12Count)
1259 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001260 phosphor::logging::log<phosphor::logging::level::ERR>(
1261 "getSensorDataRecord: type12Index error");
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001262 return GENERAL_ERROR;
1263 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001264 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001265 }
1266 else
1267 {
1268 // handle fru records
1269 get_sdr::SensorDataFruRecord data;
1270 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1271 if (ret != IPMI_CC_OK)
1272 {
1273 return GENERAL_ERROR;
1274 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001275 data.header.record_id_msb = recordID >> 8;
1276 data.header.record_id_lsb = recordID & 0xFF;
1277 recordData.insert(recordData.end(), (uint8_t*)&data,
1278 ((uint8_t*)&data) + sizeof(data));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001279 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001280
1281 return 0;
1282 }
1283
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001284 // Perform a incremental scan of the SDR Record ID's and translate the
1285 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
1286 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
1287 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
1288 // which has special meaning.
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001289 std::string connection;
1290 std::string path;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001291 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001292 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001293 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001294 // LUN 0 has one reserved sensor number. Compensate here by adding one
1295 // to the record ID
1296 sensNumFromRecID = recordID + 1;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001297 ctx->lun = 1;
1298 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001299 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001300 {
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001301 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
1302 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
1303 // rules governing its use.
1304 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001305 ctx->lun = 3;
1306 }
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001307
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001308 auto status = getSensorConnection(
1309 ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001310 if (status)
1311 {
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 "getSensorDataRecord: getSensorConnection error");
1314 return GENERAL_ERROR;
1315 }
1316 SensorMap sensorMap;
1317 if (!getSensorMap(ctx->yield, connection, path, sensorMap,
1318 sensorMapUpdatePeriod))
1319 {
1320 phosphor::logging::log<phosphor::logging::level::ERR>(
1321 "getSensorDataRecord: getSensorMap error");
1322 return GENERAL_ERROR;
1323 }
1324 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001325 // Return an error on LUN 2 assingments, and any sensor number beyond the
1326 // range of LUN 3
1327 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
1328 (sensorNum > lun3MaxSensorNum))
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001329 {
1330 phosphor::logging::log<phosphor::logging::level::ERR>(
1331 "getSensorDataRecord: invalidSensorNumber");
1332 return GENERAL_ERROR;
1333 }
1334 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1335 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1336
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001337 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
1338 (lun != ctx->lun))
Johnathan Manteyb485b1e2021-07-28 15:08:30 -07001339 {
1340 phosphor::logging::log<phosphor::logging::level::ERR>(
1341 "getSensorDataRecord: sensor record mismatch");
1342 return GENERAL_ERROR;
1343 }
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001344 get_sdr::SensorDataFullRecord record = {0};
1345
1346 get_sdr::header::set_record_id(
1347 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1348
1349 record.header.sdr_version = ipmiSdrVersion;
1350 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1351 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1352 sizeof(get_sdr::SensorDataRecordHeader);
1353 record.key.owner_id = 0x20;
1354 record.key.owner_lun = lun;
1355 record.key.sensor_number = sensornumber;
1356
1357 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1358 record.body.sensor_type = getSensorTypeFromPath(path);
1359 std::string type = getSensorTypeStringFromPath(path);
1360 auto typeCstr = type.c_str();
1361 auto findUnits = sensorUnits.find(typeCstr);
1362 if (findUnits != sensorUnits.end())
1363 {
1364 record.body.sensor_units_2_base =
1365 static_cast<uint8_t>(findUnits->second);
1366 } // else default 0x0 unspecified
1367
1368 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1369
1370 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1371 if (sensorObject == sensorMap.end())
1372 {
1373 phosphor::logging::log<phosphor::logging::level::ERR>(
1374 "getSensorDataRecord: sensorObject error");
1375 return GENERAL_ERROR;
1376 }
1377
1378 uint8_t entityId = 0;
1379 uint8_t entityInstance = 0x01;
1380
1381 // follow the association chain to get the parent board's entityid and
1382 // entityInstance
1383 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1384
1385 record.body.entity_id = entityId;
1386 record.body.entity_instance = entityInstance;
1387
1388 auto maxObject = sensorObject->second.find("MaxValue");
1389 auto minObject = sensorObject->second.find("MinValue");
1390
1391 // If min and/or max are left unpopulated,
1392 // then default to what a signed byte would be, namely (-128,127) range.
1393 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1394 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1395 if (maxObject != sensorObject->second.end())
1396 {
1397 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1398 }
1399
1400 if (minObject != sensorObject->second.end())
1401 {
1402 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1403 }
1404
1405 int16_t mValue = 0;
1406 int8_t rExp = 0;
1407 int16_t bValue = 0;
1408 int8_t bExp = 0;
1409 bool bSigned = false;
1410
1411 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1412 {
1413 phosphor::logging::log<phosphor::logging::level::ERR>(
1414 "getSensorDataRecord: getSensorAttributes error");
1415 return GENERAL_ERROR;
1416 }
1417
1418 // The record.body is a struct SensorDataFullRecordBody
1419 // from sensorhandler.hpp in phosphor-ipmi-host.
1420 // The meaning of these bits appears to come from
1421 // table 43.1 of the IPMI spec.
1422 // The above 5 sensor attributes are stuffed in as follows:
1423 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1424 // Byte 22-24 are for other purposes
1425 // Byte 25 = MMMMMMMM = LSB of M
1426 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1427 // Byte 27 = BBBBBBBB = LSB of B
1428 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1429 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1430 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1431
1432 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1433 record.body.m_lsb = mValue & 0xFF;
1434
1435 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1436 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1437
1438 // move the smallest bit of the MSB into place (bit 9)
1439 // the MSbs are bits 7:8 in m_msb_and_tolerance
1440 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1441
1442 record.body.b_lsb = bValue & 0xFF;
1443
1444 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1445 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1446
1447 // move the smallest bit of the MSB into place (bit 9)
1448 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1449 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1450
1451 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1452 uint8_t rExpBits = rExp & 0x07;
1453
1454 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1455 uint8_t bExpBits = bExp & 0x07;
1456
1457 // move rExp and bExp into place
1458 record.body.r_b_exponents =
1459 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1460
1461 // Set the analog reading byte interpretation accordingly
1462 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1463
1464 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1465 // These seem redundant, but derivable from the above 5 attributes
1466 // Original comment said "todo fill out rest of units"
1467
1468 // populate sensor name from path
1469 std::string name;
1470 size_t nameStart = path.rfind("/");
1471 if (nameStart != std::string::npos)
1472 {
1473 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1474 }
1475
1476 std::replace(name.begin(), name.end(), '_', ' ');
1477 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1478 {
1479 // try to not truncate by replacing common words
1480 constexpr std::array<std::pair<const char*, const char*>, 2>
1481 replaceWords = {std::make_pair("Output", "Out"),
1482 std::make_pair("Input", "In")};
1483 for (const auto& [find, replace] : replaceWords)
1484 {
1485 boost::replace_all(name, find, replace);
1486 }
1487
1488 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1489 }
Paul Fertser97221512022-08-18 12:36:41 +00001490 get_sdr::body::set_id_strlen(name.size(), &record.body);
1491 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001492 std::strncpy(record.body.id_string, name.c_str(),
1493 sizeof(record.body.id_string));
1494
Josh Lehan06aa21a2020-10-28 21:59:06 -07001495 // Remember the sensor name, as determined for this sensor number
1496 details::sdrStatsTable.updateName(sensornumber, name);
1497
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001498 IPMIThresholds thresholdData;
1499 try
1500 {
1501 thresholdData = getIPMIThresholds(sensorMap);
1502 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001503 catch (const std::exception&)
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001504 {
1505 phosphor::logging::log<phosphor::logging::level::ERR>(
1506 "getSensorDataRecord: getIPMIThresholds error");
1507 return GENERAL_ERROR;
1508 }
1509
1510 if (thresholdData.criticalHigh)
1511 {
1512 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1513 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1514 IPMISensorEventEnableThresholds::criticalThreshold);
1515 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1516 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1517 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1518 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1519 record.body.discrete_reading_setting_mask[0] |=
1520 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1521 }
1522 if (thresholdData.warningHigh)
1523 {
1524 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1525 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1526 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1527 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1528 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1529 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1530 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1531 record.body.discrete_reading_setting_mask[0] |=
1532 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1533 }
1534 if (thresholdData.criticalLow)
1535 {
1536 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1537 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1538 IPMISensorEventEnableThresholds::criticalThreshold);
1539 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1540 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1541 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1542 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1543 record.body.discrete_reading_setting_mask[0] |=
1544 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1545 }
1546 if (thresholdData.warningLow)
1547 {
1548 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1549 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1550 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1551 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1552 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1553 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1554 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1555 record.body.discrete_reading_setting_mask[0] |=
1556 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1557 }
1558
1559 // everything that is readable is setable
1560 record.body.discrete_reading_setting_mask[1] =
1561 record.body.discrete_reading_setting_mask[0];
1562 recordData.insert(recordData.end(), (uint8_t*)&record,
1563 ((uint8_t*)&record) + sizeof(record));
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001564 return 0;
1565}
1566
1567/** @brief implements the get SDR Info command
1568 * @param count - Operation
1569 *
1570 * @returns IPMI completion code plus response data
1571 * - sdrCount - sensor/SDR count
1572 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1573 */
1574static ipmi::RspType<uint8_t, // respcount
1575 uint8_t, // dynamic population flags
1576 uint32_t // last time a sensor was added
1577 >
1578 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1579 std::optional<uint8_t> count)
1580{
1581 uint8_t sdrCount = 0;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001582 uint16_t recordID = 0;
1583 std::vector<uint8_t> record;
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001584 // Sensors are dynamically allocated, and there is at least one LUN
1585 uint8_t lunsAndDynamicPopulation = 0x80;
1586 constexpr uint8_t getSdrCount = 0x01;
1587 constexpr uint8_t getSensorCount = 0x00;
1588
1589 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1590 {
1591 return ipmi::responseResponseError();
1592 }
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001593 uint16_t numSensors = getNumberOfSensors();
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001594 if (count.value_or(0) == getSdrCount)
1595 {
1596 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001597 while (!getSensorDataRecord(ctx, record, recordID++))
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001598 {
1599 get_sdr::SensorDataRecordHeader* hdr =
1600 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001601 record.data());
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001602 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1603 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001604 get_sdr::SensorDataFullRecord* recordData =
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001605 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001606 record.data());
1607 if (ctx->lun == recordData->key.owner_lun)
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001608 {
1609 sdrCount++;
1610 }
1611 }
1612 }
1613 }
1614 else if (count.value_or(0) == getSensorCount)
1615 {
1616 // Return the number of sensors attached to the LUN
1617 if ((ctx->lun == 0) && (numSensors > 0))
1618 {
1619 sdrCount =
1620 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1621 }
1622 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1623 {
1624 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1625 ? maxSensorsPerLUN
1626 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1627 }
1628 else if (ctx->lun == 3)
1629 {
1630 if (numSensors <= maxIPMISensors)
1631 {
1632 sdrCount =
1633 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1634 }
1635 else
1636 {
1637 // error
1638 throw std::out_of_range(
1639 "Maximum number of IPMI sensors exceeded.");
1640 }
1641 }
1642 }
1643 else
1644 {
1645 return ipmi::responseInvalidFieldRequest();
1646 }
1647
1648 // Get Sensor count. This returns the number of sensors
1649 if (numSensors > 0)
1650 {
1651 lunsAndDynamicPopulation |= 1;
1652 }
1653 if (numSensors > maxSensorsPerLUN)
1654 {
1655 lunsAndDynamicPopulation |= 2;
1656 }
1657 if (numSensors >= (maxSensorsPerLUN * 2))
1658 {
1659 lunsAndDynamicPopulation |= 8;
1660 }
1661 if (numSensors > maxIPMISensors)
1662 {
1663 // error
1664 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1665 }
1666
1667 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1668 sdrLastAdd);
1669}
1670
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001671/* end sensor commands */
1672
1673/* storage commands */
1674
James Feist74c50c62019-08-14 14:18:41 -07001675ipmi::RspType<uint8_t, // sdr version
1676 uint16_t, // record count
1677 uint16_t, // free space
1678 uint32_t, // most recent addition
1679 uint32_t, // most recent erase
1680 uint8_t // operationSupport
1681 >
James Feist25690252019-12-23 12:25:49 -08001682 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001683{
James Feist74c50c62019-08-14 14:18:41 -07001684 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001685 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001686 {
James Feist74c50c62019-08-14 14:18:41 -07001687 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001688 }
1689
James Feist74c50c62019-08-14 14:18:41 -07001690 size_t fruCount = 0;
James Feist25690252019-12-23 12:25:49 -08001691 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001692 if (ret != ipmi::ccSuccess)
1693 {
1694 return ipmi::response(ret);
1695 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001696
sureshvijayv1d4b74b42021-10-08 10:49:18 +05301697 uint16_t recordCount = getNumberOfSensors() + fruCount +
1698 ipmi::storage::type12Count +
1699 ipmi::storage::nmDiscoverySDRCount;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001700
James Feist74c50c62019-08-14 14:18:41 -07001701 uint8_t operationSupport = static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001702 SdrRepositoryInfoOps::overflow); // write not supported
James Feist74c50c62019-08-14 14:18:41 -07001703
1704 operationSupport |=
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001705 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001706 operationSupport |= static_cast<uint8_t>(
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001707 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
James Feist74c50c62019-08-14 14:18:41 -07001708 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1709 unspecifiedFreeSpace, sdrLastAdd,
1710 sdrLastRemove, operationSupport);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001711}
1712
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001713/** @brief implements the get SDR allocation info command
1714 *
1715 * @returns IPMI completion code plus response data
1716 * - allocUnits - Number of possible allocation units
1717 * - allocUnitSize - Allocation unit size in bytes.
1718 * - allocUnitFree - Number of free allocation units
1719 * - allocUnitLargestFree - Largest free block in allocation units
1720 * - maxRecordSize - Maximum record size in allocation units.
1721 */
1722ipmi::RspType<uint16_t, // allocUnits
1723 uint16_t, // allocUnitSize
1724 uint16_t, // allocUnitFree
1725 uint16_t, // allocUnitLargestFree
1726 uint8_t // maxRecordSize
1727 >
1728 ipmiStorageGetSDRAllocationInfo()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001729{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001730 // 0000h unspecified number of alloc units
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001731 constexpr uint16_t allocUnits = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001732
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001733 constexpr uint16_t allocUnitFree = 0;
1734 constexpr uint16_t allocUnitLargestFree = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001735 // only allow one block at a time
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001736 constexpr uint8_t maxRecordSize = 1;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001737
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001738 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1739 allocUnitLargestFree, maxRecordSize);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001740}
1741
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001742/** @brief implements the reserve SDR command
1743 * @returns IPMI completion code plus response data
1744 * - sdrReservationID
1745 */
1746ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001747{
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001748 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -08001749 if (sdrReservationID == 0)
1750 {
1751 sdrReservationID++;
1752 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001753
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001754 return ipmi::responseSuccess(sdrReservationID);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001755}
1756
James Feistb49a98a2019-04-16 13:48:09 -07001757ipmi::RspType<uint16_t, // next record ID
1758 std::vector<uint8_t> // payload
1759 >
James Feist25690252019-12-23 12:25:49 -08001760 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1761 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001762{
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001763 size_t fruCount = 0;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001764 // reservation required for partial reads with non zero offset into
1765 // record
James Feistb49a98a2019-04-16 13:48:09 -07001766 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001767 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001768 phosphor::logging::log<phosphor::logging::level::ERR>(
1769 "ipmiStorageGetSDR: responseInvalidReservationId");
James Feistb49a98a2019-04-16 13:48:09 -07001770 return ipmi::responseInvalidReservationId();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001771 }
James Feist25690252019-12-23 12:25:49 -08001772 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
James Feist74c50c62019-08-14 14:18:41 -07001773 if (ret != ipmi::ccSuccess)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001774 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001775 phosphor::logging::log<phosphor::logging::level::ERR>(
1776 "ipmiStorageGetSDR: getFruSdrCount error");
James Feistb49a98a2019-04-16 13:48:09 -07001777 return ipmi::response(ret);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001778 }
1779
Johnathan Mantey2346b5d2021-08-06 11:21:10 -07001780 size_t lastRecord = getNumberOfSensors() + fruCount +
Yong Lifee5e4c2020-01-17 19:36:29 +08001781 ipmi::storage::type12Count +
1782 ipmi::storage::nmDiscoverySDRCount - 1;
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001783 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1784
1785 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001786 {
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001787 phosphor::logging::log<phosphor::logging::level::ERR>(
1788 "ipmiStorageGetSDR: getSensorSubtree error");
1789 return ipmi::responseResponseError();
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001790 }
1791
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001792 std::vector<uint8_t> record;
1793 if (getSensorDataRecord(ctx, record, recordID))
1794 {
1795 phosphor::logging::log<phosphor::logging::level::ERR>(
1796 "ipmiStorageGetSDR: fail to get SDR");
1797 return ipmi::responseInvalidFieldRequest();
1798 }
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001799 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001800 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Kuiying Wangb9109872021-01-15 15:54:59 +08001801 if (!hdr)
1802 {
1803 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001804 "ipmiStorageGetSDR: record header is null");
1805 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001806 }
1807
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001808 size_t sdrLength =
1809 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1810 if (sdrLength < (offset + bytesToRead))
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001811 {
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001812 bytesToRead = sdrLength - offset;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001813 }
1814
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001815 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
Kuiying Wangb9109872021-01-15 15:54:59 +08001816 if (!respStart)
1817 {
1818 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001819 "ipmiStorageGetSDR: record is null");
1820 return ipmi::responseSuccess(nextRecordId, record);
Kuiying Wangb9109872021-01-15 15:54:59 +08001821 }
James Feistb49a98a2019-04-16 13:48:09 -07001822 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wang17eadbf2021-02-06 23:38:22 +08001823
James Feistb49a98a2019-04-16 13:48:09 -07001824 return ipmi::responseSuccess(nextRecordId, recordData);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001825}
1826/* end storage commands */
1827
1828void registerSensorFunctions()
1829{
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001830 // <Platform Event>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001831 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1832 ipmi::sensor_event::cmdPlatformEvent,
1833 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
Jason M. Billsae6bdb12019-04-02 12:00:04 -07001834
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001835 // <Get Sensor Reading>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001836 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1837 ipmi::sensor_event::cmdGetSensorReading,
1838 ipmi::Privilege::User, ipmiSenGetSensorReading);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001839
1840 // <Get Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001841 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1842 ipmi::sensor_event::cmdGetSensorThreshold,
1843 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001844
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001845 // <Set Sensor Threshold>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001846 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1847 ipmi::sensor_event::cmdSetSensorThreshold,
1848 ipmi::Privilege::Operator,
1849 ipmiSenSetSensorThresholds);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001850
1851 // <Get Sensor Event Enable>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001852 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1853 ipmi::sensor_event::cmdGetSensorEventEnable,
jayaprakash Mutyala39fa93f2019-05-13 12:16:30 +00001854 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001855
1856 // <Get Sensor Event Status>
jayaprakash Mutyalaccf88f62019-05-13 16:57:16 +00001857 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1858 ipmi::sensor_event::cmdGetSensorEventStatus,
1859 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001860
1861 // register all storage commands for both Sensor and Storage command
1862 // versions
1863
1864 // <Get SDR Repository Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001865 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1866 ipmi::storage::cmdGetSdrRepositoryInfo,
1867 ipmi::Privilege::User,
1868 ipmiStorageGetSDRRepositoryInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001869
Johnathan Mantey308c3a82020-07-22 11:50:54 -07001870 // <Get Device SDR Info>
1871 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1872 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1873 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1874
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001875 // <Get SDR Allocation Info>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001876 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1877 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1878 ipmi::Privilege::User,
1879 ipmiStorageGetSDRAllocationInfo);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001880
1881 // <Reserve SDR Repo>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001882 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1883 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
jayaprakash Mutyala6ae08182019-05-13 18:56:11 +00001884 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001885
Vernon Mauery98bbf692019-09-16 11:14:59 -07001886 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1887 ipmi::storage::cmdReserveSdrRepository,
1888 ipmi::Privilege::User, ipmiStorageReserveSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001889
1890 // <Get Sdr>
Vernon Mauery98bbf692019-09-16 11:14:59 -07001891 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
1892 ipmi::sensor_event::cmdGetDeviceSdr,
1893 ipmi::Privilege::User, ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001894
Vernon Mauery98bbf692019-09-16 11:14:59 -07001895 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
1896 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1897 ipmiStorageGetSDR);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001898}
1899} // namespace ipmi