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