blob: 43c27f8a195fad01d4ae543306d1f2e11160c3ae [file] [log] [blame]
Tom Josephbe5eaa12017-07-12 19:54:44 +05301#include "dcmihandler.hpp"
Patrick Williams37af7332016-09-02 21:21:42 -05002#include "host-ipmid/ipmid-api.h"
Tom Josephbe5eaa12017-07-12 19:54:44 +05303#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler50c0c8f2017-07-11 16:18:51 -05004#include <phosphor-logging/log.hpp>
5#include <sdbusplus/bus.hpp>
6#include "utils.hpp"
Chris Austen1810bec2015-10-13 12:12:39 -05007#include <stdio.h>
8#include <string.h>
9#include <stdint.h>
Tom Josephbe5eaa12017-07-12 19:54:44 +053010#include "xyz/openbmc_project/Common/error.hpp"
11
12using namespace phosphor::logging;
13using InternalFailure =
14 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050015
16void register_netfn_dcmi_functions() __attribute__((constructor));
17
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050018constexpr auto PCAP_SETTINGS_SERVICE = "xyz.openbmc_project.Settings";
19constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
20constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
21
22constexpr auto POWER_CAP_PROP = "PowerCap";
23constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
24
25using namespace phosphor::logging;
26
27uint32_t getPcap(sdbusplus::bus::bus& bus)
28{
29 auto settingService = ipmi::getService(bus,
30 PCAP_PATH,PCAP_SETTINGS_SERVICE);
31
32 auto method = bus.new_method_call(settingService.c_str(),
33 PCAP_PATH,
34 "org.freedesktop.DBus.Properties",
35 "Get");
36
37 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
38 auto reply = bus.call(method);
39
40 if (reply.is_method_error())
41 {
42 log<level::ERR>("Error in getPcap prop");
43 // TODO openbmc/openbmc#851 - Once available, throw returned error
44 // and return IPMI_CC_UNSPECIFIED_ERROR to caller
45 return 0;
46 }
47 sdbusplus::message::variant<uint32_t> pcap;
48 reply.read(pcap);
49
50 return sdbusplus::message::variant_ns::get<uint32_t>(pcap);
51}
52
53bool getPcapEnabled(sdbusplus::bus::bus& bus)
54{
55 auto settingService = ipmi::getService(bus,
56 PCAP_PATH,PCAP_SETTINGS_SERVICE);
57
58 auto method = bus.new_method_call(settingService.c_str(),
59 PCAP_PATH,
60 "org.freedesktop.DBus.Properties",
61 "Get");
62
63 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
64 auto reply = bus.call(method);
65
66 if (reply.is_method_error())
67 {
68 log<level::ERR>("Error in getPcapEnabled prop");
69 // TODO openbmc/openbmc#851 - Once available, throw returned error
70 // and return IPMI_CC_UNSPECIFIED_ERROR to caller
71 return false;
72 }
73 sdbusplus::message::variant<bool> pcapEnabled;
74 reply.read(pcapEnabled);
75
76 return sdbusplus::message::variant_ns::get<bool>(pcapEnabled);
77}
Chris Austen1810bec2015-10-13 12:12:39 -050078
79ipmi_ret_t ipmi_dcmi_get_power_limit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
80 ipmi_request_t request, ipmi_response_t response,
81 ipmi_data_len_t data_len, ipmi_context_t context)
82{
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050083 // Default to no power cap enabled
Chris Austen1810bec2015-10-13 12:12:39 -050084 ipmi_ret_t rc = IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
85
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050086 // Get our sdbus object
87 sd_bus *bus = ipmid_get_sd_bus_connection();
88 sdbusplus::bus::bus sdbus {bus};
89
90 // Read our power cap settings
91 auto pcap = getPcap(sdbus);
92 auto pcapEnable = getPcapEnabled(sdbus);
93 if(pcapEnable)
94 {
95 // indicate power cap enabled with success return code
96 rc = IPMI_CC_OK;
97 }
98
99 uint8_t pcapBytes[2] = {0};
100 pcapBytes[1] = (pcap & 0xFF00) >> 8;
101 pcapBytes[0] = pcap & 0xFF;
102 // dcmi-v1-5-rev-spec.pdf 6.6.2.
103 uint8_t data_response[] = { 0xDC, 0x00, 0x00, 0x01, pcapBytes[0],
104 pcapBytes[1], 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x01};
Chris Austen1810bec2015-10-13 12:12:39 -0500106
107
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500108 log<level::INFO>("IPMI DCMI POWER CAP INFO",
109 entry("DCMI_PCAP=%u",pcap),
110 entry("DCMI_PCAP_ENABLE=%u",pcapEnable));
Chris Austen1810bec2015-10-13 12:12:39 -0500111
112 memcpy(response, data_response, sizeof(data_response));
113 *data_len = sizeof(data_response);
114
115 return rc;
116}
117
Tom Josephbe5eaa12017-07-12 19:54:44 +0530118namespace dcmi
119{
120
121void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
122{
123 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
124 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
125 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
126 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
127
128 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
129 auto depth = 0;
130
131 auto mapperCall = bus.new_method_call(mapperBusName,
132 mapperObjPath,
133 mapperIface,
134 "GetSubTree");
135
136 mapperCall.append(inventoryRoot);
137 mapperCall.append(depth);
138 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
139
140 auto mapperReply = bus.call(mapperCall);
141 if (mapperReply.is_method_error())
142 {
143 log<level::ERR>("Error in mapper call");
144 elog<InternalFailure>();
145 }
146
147 mapperReply.read(objectTree);
148
149 if (objectTree.empty())
150 {
151 log<level::ERR>("AssetTag property is not populated");
152 elog<InternalFailure>();
153 }
154}
155
156std::string readAssetTag()
157{
158 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
159 dcmi::assettag::ObjectTree objectTree;
160
161 // Read the object tree with the inventory root to figure out the object
162 // that has implemented the Asset tag interface.
163 readAssetTagObjectTree(objectTree);
164
165 auto method = bus.new_method_call(
166 (objectTree.begin()->second.begin()->first).c_str(),
167 (objectTree.begin()->first).c_str(),
168 dcmi::propIntf,
169 "Get");
170 method.append(dcmi::assetTagIntf);
171 method.append(dcmi::assetTagProp);
172
173 auto reply = bus.call(method);
174 if (reply.is_method_error())
175 {
176 log<level::ERR>("Error in reading asset tag");
177 elog<InternalFailure>();
178 }
179
180 sdbusplus::message::variant<std::string> assetTag;
181 reply.read(assetTag);
182
183 return assetTag.get<std::string>();
184}
185
Tom Josephbe5b9892017-07-15 00:55:23 +0530186void writeAssetTag(const std::string& assetTag)
187{
188 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
189 dcmi::assettag::ObjectTree objectTree;
190
191 // Read the object tree with the inventory root to figure out the object
192 // that has implemented the Asset tag interface.
193 readAssetTagObjectTree(objectTree);
194
195 auto method = bus.new_method_call(
196 (objectTree.begin()->second.begin()->first).c_str(),
197 (objectTree.begin()->first).c_str(),
198 dcmi::propIntf,
199 "Set");
200 method.append(dcmi::assetTagIntf);
201 method.append(dcmi::assetTagProp);
202 method.append(sdbusplus::message::variant<std::string>(assetTag));
203
204 auto reply = bus.call(method);
205 if (reply.is_method_error())
206 {
207 log<level::ERR>("Error in writing asset tag");
208 elog<InternalFailure>();
209 }
210}
211
Tom Josephbe5eaa12017-07-12 19:54:44 +0530212} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500213
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530214ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
215 ipmi_request_t request, ipmi_response_t response,
216 ipmi_data_len_t data_len, ipmi_context_t context)
217{
218 auto requestData = reinterpret_cast<const dcmi::GetAssetTagRequest*>
219 (request);
220 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
221 auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
222 (outPayload.data());
223
224 if (requestData->groupID != dcmi::groupExtId)
225 {
226 *data_len = 0;
227 return IPMI_CC_INVALID_FIELD_REQUEST;
228 }
229
230 // Verify offset to read and number of bytes to read are not exceeding the
231 // range.
232 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
233 (requestData->bytes > dcmi::maxBytes) ||
234 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
235 {
236 *data_len = 0;
237 return IPMI_CC_PARM_OUT_OF_RANGE;
238 }
239
240 std::string assetTag;
241
242 try
243 {
244 assetTag = dcmi::readAssetTag();
245 }
246 catch (InternalFailure& e)
247 {
248 *data_len = 0;
249 return IPMI_CC_UNSPECIFIED_ERROR;
250 }
251
252 responseData->groupID = dcmi::groupExtId;
253
254 // Return if the asset tag is not populated.
255 if (!assetTag.size())
256 {
257 responseData->tagLength = 0;
258 memcpy(response, outPayload.data(), outPayload.size());
259 *data_len = outPayload.size();
260 return IPMI_CC_OK;
261 }
262
263 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
264 // Get Asset Tag command.
265 if (assetTag.size() > dcmi::assetTagMaxSize)
266 {
267 assetTag.resize(dcmi::assetTagMaxSize);
268 }
269
270 // If the requested offset is beyond the asset tag size.
271 if (requestData->offset >= assetTag.size())
272 {
273 *data_len = 0;
274 return IPMI_CC_PARM_OUT_OF_RANGE;
275 }
276
277 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
278
279 responseData->tagLength = assetTag.size();
280
281 memcpy(response, outPayload.data(), outPayload.size());
282 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
283 returnData.data(), returnData.size());
284 *data_len = outPayload.size() + returnData.size();
285
286 return IPMI_CC_OK;
287}
288
Tom Joseph545dd232017-07-12 20:20:49 +0530289ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
290 ipmi_request_t request, ipmi_response_t response,
291 ipmi_data_len_t data_len, ipmi_context_t context)
292{
293 auto requestData = reinterpret_cast<const dcmi::SetAssetTagRequest*>
294 (request);
295 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
296 auto responseData = reinterpret_cast<dcmi::SetAssetTagResponse*>
297 (outPayload.data());
298
299 if (requestData->groupID != dcmi::groupExtId)
300 {
301 *data_len = 0;
302 return IPMI_CC_INVALID_FIELD_REQUEST;
303 }
304
305 // Verify offset to read and number of bytes to read are not exceeding the
306 // range.
307 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
308 (requestData->bytes > dcmi::maxBytes) ||
309 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
310 {
311 *data_len = 0;
312 return IPMI_CC_PARM_OUT_OF_RANGE;
313 }
314
315 std::string assetTag;
316
317 try
318 {
319 assetTag = dcmi::readAssetTag();
320
321 if (requestData->offset > assetTag.size())
322 {
323 *data_len = 0;
324 return IPMI_CC_PARM_OUT_OF_RANGE;
325 }
326
327 assetTag.replace(requestData->offset,
328 assetTag.size() - requestData->offset,
329 static_cast<const char*>(request) +
330 sizeof(dcmi::SetAssetTagRequest),
331 requestData->bytes);
332
333 dcmi::writeAssetTag(assetTag);
334
335 responseData->groupID = dcmi::groupExtId;
336 responseData->tagLength = assetTag.size();
337 memcpy(response, outPayload.data(), outPayload.size());
338 *data_len = outPayload.size();
339
340 return IPMI_CC_OK;
341 }
342 catch (InternalFailure& e)
343 {
344 *data_len = 0;
345 return IPMI_CC_UNSPECIFIED_ERROR;
346 }
347}
348
Chris Austen1810bec2015-10-13 12:12:39 -0500349void register_netfn_dcmi_functions()
350{
Tom05732372016-09-06 17:21:23 +0530351 // <Get Power Limit>
Chris Austen1810bec2015-10-13 12:12:39 -0500352 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER);
Tom05732372016-09-06 17:21:23 +0530353 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER, NULL, ipmi_dcmi_get_power_limit,
354 PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530355
356 // <Get Asset Tag>
357 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG);
358 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG, NULL, getAssetTag,
359 PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +0530360
361 // <Set Asset Tag>
362 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG);
363 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG, NULL, setAssetTag,
364 PRIVILEGE_OPERATOR);
Chris Austen1810bec2015-10-13 12:12:39 -0500365 return;
366}
Tom05732372016-09-06 17:21:23 +0530367// 956379