blob: d67e7f5a4ab7353253c7725fe941016a1efa590c [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07002
3#include "fruread.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07004
Tomd700e762016-09-20 18:24:13 +05305#include <mapper.h>
Chris Austen10ccc0f2015-12-10 18:27:04 -06006#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07007
8#include <bitset>
Patrick Venture586d35b2018-09-07 19:56:18 -07009#include <cmath>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070010#include <cstring>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070011#include <ipmid/api.hpp>
Vernon Mauery33250242019-03-12 16:49:26 -070012#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070013#include <ipmid/utils.hpp>
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050014#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070016#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070017#include <set>
18#include <xyz/openbmc_project/Common/error.hpp>
19#include <xyz/openbmc_project/Sensor/Value/server.hpp>
20
Ratan Guptae0cc8552018-01-22 14:23:04 +053021static constexpr uint8_t fruInventoryDevice = 0x10;
22static constexpr uint8_t IPMIFruInventory = 0x02;
23static constexpr uint8_t BMCSlaveAddress = 0x20;
24
Patrick Venture0b02be92018-08-31 11:55:55 -070025extern int updateSensorRecordFromSSRAESC(const void*);
26extern sd_bus* bus;
Tom Josephbe703f72017-03-09 12:34:35 +053027extern const ipmi::sensor::IdInfoMap sensors;
Ratan Guptae0cc8552018-01-22 14:23:04 +053028extern const FruMap frus;
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -080029extern const ipmi::sensor::EntityInfoMap entities;
Ratan Guptae0cc8552018-01-22 14:23:04 +053030
Tom Josephbe703f72017-03-09 12:34:35 +053031using namespace phosphor::logging;
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050032using InternalFailure =
33 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austenac4604a2015-10-13 12:43:27 -050034
Patrick Venture0b02be92018-08-31 11:55:55 -070035void register_netfn_sen_functions() __attribute__((constructor));
Chris Austenac4604a2015-10-13 12:43:27 -050036
Patrick Venture0b02be92018-08-31 11:55:55 -070037struct sensorTypemap_t
38{
Chris Austen0012e9b2015-10-22 01:37:46 -050039 uint8_t number;
Chris Austend7cf0e42015-11-07 14:27:12 -060040 uint8_t typecode;
Chris Austen0012e9b2015-10-22 01:37:46 -050041 char dbusname[32];
Patrick Venture0b02be92018-08-31 11:55:55 -070042};
Chris Austen0012e9b2015-10-22 01:37:46 -050043
Chris Austen0012e9b2015-10-22 01:37:46 -050044sensorTypemap_t g_SensorTypeMap[] = {
45
Chris Austend7cf0e42015-11-07 14:27:12 -060046 {0x01, 0x6F, "Temp"},
47 {0x0C, 0x6F, "DIMM"},
48 {0x0C, 0x6F, "MEMORY_BUFFER"},
49 {0x07, 0x6F, "PROC"},
50 {0x07, 0x6F, "CORE"},
51 {0x07, 0x6F, "CPU"},
52 {0x0F, 0x6F, "BootProgress"},
Patrick Venture0b02be92018-08-31 11:55:55 -070053 {0xe9, 0x09, "OccStatus"}, // E9 is an internal mapping to handle sensor
54 // type code os 0x09
Chris Austend7cf0e42015-11-07 14:27:12 -060055 {0xC3, 0x6F, "BootCount"},
56 {0x1F, 0x6F, "OperatingSystemStatus"},
Chris Austen800ba712015-12-03 15:31:00 -060057 {0x12, 0x6F, "SYSTEM_EVENT"},
58 {0xC7, 0x03, "SYSTEM"},
59 {0xC7, 0x03, "MAIN_PLANAR"},
Chris Austen10ccc0f2015-12-10 18:27:04 -060060 {0xC2, 0x6F, "PowerCap"},
Tom Joseph558184e2017-09-01 13:45:05 +053061 {0x0b, 0xCA, "PowerSupplyRedundancy"},
Jayanth Othayoth0661beb2017-03-22 06:00:58 -050062 {0xDA, 0x03, "TurboAllowed"},
Tom Joseph558184e2017-09-01 13:45:05 +053063 {0xD8, 0xC8, "PowerSupplyDerating"},
Chris Austend7cf0e42015-11-07 14:27:12 -060064 {0xFF, 0x00, ""},
Chris Austen0012e9b2015-10-22 01:37:46 -050065};
66
Patrick Venture0b02be92018-08-31 11:55:55 -070067struct sensor_data_t
68{
Chris Austenac4604a2015-10-13 12:43:27 -050069 uint8_t sennum;
Patrick Venture0b02be92018-08-31 11:55:55 -070070} __attribute__((packed));
Chris Austenac4604a2015-10-13 12:43:27 -050071
Patrick Venture0b02be92018-08-31 11:55:55 -070072struct sensorreadingresp_t
73{
Chris Austen10ccc0f2015-12-10 18:27:04 -060074 uint8_t value;
75 uint8_t operation;
76 uint8_t indication[2];
Patrick Venture0b02be92018-08-31 11:55:55 -070077} __attribute__((packed));
Chris Austenac4604a2015-10-13 12:43:27 -050078
Patrick Venture83a0b842019-07-19 18:37:15 -070079const ipmi::sensor::EntityInfoMap& getIpmiEntityRecords()
80{
81 return entities;
82}
83
Patrick Venture0b02be92018-08-31 11:55:55 -070084int get_bus_for_path(const char* path, char** busname)
85{
Emily Shaffer2ae09b92017-04-05 15:09:41 -070086 return mapper_get_service(bus, path, busname);
87}
Tomd700e762016-09-20 18:24:13 +053088
Emily Shaffer2ae09b92017-04-05 15:09:41 -070089// Use a lookup table to find the interface name of a specific sensor
90// This will be used until an alternative is found. this is the first
91// step for mapping IPMI
Patrick Venture0b02be92018-08-31 11:55:55 -070092int find_openbmc_path(uint8_t num, dbus_interface_t* interface)
93{
Emily Shaffer2ae09b92017-04-05 15:09:41 -070094 int rc;
95
Emily Shaffer2ae09b92017-04-05 15:09:41 -070096 const auto& sensor_it = sensors.find(num);
97 if (sensor_it == sensors.end())
98 {
Adriana Kobylakba23ff72018-09-12 12:58:43 -050099 // The sensor map does not contain the sensor requested
100 return -EINVAL;
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700101 }
102
103 const auto& info = sensor_it->second;
104
Patrick Williams8451edf2017-06-13 09:01:06 -0500105 char* busname = nullptr;
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700106 rc = get_bus_for_path(info.sensorPath.c_str(), &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700107 if (rc < 0)
108 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700109 std::fprintf(stderr, "Failed to get %s busname: %s\n",
110 info.sensorPath.c_str(), busname);
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700111 goto final;
112 }
113
114 interface->sensortype = info.sensorType;
115 strcpy(interface->bus, busname);
116 strcpy(interface->path, info.sensorPath.c_str());
117 // Take the interface name from the beginning of the DbusInterfaceMap. This
118 // works for the Value interface but may not suffice for more complex
119 // sensors.
120 // tracked https://github.com/openbmc/phosphor-host-ipmid/issues/103
Patrick Venture0b02be92018-08-31 11:55:55 -0700121 strcpy(interface->interface,
122 info.propertyInterfaces.begin()->first.c_str());
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700123 interface->sensornumber = num;
124
125final:
126 free(busname);
127 return rc;
128}
129
Tomd700e762016-09-20 18:24:13 +0530130/////////////////////////////////////////////////////////////////////
131//
132// Routines used by ipmi commands wanting to interact on the dbus
133//
134/////////////////////////////////////////////////////////////////////
Patrick Venture0b02be92018-08-31 11:55:55 -0700135int set_sensor_dbus_state_s(uint8_t number, const char* method,
136 const char* value)
137{
Tomd700e762016-09-20 18:24:13 +0530138
139 dbus_interface_t a;
140 int r;
141 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700142 sd_bus_message* m = NULL;
Tomd700e762016-09-20 18:24:13 +0530143
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700144 r = find_openbmc_path(number, &a);
Tomd700e762016-09-20 18:24:13 +0530145
Patrick Venture0b02be92018-08-31 11:55:55 -0700146 if (r < 0)
147 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700148 std::fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
Tomd700e762016-09-20 18:24:13 +0530149 return 0;
150 }
151
Patrick Venture0b02be92018-08-31 11:55:55 -0700152 r = sd_bus_message_new_method_call(bus, &m, a.bus, a.path, a.interface,
153 method);
154 if (r < 0)
155 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700156 std::fprintf(stderr, "Failed to create a method call: %s",
157 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530158 goto final;
159 }
160
161 r = sd_bus_message_append(m, "v", "s", value);
Patrick Venture0b02be92018-08-31 11:55:55 -0700162 if (r < 0)
163 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700164 std::fprintf(stderr, "Failed to create a input parameter: %s",
165 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530166 goto final;
167 }
168
Tomd700e762016-09-20 18:24:13 +0530169 r = sd_bus_call(bus, m, 0, &error, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700170 if (r < 0)
171 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700172 std::fprintf(stderr, "Failed to call the method: %s", strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530173 }
174
175final:
176 sd_bus_error_free(&error);
177 m = sd_bus_message_unref(m);
178
179 return 0;
180}
Patrick Venture0b02be92018-08-31 11:55:55 -0700181int set_sensor_dbus_state_y(uint8_t number, const char* method,
182 const uint8_t value)
183{
Tomd700e762016-09-20 18:24:13 +0530184
185 dbus_interface_t a;
186 int r;
187 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700188 sd_bus_message* m = NULL;
Tomd700e762016-09-20 18:24:13 +0530189
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700190 r = find_openbmc_path(number, &a);
Tomd700e762016-09-20 18:24:13 +0530191
Patrick Venture0b02be92018-08-31 11:55:55 -0700192 if (r < 0)
193 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700194 std::fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
Tomd700e762016-09-20 18:24:13 +0530195 return 0;
196 }
197
Patrick Venture0b02be92018-08-31 11:55:55 -0700198 r = sd_bus_message_new_method_call(bus, &m, a.bus, a.path, a.interface,
199 method);
200 if (r < 0)
201 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700202 std::fprintf(stderr, "Failed to create a method call: %s",
203 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530204 goto final;
205 }
206
207 r = sd_bus_message_append(m, "v", "i", value);
Patrick Venture0b02be92018-08-31 11:55:55 -0700208 if (r < 0)
209 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700210 std::fprintf(stderr, "Failed to create a input parameter: %s",
211 strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530212 goto final;
213 }
214
Tomd700e762016-09-20 18:24:13 +0530215 r = sd_bus_call(bus, m, 0, &error, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700216 if (r < 0)
217 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700218 std::fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
Tomd700e762016-09-20 18:24:13 +0530219 }
220
221final:
222 sd_bus_error_free(&error);
223 m = sd_bus_message_unref(m);
224
225 return 0;
226}
227
Patrick Venture0b02be92018-08-31 11:55:55 -0700228uint8_t dbus_to_sensor_type(char* p)
229{
Chris Austenac4604a2015-10-13 12:43:27 -0500230
Patrick Venture0b02be92018-08-31 11:55:55 -0700231 sensorTypemap_t* s = g_SensorTypeMap;
232 char r = 0;
233 while (s->number != 0xFF)
234 {
235 if (!strcmp(s->dbusname, p))
236 {
Tom Joseph558184e2017-09-01 13:45:05 +0530237 r = s->typecode;
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 break;
Chris Austenac4604a2015-10-13 12:43:27 -0500239 }
Chris Austen0012e9b2015-10-22 01:37:46 -0500240 s++;
Chris Austenac4604a2015-10-13 12:43:27 -0500241 }
242
Chris Austen0012e9b2015-10-22 01:37:46 -0500243 if (s->number == 0xFF)
244 printf("Failed to find Sensor Type %s\n", p);
Chris Austenac4604a2015-10-13 12:43:27 -0500245
Chris Austen0012e9b2015-10-22 01:37:46 -0500246 return r;
Chris Austenac4604a2015-10-13 12:43:27 -0500247}
248
Patrick Venture0b02be92018-08-31 11:55:55 -0700249uint8_t get_type_from_interface(dbus_interface_t dbus_if)
250{
Chris Austen0012e9b2015-10-22 01:37:46 -0500251
Brad Bishop56003452016-10-05 21:49:19 -0400252 uint8_t type;
Chris Austen0012e9b2015-10-22 01:37:46 -0500253
Chris Austen0012e9b2015-10-22 01:37:46 -0500254 // This is where sensors that do not exist in dbus but do
255 // exist in the host code stop. This should indicate it
256 // is not a supported sensor
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 if (dbus_if.interface[0] == 0)
258 {
259 return 0;
260 }
Chris Austen0012e9b2015-10-22 01:37:46 -0500261
Emily Shaffer71174412017-04-05 15:10:40 -0700262 // Fetch type from interface itself.
263 if (dbus_if.sensortype != 0)
264 {
265 type = dbus_if.sensortype;
Patrick Venture0b02be92018-08-31 11:55:55 -0700266 }
267 else
268 {
Chris Austen0012e9b2015-10-22 01:37:46 -0500269 // Non InventoryItems
Patrick Venture4491a462018-10-13 13:00:42 -0700270 char* p = strrchr(dbus_if.path, '/');
Patrick Venture0b02be92018-08-31 11:55:55 -0700271 type = dbus_to_sensor_type(p + 1);
Chris Austen0012e9b2015-10-22 01:37:46 -0500272 }
273
Brad Bishop56003452016-10-05 21:49:19 -0400274 return type;
Patrick Venture0b02be92018-08-31 11:55:55 -0700275}
Chris Austen0012e9b2015-10-22 01:37:46 -0500276
Emily Shaffer391f3302017-04-03 10:27:08 -0700277// Replaces find_sensor
Patrick Venture0b02be92018-08-31 11:55:55 -0700278uint8_t find_type_for_sensor_number(uint8_t num)
279{
Emily Shaffer391f3302017-04-03 10:27:08 -0700280 int r;
281 dbus_interface_t dbus_if;
Emily Shaffer2ae09b92017-04-05 15:09:41 -0700282 r = find_openbmc_path(num, &dbus_if);
Patrick Venture0b02be92018-08-31 11:55:55 -0700283 if (r < 0)
284 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700285 std::fprintf(stderr, "Could not find sensor %d\n", num);
Lei YU91875f72018-04-03 15:14:49 +0800286 return 0;
Emily Shaffer391f3302017-04-03 10:27:08 -0700287 }
288 return get_type_from_interface(dbus_if);
289}
290
Chris Austen0012e9b2015-10-22 01:37:46 -0500291ipmi_ret_t ipmi_sen_get_sensor_type(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700292 ipmi_request_t request,
293 ipmi_response_t response,
294 ipmi_data_len_t data_len,
295 ipmi_context_t context)
Chris Austenac4604a2015-10-13 12:43:27 -0500296{
Patrick Ventured99148b2018-10-13 10:06:13 -0700297 auto reqptr = static_cast<sensor_data_t*>(request);
Chris Austenac4604a2015-10-13 12:43:27 -0500298 ipmi_ret_t rc = IPMI_CC_OK;
299
Patrick Venture0b02be92018-08-31 11:55:55 -0700300 printf("IPMI GET_SENSOR_TYPE [0x%02X]\n", reqptr->sennum);
Chris Austenac4604a2015-10-13 12:43:27 -0500301
302 // TODO Not sure what the System-event-sensor is suppose to return
303 // need to ask Hostboot team
Patrick Venture0b02be92018-08-31 11:55:55 -0700304 unsigned char buf[] = {0x00, 0x6F};
Chris Austenac4604a2015-10-13 12:43:27 -0500305
Emily Shaffer391f3302017-04-03 10:27:08 -0700306 buf[0] = find_type_for_sensor_number(reqptr->sennum);
Chris Austen0012e9b2015-10-22 01:37:46 -0500307
308 // HACK UNTIL Dbus gets updated or we find a better way
Patrick Venture0b02be92018-08-31 11:55:55 -0700309 if (buf[0] == 0)
310 {
Chris Austen800ba712015-12-03 15:31:00 -0600311 rc = IPMI_CC_SENSOR_INVALID;
Chris Austen0012e9b2015-10-22 01:37:46 -0500312 }
313
Chris Austenac4604a2015-10-13 12:43:27 -0500314 *data_len = sizeof(buf);
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700315 std::memcpy(response, &buf, *data_len);
Chris Austenac4604a2015-10-13 12:43:27 -0500316
Chris Austenac4604a2015-10-13 12:43:27 -0500317 return rc;
318}
319
Patrick Venture0b02be92018-08-31 11:55:55 -0700320const std::set<std::string> analogSensorInterfaces = {
Emily Shaffercc941e12017-06-14 13:06:26 -0700321 "xyz.openbmc_project.Sensor.Value",
Patrick Venturee9a64052017-08-18 19:17:27 -0700322 "xyz.openbmc_project.Control.FanPwm",
Emily Shaffercc941e12017-06-14 13:06:26 -0700323};
324
325bool isAnalogSensor(const std::string& interface)
326{
327 return (analogSensorInterfaces.count(interface));
328}
329
Patrick Venture0b02be92018-08-31 11:55:55 -0700330ipmi_ret_t setSensorReading(void* request)
Tom Josephbe703f72017-03-09 12:34:35 +0530331{
Tom Joseph816e92b2017-09-06 19:23:00 +0530332 ipmi::sensor::SetSensorReadingReq cmdData =
Patrick Venture0b02be92018-08-31 11:55:55 -0700333 *(static_cast<ipmi::sensor::SetSensorReadingReq*>(request));
Tom Josephbe703f72017-03-09 12:34:35 +0530334
335 // Check if the Sensor Number is present
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500336 const auto iter = sensors.find(cmdData.number);
Tom Josephbe703f72017-03-09 12:34:35 +0530337 if (iter == sensors.end())
338 {
339 return IPMI_CC_SENSOR_INVALID;
340 }
341
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500342 try
343 {
Jayanth Othayoth0922bde2018-04-02 07:59:34 -0500344 if (ipmi::sensor::Mutability::Write !=
Patrick Venture0b02be92018-08-31 11:55:55 -0700345 (iter->second.mutability & ipmi::sensor::Mutability::Write))
Jayanth Othayoth0922bde2018-04-02 07:59:34 -0500346 {
347 log<level::ERR>("Sensor Set operation is not allowed",
348 entry("SENSOR_NUM=%d", cmdData.number));
349 return IPMI_CC_ILLEGAL_COMMAND;
350 }
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500351 return iter->second.updateFunc(cmdData, iter->second);
352 }
353 catch (InternalFailure& e)
354 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700355 log<level::ERR>("Set sensor failed",
356 entry("SENSOR_NUM=%d", cmdData.number));
357 commit<InternalFailure>();
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500358 }
Tom Joseph82024322017-09-28 20:07:29 +0530359 catch (const std::runtime_error& e)
360 {
361 log<level::ERR>(e.what());
362 }
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -0500363
364 return IPMI_CC_UNSPECIFIED_ERROR;
Tom Josephbe703f72017-03-09 12:34:35 +0530365}
Chris Austenac4604a2015-10-13 12:43:27 -0500366
Chris Austen0012e9b2015-10-22 01:37:46 -0500367ipmi_ret_t ipmi_sen_set_sensor(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700368 ipmi_request_t request, ipmi_response_t response,
369 ipmi_data_len_t data_len, ipmi_context_t context)
Chris Austenac4604a2015-10-13 12:43:27 -0500370{
Patrick Ventured99148b2018-10-13 10:06:13 -0700371 auto reqptr = static_cast<sensor_data_t*>(request);
Chris Austenac4604a2015-10-13 12:43:27 -0500372
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530373 log<level::DEBUG>("IPMI SET_SENSOR",
374 entry("SENSOR_NUM=0x%02x", reqptr->sennum));
Chris Austenac4604a2015-10-13 12:43:27 -0500375
Tom Josephbe703f72017-03-09 12:34:35 +0530376 /*
377 * This would support the Set Sensor Reading command for the presence
378 * and functional state of Processor, Core & DIMM. For the remaining
379 * sensors the existing support is invoked.
380 */
381 auto ipmiRC = setSensorReading(request);
382
Patrick Venture0b02be92018-08-31 11:55:55 -0700383 if (ipmiRC == IPMI_CC_SENSOR_INVALID)
Tom Josephbe703f72017-03-09 12:34:35 +0530384 {
385 updateSensorRecordFromSSRAESC(reqptr);
386 ipmiRC = IPMI_CC_OK;
387 }
Chris Austen8a45e7c2015-10-15 00:31:46 -0500388
Patrick Venture0b02be92018-08-31 11:55:55 -0700389 *data_len = 0;
Tom Josephbe703f72017-03-09 12:34:35 +0530390 return ipmiRC;
Chris Austenac4604a2015-10-13 12:43:27 -0500391}
392
Tom Joseph3ee668f2018-03-02 19:49:17 +0530393ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700394 ipmi_request_t request,
395 ipmi_response_t response,
396 ipmi_data_len_t data_len,
397 ipmi_context_t context)
Tom Joseph3ee668f2018-03-02 19:49:17 +0530398{
Patrick Ventured99148b2018-10-13 10:06:13 -0700399 auto reqptr = static_cast<sensor_data_t*>(request);
400 auto resp = static_cast<sensorreadingresp_t*>(response);
Patrick Venture0b02be92018-08-31 11:55:55 -0700401 ipmi::sensor::GetSensorResponse getResponse{};
Tom Joseph3ee668f2018-03-02 19:49:17 +0530402 static constexpr auto scanningEnabledBit = 6;
403
404 const auto iter = sensors.find(reqptr->sennum);
405 if (iter == sensors.end())
406 {
Adriana Kobylakba23ff72018-09-12 12:58:43 -0500407 return IPMI_CC_SENSOR_INVALID;
Tom Joseph3ee668f2018-03-02 19:49:17 +0530408 }
409 if (ipmi::sensor::Mutability::Read !=
Patrick Venture0b02be92018-08-31 11:55:55 -0700410 (iter->second.mutability & ipmi::sensor::Mutability::Read))
Tom Joseph3ee668f2018-03-02 19:49:17 +0530411 {
Jayanth Othayoth6ccf8812018-04-05 22:58:48 -0500412 return IPMI_CC_ILLEGAL_COMMAND;
Tom Joseph3ee668f2018-03-02 19:49:17 +0530413 }
414
415 try
416 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700417 getResponse = iter->second.getFunc(iter->second);
Tom Joseph3ee668f2018-03-02 19:49:17 +0530418 *data_len = getResponse.size();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700419 std::memcpy(resp, getResponse.data(), *data_len);
Tom Joseph3ee668f2018-03-02 19:49:17 +0530420 resp->operation = 1 << scanningEnabledBit;
421 return IPMI_CC_OK;
422 }
423 catch (const std::exception& e)
424 {
425 *data_len = getResponse.size();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700426 std::memcpy(resp, getResponse.data(), *data_len);
Tom Joseph3ee668f2018-03-02 19:49:17 +0530427 return IPMI_CC_OK;
428 }
429}
430
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530431void getSensorThresholds(uint8_t sensorNum,
432 get_sdr::GetSensorThresholdsResponse* response)
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600433{
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530434 constexpr auto warningThreshIntf =
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600435 "xyz.openbmc_project.Sensor.Threshold.Warning";
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530436 constexpr auto criticalThreshIntf =
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600437 "xyz.openbmc_project.Sensor.Threshold.Critical";
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600438
439 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
440
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530441 const auto iter = sensors.find(sensorNum);
442 const auto info = iter->second;
443
444 auto service = ipmi::getService(bus, info.sensorInterface, info.sensorPath);
445
Patrick Venture0b02be92018-08-31 11:55:55 -0700446 auto warnThresholds = ipmi::getAllDbusProperties(
447 bus, service, info.sensorPath, warningThreshIntf);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530448
Vernon Maueryf442e112019-04-09 11:44:36 -0700449 double warnLow = std::visit(ipmi::VariantToDoubleVisitor(),
450 warnThresholds["WarningLow"]);
451 double warnHigh = std::visit(ipmi::VariantToDoubleVisitor(),
452 warnThresholds["WarningHigh"]);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530453
454 if (warnLow != 0)
455 {
Patrick Venture586d35b2018-09-07 19:56:18 -0700456 warnLow *= std::pow(10, info.scale - info.exponentR);
Patrick Venture0b02be92018-08-31 11:55:55 -0700457 response->lowerNonCritical = static_cast<uint8_t>(
458 (warnLow - info.scaledOffset) / info.coefficientM);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530459 response->validMask |= static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700460 ipmi::sensor::ThresholdMask::NON_CRITICAL_LOW_MASK);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530461 }
462
463 if (warnHigh != 0)
464 {
Patrick Venture586d35b2018-09-07 19:56:18 -0700465 warnHigh *= std::pow(10, info.scale - info.exponentR);
Patrick Venture0b02be92018-08-31 11:55:55 -0700466 response->upperNonCritical = static_cast<uint8_t>(
467 (warnHigh - info.scaledOffset) / info.coefficientM);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530468 response->validMask |= static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700469 ipmi::sensor::ThresholdMask::NON_CRITICAL_HIGH_MASK);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530470 }
471
Patrick Venture0b02be92018-08-31 11:55:55 -0700472 auto critThresholds = ipmi::getAllDbusProperties(
473 bus, service, info.sensorPath, criticalThreshIntf);
Vernon Maueryf442e112019-04-09 11:44:36 -0700474 double critLow = std::visit(ipmi::VariantToDoubleVisitor(),
475 critThresholds["CriticalLow"]);
476 double critHigh = std::visit(ipmi::VariantToDoubleVisitor(),
477 critThresholds["CriticalHigh"]);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530478
479 if (critLow != 0)
480 {
Patrick Venture586d35b2018-09-07 19:56:18 -0700481 critLow *= std::pow(10, info.scale - info.exponentR);
Patrick Venture0b02be92018-08-31 11:55:55 -0700482 response->lowerCritical = static_cast<uint8_t>(
483 (critLow - info.scaledOffset) / info.coefficientM);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530484 response->validMask |= static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700485 ipmi::sensor::ThresholdMask::CRITICAL_LOW_MASK);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530486 }
487
488 if (critHigh != 0)
489 {
Patrick Venture586d35b2018-09-07 19:56:18 -0700490 critHigh *= std::pow(10, info.scale - info.exponentR);
Patrick Venture0b02be92018-08-31 11:55:55 -0700491 response->upperCritical = static_cast<uint8_t>(
492 (critHigh - info.scaledOffset) / info.coefficientM);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530493 response->validMask |= static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700494 ipmi::sensor::ThresholdMask::CRITICAL_HIGH_MASK);
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530495 }
496}
497
498ipmi_ret_t ipmi_sen_get_sensor_thresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700499 ipmi_request_t request,
500 ipmi_response_t response,
501 ipmi_data_len_t data_len,
502 ipmi_context_t context)
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530503{
504 constexpr auto valueInterface = "xyz.openbmc_project.Sensor.Value";
505
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600506 if (*data_len != sizeof(uint8_t))
507 {
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530508 *data_len = 0;
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600509 return IPMI_CC_REQ_DATA_LEN_INVALID;
510 }
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600511
Patrick Venture0b02be92018-08-31 11:55:55 -0700512 auto sensorNum = *(reinterpret_cast<const uint8_t*>(request));
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530513 *data_len = 0;
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600514
515 const auto iter = sensors.find(sensorNum);
516 if (iter == sensors.end())
517 {
518 return IPMI_CC_SENSOR_INVALID;
519 }
520
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530521 const auto info = iter->second;
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600522
Patrick Venture0b02be92018-08-31 11:55:55 -0700523 // Proceed only if the sensor value interface is implemented.
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530524 if (info.propertyInterfaces.find(valueInterface) ==
525 info.propertyInterfaces.end())
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600526 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700527 // return with valid mask as 0
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600528 return IPMI_CC_OK;
529 }
530
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530531 auto responseData =
532 reinterpret_cast<get_sdr::GetSensorThresholdsResponse*>(response);
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600533
534 try
535 {
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530536 getSensorThresholds(sensorNum, responseData);
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600537 }
Tom Joseph0ac0dd22018-02-16 09:14:45 +0530538 catch (std::exception& e)
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600539 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700540 // Mask if the property is not present
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -0600541 responseData->validMask = 0;
542 }
543
544 *data_len = sizeof(get_sdr::GetSensorThresholdsResponse);
545 return IPMI_CC_OK;
546}
547
Chris Austen0012e9b2015-10-22 01:37:46 -0500548ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
549 ipmi_request_t request, ipmi_response_t response,
Chris Austenac4604a2015-10-13 12:43:27 -0500550 ipmi_data_len_t data_len, ipmi_context_t context)
551{
Nan Li70aa8d92016-08-29 00:11:10 +0800552 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenac4604a2015-10-13 12:43:27 -0500553
Patrick Venture0b02be92018-08-31 11:55:55 -0700554 printf("IPMI S/E Wildcard Netfn:[0x%X], Cmd:[0x%X]\n", netfn, cmd);
Chris Austenac4604a2015-10-13 12:43:27 -0500555 *data_len = 0;
556
557 return rc;
558}
559
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000560/** @brief implements the get SDR Info command
561 * @param count - Operation
562 *
563 * @returns IPMI completion code plus response data
564 * - sdrCount - sensor/SDR count
565 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
566 */
567ipmi::RspType<uint8_t, // respcount
568 uint8_t // dynamic population flags
569 >
570 ipmiSensorGetDeviceSdrInfo(std::optional<uint8_t> count)
Emily Shafferd06e0e72017-04-05 09:08:57 -0700571{
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000572 uint8_t sdrCount;
573 // multiple LUNs not supported.
574 constexpr uint8_t lunsAndDynamicPopulation = 1;
575 constexpr uint8_t getSdrCount = 0x01;
576 constexpr uint8_t getSensorCount = 0x00;
577
578 if (count.value_or(0) == getSdrCount)
Emily Shafferd06e0e72017-04-05 09:08:57 -0700579 {
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000580 // Get SDR count. This returns the total number of SDRs in the device.
Patrick Venture83a0b842019-07-19 18:37:15 -0700581 const auto& entityRecords = getIpmiEntityRecords();
582 sdrCount = sensors.size() + frus.size() + entityRecords.size();
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000583 }
584 else if (count.value_or(0) == getSensorCount)
585 {
586 // Get Sensor count. This returns the number of sensors
587 sdrCount = sensors.size();
Emily Shafferd06e0e72017-04-05 09:08:57 -0700588 }
589 else
590 {
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000591 return ipmi::responseInvalidCommandOnLun();
Emily Shafferd06e0e72017-04-05 09:08:57 -0700592 }
593
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000594 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation);
Emily Shafferd06e0e72017-04-05 09:08:57 -0700595}
596
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000597/** @brief implements the reserve SDR command
598 * @returns IPMI completion code plus response data
599 * - reservationID - reservation ID
600 */
601ipmi::RspType<uint16_t> ipmiSensorReserveSdr()
Emily Shaffera344afc2017-04-13 15:09:39 -0700602{
603 // A constant reservation ID is okay until we implement add/remove SDR.
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000604 constexpr uint16_t reservationID = 1;
Emily Shaffera344afc2017-04-13 15:09:39 -0700605
jayaprakash Mutyalad9578232019-05-13 20:22:50 +0000606 return ipmi::responseSuccess(reservationID);
Emily Shaffera344afc2017-04-13 15:09:39 -0700607}
Chris Austenac4604a2015-10-13 12:43:27 -0500608
Patrick Venture0b02be92018-08-31 11:55:55 -0700609void setUnitFieldsForObject(const ipmi::sensor::Info* info,
610 get_sdr::SensorDataFullRecordBody* body)
Emily Shaffercc941e12017-06-14 13:06:26 -0700611{
Tom Josephdc212b22018-02-16 09:59:57 +0530612 namespace server = sdbusplus::xyz::openbmc_project::Sensor::server;
613 try
Emily Shaffercc941e12017-06-14 13:06:26 -0700614 {
Tom Josephdc212b22018-02-16 09:59:57 +0530615 auto unit = server::Value::convertUnitFromString(info->unit);
616 // Unit strings defined in
617 // phosphor-dbus-interfaces/xyz/openbmc_project/Sensor/Value.interface.yaml
618 switch (unit)
Emily Shaffercc941e12017-06-14 13:06:26 -0700619 {
Tom Josephdc212b22018-02-16 09:59:57 +0530620 case server::Value::Unit::DegreesC:
621 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_DEGREES_C;
622 break;
623 case server::Value::Unit::RPMS:
Kirill Pakhomov812e44c2018-10-22 16:25:35 +0300624 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_RPM;
Tom Josephdc212b22018-02-16 09:59:57 +0530625 break;
626 case server::Value::Unit::Volts:
627 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_VOLTS;
628 break;
629 case server::Value::Unit::Meters:
630 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_METERS;
631 break;
632 case server::Value::Unit::Amperes:
633 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_AMPERES;
634 break;
635 case server::Value::Unit::Joules:
636 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_JOULES;
637 break;
638 case server::Value::Unit::Watts:
639 body->sensor_units_2_base = get_sdr::SENSOR_UNIT_WATTS;
640 break;
641 default:
642 // Cannot be hit.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700643 std::fprintf(stderr, "Unknown value unit type: = %s\n",
644 info->unit.c_str());
Emily Shaffercc941e12017-06-14 13:06:26 -0700645 }
646 }
Patrick Venture64678b82018-10-13 13:11:32 -0700647 catch (const sdbusplus::exception::InvalidEnumString& e)
Emily Shaffercc941e12017-06-14 13:06:26 -0700648 {
Tom Josephdc212b22018-02-16 09:59:57 +0530649 log<level::WARNING>("Warning: no unit provided for sensor!");
Emily Shaffercc941e12017-06-14 13:06:26 -0700650 }
Emily Shaffercc941e12017-06-14 13:06:26 -0700651}
652
Patrick Venture0b02be92018-08-31 11:55:55 -0700653ipmi_ret_t populate_record_from_dbus(get_sdr::SensorDataFullRecordBody* body,
654 const ipmi::sensor::Info* info,
Emily Shafferbbef71c2017-05-08 16:36:17 -0700655 ipmi_data_len_t data_len)
656{
657 /* Functional sensor case */
Emily Shaffercc941e12017-06-14 13:06:26 -0700658 if (isAnalogSensor(info->propertyInterfaces.begin()->first))
Emily Shafferbbef71c2017-05-08 16:36:17 -0700659 {
Emily Shafferbbef71c2017-05-08 16:36:17 -0700660
661 body->sensor_units_1 = 0; // unsigned, no rate, no modifier, not a %
662
663 /* Unit info */
Tom Josephdc212b22018-02-16 09:59:57 +0530664 setUnitFieldsForObject(info, body);
Emily Shaffer10f49592017-05-10 12:01:10 -0700665
666 get_sdr::body::set_b(info->coefficientB, body);
667 get_sdr::body::set_m(info->coefficientM, body);
668 get_sdr::body::set_b_exp(info->exponentB, body);
Tom Josephdc212b22018-02-16 09:59:57 +0530669 get_sdr::body::set_r_exp(info->exponentR, body);
Emily Shafferbbef71c2017-05-08 16:36:17 -0700670
Emily Shafferbbef71c2017-05-08 16:36:17 -0700671 get_sdr::body::set_id_type(0b00, body); // 00 = unicode
Emily Shafferbbef71c2017-05-08 16:36:17 -0700672 }
673
Tom Joseph96423912018-01-25 00:14:34 +0530674 /* ID string */
675 auto id_string = info->sensorNameFunc(*info);
676
677 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
678 {
679 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH, body);
680 }
681 else
682 {
683 get_sdr::body::set_id_strlen(id_string.length(), body);
684 }
685 strncpy(body->id_string, id_string.c_str(),
686 get_sdr::body::get_id_strlen(body));
687
Emily Shafferbbef71c2017-05-08 16:36:17 -0700688 return IPMI_CC_OK;
689};
690
Ratan Guptae0cc8552018-01-22 14:23:04 +0530691ipmi_ret_t ipmi_fru_get_sdr(ipmi_request_t request, ipmi_response_t response,
692 ipmi_data_len_t data_len)
693{
694 auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request);
695 auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response);
Patrick Venture0b02be92018-08-31 11:55:55 -0700696 get_sdr::SensorDataFruRecord record{};
Ratan Guptae0cc8552018-01-22 14:23:04 +0530697 auto dataLength = 0;
698
699 auto fru = frus.begin();
Patrick Venture0b02be92018-08-31 11:55:55 -0700700 uint8_t fruID{};
Ratan Guptae0cc8552018-01-22 14:23:04 +0530701 auto recordID = get_sdr::request::get_record_id(req);
702
703 fruID = recordID - FRU_RECORD_ID_START;
704 fru = frus.find(fruID);
705 if (fru == frus.end())
706 {
707 return IPMI_CC_SENSOR_INVALID;
708 }
709
710 /* Header */
711 get_sdr::header::set_record_id(recordID, &(record.header));
712 record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1
713 record.header.record_type = get_sdr::SENSOR_DATA_FRU_RECORD;
714 record.header.record_length = sizeof(record.key) + sizeof(record.body);
715
716 /* Key */
717 record.key.fruID = fruID;
718 record.key.accessLun |= IPMI_LOGICAL_FRU;
719 record.key.deviceAddress = BMCSlaveAddress;
720
721 /* Body */
722 record.body.entityID = fru->second[0].entityID;
723 record.body.entityInstance = fru->second[0].entityInstance;
724 record.body.deviceType = fruInventoryDevice;
725 record.body.deviceTypeModifier = IPMIFruInventory;
726
727 /* Device ID string */
Patrick Venture0b02be92018-08-31 11:55:55 -0700728 auto deviceID =
729 fru->second[0].path.substr(fru->second[0].path.find_last_of('/') + 1,
730 fru->second[0].path.length());
Ratan Guptae0cc8552018-01-22 14:23:04 +0530731
732 if (deviceID.length() > get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH)
733 {
734 get_sdr::body::set_device_id_strlen(
Patrick Venture0b02be92018-08-31 11:55:55 -0700735 get_sdr::FRU_RECORD_DEVICE_ID_MAX_LENGTH, &(record.body));
Ratan Guptae0cc8552018-01-22 14:23:04 +0530736 }
737 else
738 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700739 get_sdr::body::set_device_id_strlen(deviceID.length(), &(record.body));
Ratan Guptae0cc8552018-01-22 14:23:04 +0530740 }
741
742 strncpy(record.body.deviceID, deviceID.c_str(),
743 get_sdr::body::get_device_id_strlen(&(record.body)));
744
745 if (++fru == frus.end())
746 {
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800747 // we have reached till end of fru, so assign the next record id to
748 // 512(Max fru ID = 511) + Entity Record ID(may start with 0).
Patrick Venture83a0b842019-07-19 18:37:15 -0700749 const auto& entityRecords = getIpmiEntityRecords();
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800750 auto next_record_id =
Patrick Venture83a0b842019-07-19 18:37:15 -0700751 (entityRecords.size())
752 ? entityRecords.begin()->first + ENTITY_RECORD_ID_START
753 : END_OF_RECORD;
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800754 get_sdr::response::set_next_record_id(next_record_id, resp);
755 }
756 else
757 {
758 get_sdr::response::set_next_record_id(
759 (FRU_RECORD_ID_START + fru->first), resp);
760 }
761
762 // Check for invalid offset size
763 if (req->offset > sizeof(record))
764 {
765 return IPMI_CC_PARM_OUT_OF_RANGE;
766 }
767
768 dataLength = std::min(static_cast<size_t>(req->bytes_to_read),
769 sizeof(record) - req->offset);
770
771 std::memcpy(resp->record_data,
772 reinterpret_cast<uint8_t*>(&record) + req->offset, dataLength);
773
774 *data_len = dataLength;
775 *data_len += 2; // additional 2 bytes for next record ID
776
777 return IPMI_CC_OK;
778}
779
780ipmi_ret_t ipmi_entity_get_sdr(ipmi_request_t request, ipmi_response_t response,
781 ipmi_data_len_t data_len)
782{
783 auto req = reinterpret_cast<get_sdr::GetSdrReq*>(request);
784 auto resp = reinterpret_cast<get_sdr::GetSdrResp*>(response);
785 get_sdr::SensorDataEntityRecord record{};
786 auto dataLength = 0;
787
Patrick Venture83a0b842019-07-19 18:37:15 -0700788 const auto& entityRecords = getIpmiEntityRecords();
789 auto entity = entityRecords.begin();
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800790 uint8_t entityRecordID;
791 auto recordID = get_sdr::request::get_record_id(req);
792
793 entityRecordID = recordID - ENTITY_RECORD_ID_START;
Patrick Venture83a0b842019-07-19 18:37:15 -0700794 entity = entityRecords.find(entityRecordID);
795 if (entity == entityRecords.end())
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800796 {
797 return IPMI_CC_SENSOR_INVALID;
798 }
799
800 /* Header */
801 get_sdr::header::set_record_id(recordID, &(record.header));
802 record.header.sdr_version = SDR_VERSION; // Based on IPMI Spec v2.0 rev 1.1
803 record.header.record_type = get_sdr::SENSOR_DATA_ENTITY_RECORD;
804 record.header.record_length = sizeof(record.key) + sizeof(record.body);
805
806 /* Key */
807 record.key.containerEntityId = entity->second.containerEntityId;
808 record.key.containerEntityInstance = entity->second.containerEntityInstance;
809 get_sdr::key::set_flags(entity->second.isList, entity->second.isLinked,
810 &(record.key));
811 record.key.entityId1 = entity->second.containedEntities[0].first;
812 record.key.entityInstance1 = entity->second.containedEntities[0].second;
813
814 /* Body */
815 record.body.entityId2 = entity->second.containedEntities[1].first;
816 record.body.entityInstance2 = entity->second.containedEntities[1].second;
817 record.body.entityId3 = entity->second.containedEntities[2].first;
818 record.body.entityInstance3 = entity->second.containedEntities[2].second;
819 record.body.entityId4 = entity->second.containedEntities[3].first;
820 record.body.entityInstance4 = entity->second.containedEntities[3].second;
821
Patrick Venture83a0b842019-07-19 18:37:15 -0700822 if (++entity == entityRecords.end())
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800823 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700824 get_sdr::response::set_next_record_id(END_OF_RECORD,
825 resp); // last record
Ratan Guptae0cc8552018-01-22 14:23:04 +0530826 }
827 else
828 {
829 get_sdr::response::set_next_record_id(
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800830 (ENTITY_RECORD_ID_START + entity->first), resp);
Ratan Guptae0cc8552018-01-22 14:23:04 +0530831 }
832
Emily Shaffer0fbdbce2018-09-27 09:30:41 -0700833 // Check for invalid offset size
834 if (req->offset > sizeof(record))
Ratan Guptae0cc8552018-01-22 14:23:04 +0530835 {
Emily Shaffer0fbdbce2018-09-27 09:30:41 -0700836 return IPMI_CC_PARM_OUT_OF_RANGE;
Ratan Guptae0cc8552018-01-22 14:23:04 +0530837 }
838
Emily Shaffer0fbdbce2018-09-27 09:30:41 -0700839 dataLength = std::min(static_cast<size_t>(req->bytes_to_read),
840 sizeof(record) - req->offset);
Ratan Guptae0cc8552018-01-22 14:23:04 +0530841
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700842 std::memcpy(resp->record_data,
Jason M. Bills1cd85962018-10-05 12:04:01 -0700843 reinterpret_cast<uint8_t*>(&record) + req->offset, dataLength);
Ratan Guptae0cc8552018-01-22 14:23:04 +0530844
845 *data_len = dataLength;
846 *data_len += 2; // additional 2 bytes for next record ID
847
848 return IPMI_CC_OK;
849}
850
Emily Shafferbbef71c2017-05-08 16:36:17 -0700851ipmi_ret_t ipmi_sen_get_sdr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
852 ipmi_request_t request, ipmi_response_t response,
853 ipmi_data_len_t data_len, ipmi_context_t context)
854{
855 ipmi_ret_t ret = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700856 get_sdr::GetSdrReq* req = (get_sdr::GetSdrReq*)request;
857 get_sdr::GetSdrResp* resp = (get_sdr::GetSdrResp*)response;
Emily Shafferbbef71c2017-05-08 16:36:17 -0700858 get_sdr::SensorDataFullRecord record = {0};
859 if (req != NULL)
860 {
861 // Note: we use an iterator so we can provide the next ID at the end of
862 // the call.
863 auto sensor = sensors.begin();
Ratan Guptae0cc8552018-01-22 14:23:04 +0530864 auto recordID = get_sdr::request::get_record_id(req);
Emily Shafferbbef71c2017-05-08 16:36:17 -0700865
866 // At the beginning of a scan, the host side will send us id=0.
Ratan Guptae0cc8552018-01-22 14:23:04 +0530867 if (recordID != 0)
Emily Shafferbbef71c2017-05-08 16:36:17 -0700868 {
Jaghathiswari Rankappagounder Natarajan9c118942019-02-12 13:22:55 -0800869 // recordID 0 to 255 means it is a FULL record.
870 // recordID 256 to 511 means it is a FRU record.
871 // recordID greater then 511 means it is a Entity Association
872 // record. Currently we are supporting three record types: FULL
873 // record, FRU record and Enttiy Association record.
874 if (recordID >= ENTITY_RECORD_ID_START)
875 {
876 return ipmi_entity_get_sdr(request, response, data_len);
877 }
878 else if (recordID >= FRU_RECORD_ID_START &&
879 recordID < ENTITY_RECORD_ID_START)
Ratan Guptae0cc8552018-01-22 14:23:04 +0530880 {
881 return ipmi_fru_get_sdr(request, response, data_len);
882 }
883 else
884 {
885 sensor = sensors.find(recordID);
886 if (sensor == sensors.end())
887 {
888 return IPMI_CC_SENSOR_INVALID;
889 }
Emily Shafferbbef71c2017-05-08 16:36:17 -0700890 }
891 }
892
893 uint8_t sensor_id = sensor->first;
894
895 /* Header */
896 get_sdr::header::set_record_id(sensor_id, &(record.header));
897 record.header.sdr_version = 0x51; // Based on IPMI Spec v2.0 rev 1.1
898 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
899 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord);
900
901 /* Key */
Tom Joseph96423912018-01-25 00:14:34 +0530902 get_sdr::key::set_owner_id_bmc(&(record.key));
Emily Shafferbbef71c2017-05-08 16:36:17 -0700903 record.key.sensor_number = sensor_id;
904
905 /* Body */
Tom Joseph96423912018-01-25 00:14:34 +0530906 record.body.entity_id = sensor->second.entityType;
Emily Shafferbbef71c2017-05-08 16:36:17 -0700907 record.body.sensor_type = sensor->second.sensorType;
908 record.body.event_reading_type = sensor->second.sensorReadingType;
Tom Joseph96423912018-01-25 00:14:34 +0530909 record.body.entity_instance = sensor->second.instance;
Jaghathiswari Rankappagounder Natarajan0780df12019-02-06 15:29:24 -0800910 if (ipmi::sensor::Mutability::Write ==
911 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
912 {
913 get_sdr::body::init_settable_state(true, &(record.body));
914 }
Emily Shafferbbef71c2017-05-08 16:36:17 -0700915
916 // Set the type-specific details given the DBus interface
917 ret = populate_record_from_dbus(&(record.body), &(sensor->second),
918 data_len);
919
920 if (++sensor == sensors.end())
921 {
Ratan Guptae0cc8552018-01-22 14:23:04 +0530922 // we have reached till end of sensor, so assign the next record id
923 // to 256(Max Sensor ID = 255) + FRU ID(may start with 0).
Patrick Venture0b02be92018-08-31 11:55:55 -0700924 auto next_record_id =
925 (frus.size()) ? frus.begin()->first + FRU_RECORD_ID_START
926 : END_OF_RECORD;
Ratan Guptae0cc8552018-01-22 14:23:04 +0530927
928 get_sdr::response::set_next_record_id(next_record_id, resp);
Emily Shafferbbef71c2017-05-08 16:36:17 -0700929 }
930 else
931 {
932 get_sdr::response::set_next_record_id(sensor->first, resp);
933 }
934
Emily Shaffer6c9ee512018-09-27 11:04:36 -0700935 if (req->offset > sizeof(record))
936 {
937 return IPMI_CC_PARM_OUT_OF_RANGE;
938 }
939
940 // data_len will ultimately be the size of the record, plus
941 // the size of the next record ID:
942 *data_len = std::min(static_cast<size_t>(req->bytes_to_read),
943 sizeof(record) - req->offset);
944
945 std::memcpy(resp->record_data,
946 reinterpret_cast<uint8_t*>(&record) + req->offset,
947 *data_len);
948
949 // data_len should include the LSB and MSB:
Jason M. Bills1cd85962018-10-05 12:04:01 -0700950 *data_len +=
951 sizeof(resp->next_record_id_lsb) + sizeof(resp->next_record_id_msb);
Emily Shafferbbef71c2017-05-08 16:36:17 -0700952 }
953
954 return ret;
955}
956
Jia, Chunhui3342a8e2018-12-29 13:32:26 +0800957static bool isFromSystemChannel()
958{
959 // TODO we could not figure out where the request is from based on IPMI
960 // command handler parameters. because of it, we can not differentiate
961 // request from SMS/SMM or IPMB channel
962 return true;
963}
964
965ipmi_ret_t ipmicmdPlatformEvent(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
966 ipmi_request_t request,
967 ipmi_response_t response,
968 ipmi_data_len_t dataLen, ipmi_context_t context)
969{
970 uint16_t generatorID;
971 size_t count;
972 bool assert = true;
973 std::string sensorPath;
974 size_t paraLen = *dataLen;
975 PlatformEventRequest* req;
976 *dataLen = 0;
977
978 if ((paraLen < selSystemEventSizeWith1Bytes) ||
979 (paraLen > selSystemEventSizeWith3Bytes))
980 {
981 return IPMI_CC_REQ_DATA_LEN_INVALID;
982 }
983
984 if (isFromSystemChannel())
985 { // first byte for SYSTEM Interface is Generator ID
986 // +1 to get common struct
987 req = reinterpret_cast<PlatformEventRequest*>((uint8_t*)request + 1);
988 // Capture the generator ID
989 generatorID = *reinterpret_cast<uint8_t*>(request);
990 // Platform Event usually comes from other firmware, like BIOS.
991 // Unlike BMC sensor, it does not have BMC DBUS sensor path.
992 sensorPath = "System";
993 }
994 else
995 {
996 req = reinterpret_cast<PlatformEventRequest*>(request);
997 // TODO GenratorID for IPMB is combination of RqSA and RqLUN
998 generatorID = 0xff;
999 sensorPath = "IPMB";
1000 }
1001 // Content of event data field depends on sensor class.
1002 // When data0 bit[5:4] is non-zero, valid data counts is 3.
1003 // When data0 bit[7:6] is non-zero, valid data counts is 2.
1004 if (((req->data[0] & byte3EnableMask) != 0 &&
1005 paraLen < selSystemEventSizeWith3Bytes) ||
1006 ((req->data[0] & byte2EnableMask) != 0 &&
1007 paraLen < selSystemEventSizeWith2Bytes))
1008 {
1009 return IPMI_CC_REQ_DATA_LEN_INVALID;
1010 }
1011
1012 // Count bytes of Event Data
1013 if ((req->data[0] & byte3EnableMask) != 0)
1014 {
1015 count = 3;
1016 }
1017 else if ((req->data[0] & byte2EnableMask) != 0)
1018 {
1019 count = 2;
1020 }
1021 else
1022 {
1023 count = 1;
1024 }
1025 assert = req->eventDirectionType & directionMask ? false : true;
1026 std::vector<uint8_t> eventData(req->data, req->data + count);
1027
1028 sdbusplus::bus::bus dbus(bus);
1029 std::string service =
1030 ipmi::getService(dbus, ipmiSELAddInterface, ipmiSELPath);
1031 sdbusplus::message::message writeSEL = dbus.new_method_call(
1032 service.c_str(), ipmiSELPath, ipmiSELAddInterface, "IpmiSelAdd");
1033 writeSEL.append(ipmiSELAddMessage, sensorPath, eventData, assert,
1034 generatorID);
1035 try
1036 {
1037 dbus.call(writeSEL);
1038 }
1039 catch (sdbusplus::exception_t& e)
1040 {
1041 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1042 return IPMI_CC_UNSPECIFIED_ERROR;
1043 }
1044 return IPMI_CC_OK;
1045}
1046
Chris Austenac4604a2015-10-13 12:43:27 -05001047void register_netfn_sen_functions()
1048{
Tom05732372016-09-06 17:21:23 +05301049 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001050 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1051 ipmi_sen_wildcard, PRIVILEGE_USER);
Chris Austenac4604a2015-10-13 12:43:27 -05001052
Jia, Chunhui3342a8e2018-12-29 13:32:26 +08001053 // <Platform Event Message>
1054 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_PLATFORM_EVENT, nullptr,
1055 ipmicmdPlatformEvent, PRIVILEGE_OPERATOR);
Tom05732372016-09-06 17:21:23 +05301056 // <Get Sensor Type>
Patrick Venture0b02be92018-08-31 11:55:55 -07001057 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_TYPE, nullptr,
1058 ipmi_sen_get_sensor_type, PRIVILEGE_USER);
Chris Austenac4604a2015-10-13 12:43:27 -05001059
Tom05732372016-09-06 17:21:23 +05301060 // <Set Sensor Reading and Event Status>
Patrick Venture0b02be92018-08-31 11:55:55 -07001061 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR, nullptr,
1062 ipmi_sen_set_sensor, PRIVILEGE_OPERATOR);
Chris Austen8a45e7c2015-10-15 00:31:46 -05001063
Tom05732372016-09-06 17:21:23 +05301064 // <Get Sensor Reading>
Patrick Venture0b02be92018-08-31 11:55:55 -07001065 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING, nullptr,
1066 ipmi_sen_get_sensor_reading, PRIVILEGE_USER);
Emily Shaffera344afc2017-04-13 15:09:39 -07001067
Tom Joseph5ca50952018-02-22 00:33:38 +05301068 // <Reserve Device SDR Repository>
jayaprakash Mutyalad9578232019-05-13 20:22:50 +00001069 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1070 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
1071 ipmi::Privilege::User, ipmiSensorReserveSdr);
Chris Austen10ccc0f2015-12-10 18:27:04 -06001072
Tom Joseph5ca50952018-02-22 00:33:38 +05301073 // <Get Device SDR Info>
jayaprakash Mutyalad9578232019-05-13 20:22:50 +00001074 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1075 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1076 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
Emily Shafferbbef71c2017-05-08 16:36:17 -07001077
Tom Joseph5ca50952018-02-22 00:33:38 +05301078 // <Get Device SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -07001079 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_DEVICE_SDR, nullptr,
1080 ipmi_sen_get_sdr, PRIVILEGE_USER);
Emily Shafferbbef71c2017-05-08 16:36:17 -07001081
Dhruvaraj Subhashchandran5c0beec2018-01-23 04:47:06 -06001082 // <Get Sensor Thresholds>
1083 ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_THRESHOLDS,
1084 nullptr, ipmi_sen_get_sensor_thresholds,
1085 PRIVILEGE_USER);
1086
Chris Austenac4604a2015-10-13 12:43:27 -05001087 return;
1088}