blob: 4c4f8b7987d101476dd0e7424dfc60da5ad493ec [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>
Chris Austen1810bec2015-10-13 12:12:39 -05004#include <stdio.h>
5#include <string.h>
6#include <stdint.h>
Tom Josephbe5eaa12017-07-12 19:54:44 +05307#include "utils.hpp"
8#include "xyz/openbmc_project/Common/error.hpp"
9
10using namespace phosphor::logging;
11using InternalFailure =
12 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Chris Austen1810bec2015-10-13 12:12:39 -050013
14void register_netfn_dcmi_functions() __attribute__((constructor));
15
16
17ipmi_ret_t ipmi_dcmi_get_power_limit(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
18 ipmi_request_t request, ipmi_response_t response,
19 ipmi_data_len_t data_len, ipmi_context_t context)
20{
21 ipmi_ret_t rc = IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT;
22
23 // dcmi-v1-5-rev-spec.pdf 6.6.2.
24 // This is good enough for OpenBMC support for OpenPOWER based systems
25 // TODO research if more is needed
26 uint8_t data_response[] = { 0xDC, 0x00, 0x00, 0x01, 0x00, 0x00,
27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 0x00, 0x01};
29
30
31
32 printf("IPMI DCMI_GET_POWER_LEVEL\n");
33
34 memcpy(response, data_response, sizeof(data_response));
35 *data_len = sizeof(data_response);
36
37 return rc;
38}
39
Tom Josephbe5eaa12017-07-12 19:54:44 +053040namespace dcmi
41{
42
43void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
44{
45 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
46 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
47 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
48 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
49
50 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
51 auto depth = 0;
52
53 auto mapperCall = bus.new_method_call(mapperBusName,
54 mapperObjPath,
55 mapperIface,
56 "GetSubTree");
57
58 mapperCall.append(inventoryRoot);
59 mapperCall.append(depth);
60 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
61
62 auto mapperReply = bus.call(mapperCall);
63 if (mapperReply.is_method_error())
64 {
65 log<level::ERR>("Error in mapper call");
66 elog<InternalFailure>();
67 }
68
69 mapperReply.read(objectTree);
70
71 if (objectTree.empty())
72 {
73 log<level::ERR>("AssetTag property is not populated");
74 elog<InternalFailure>();
75 }
76}
77
78std::string readAssetTag()
79{
80 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
81 dcmi::assettag::ObjectTree objectTree;
82
83 // Read the object tree with the inventory root to figure out the object
84 // that has implemented the Asset tag interface.
85 readAssetTagObjectTree(objectTree);
86
87 auto method = bus.new_method_call(
88 (objectTree.begin()->second.begin()->first).c_str(),
89 (objectTree.begin()->first).c_str(),
90 dcmi::propIntf,
91 "Get");
92 method.append(dcmi::assetTagIntf);
93 method.append(dcmi::assetTagProp);
94
95 auto reply = bus.call(method);
96 if (reply.is_method_error())
97 {
98 log<level::ERR>("Error in reading asset tag");
99 elog<InternalFailure>();
100 }
101
102 sdbusplus::message::variant<std::string> assetTag;
103 reply.read(assetTag);
104
105 return assetTag.get<std::string>();
106}
107
Tom Josephbe5b9892017-07-15 00:55:23 +0530108void writeAssetTag(const std::string& assetTag)
109{
110 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
111 dcmi::assettag::ObjectTree objectTree;
112
113 // Read the object tree with the inventory root to figure out the object
114 // that has implemented the Asset tag interface.
115 readAssetTagObjectTree(objectTree);
116
117 auto method = bus.new_method_call(
118 (objectTree.begin()->second.begin()->first).c_str(),
119 (objectTree.begin()->first).c_str(),
120 dcmi::propIntf,
121 "Set");
122 method.append(dcmi::assetTagIntf);
123 method.append(dcmi::assetTagProp);
124 method.append(sdbusplus::message::variant<std::string>(assetTag));
125
126 auto reply = bus.call(method);
127 if (reply.is_method_error())
128 {
129 log<level::ERR>("Error in writing asset tag");
130 elog<InternalFailure>();
131 }
132}
133
Tom Josephbe5eaa12017-07-12 19:54:44 +0530134} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500135
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530136ipmi_ret_t getAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
137 ipmi_request_t request, ipmi_response_t response,
138 ipmi_data_len_t data_len, ipmi_context_t context)
139{
140 auto requestData = reinterpret_cast<const dcmi::GetAssetTagRequest*>
141 (request);
142 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
143 auto responseData = reinterpret_cast<dcmi::GetAssetTagResponse*>
144 (outPayload.data());
145
146 if (requestData->groupID != dcmi::groupExtId)
147 {
148 *data_len = 0;
149 return IPMI_CC_INVALID_FIELD_REQUEST;
150 }
151
152 // Verify offset to read and number of bytes to read are not exceeding the
153 // range.
154 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
155 (requestData->bytes > dcmi::maxBytes) ||
156 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
157 {
158 *data_len = 0;
159 return IPMI_CC_PARM_OUT_OF_RANGE;
160 }
161
162 std::string assetTag;
163
164 try
165 {
166 assetTag = dcmi::readAssetTag();
167 }
168 catch (InternalFailure& e)
169 {
170 *data_len = 0;
171 return IPMI_CC_UNSPECIFIED_ERROR;
172 }
173
174 responseData->groupID = dcmi::groupExtId;
175
176 // Return if the asset tag is not populated.
177 if (!assetTag.size())
178 {
179 responseData->tagLength = 0;
180 memcpy(response, outPayload.data(), outPayload.size());
181 *data_len = outPayload.size();
182 return IPMI_CC_OK;
183 }
184
185 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
186 // Get Asset Tag command.
187 if (assetTag.size() > dcmi::assetTagMaxSize)
188 {
189 assetTag.resize(dcmi::assetTagMaxSize);
190 }
191
192 // If the requested offset is beyond the asset tag size.
193 if (requestData->offset >= assetTag.size())
194 {
195 *data_len = 0;
196 return IPMI_CC_PARM_OUT_OF_RANGE;
197 }
198
199 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
200
201 responseData->tagLength = assetTag.size();
202
203 memcpy(response, outPayload.data(), outPayload.size());
204 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
205 returnData.data(), returnData.size());
206 *data_len = outPayload.size() + returnData.size();
207
208 return IPMI_CC_OK;
209}
210
Tom Joseph545dd232017-07-12 20:20:49 +0530211ipmi_ret_t setAssetTag(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
212 ipmi_request_t request, ipmi_response_t response,
213 ipmi_data_len_t data_len, ipmi_context_t context)
214{
215 auto requestData = reinterpret_cast<const dcmi::SetAssetTagRequest*>
216 (request);
217 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
218 auto responseData = reinterpret_cast<dcmi::SetAssetTagResponse*>
219 (outPayload.data());
220
221 if (requestData->groupID != dcmi::groupExtId)
222 {
223 *data_len = 0;
224 return IPMI_CC_INVALID_FIELD_REQUEST;
225 }
226
227 // Verify offset to read and number of bytes to read are not exceeding the
228 // range.
229 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
230 (requestData->bytes > dcmi::maxBytes) ||
231 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
232 {
233 *data_len = 0;
234 return IPMI_CC_PARM_OUT_OF_RANGE;
235 }
236
237 std::string assetTag;
238
239 try
240 {
241 assetTag = dcmi::readAssetTag();
242
243 if (requestData->offset > assetTag.size())
244 {
245 *data_len = 0;
246 return IPMI_CC_PARM_OUT_OF_RANGE;
247 }
248
249 assetTag.replace(requestData->offset,
250 assetTag.size() - requestData->offset,
251 static_cast<const char*>(request) +
252 sizeof(dcmi::SetAssetTagRequest),
253 requestData->bytes);
254
255 dcmi::writeAssetTag(assetTag);
256
257 responseData->groupID = dcmi::groupExtId;
258 responseData->tagLength = assetTag.size();
259 memcpy(response, outPayload.data(), outPayload.size());
260 *data_len = outPayload.size();
261
262 return IPMI_CC_OK;
263 }
264 catch (InternalFailure& e)
265 {
266 *data_len = 0;
267 return IPMI_CC_UNSPECIFIED_ERROR;
268 }
269}
270
Chris Austen1810bec2015-10-13 12:12:39 -0500271void register_netfn_dcmi_functions()
272{
Tom05732372016-09-06 17:21:23 +0530273 // <Get Power Limit>
Chris Austen1810bec2015-10-13 12:12:39 -0500274 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER);
Tom05732372016-09-06 17:21:23 +0530275 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_POWER, NULL, ipmi_dcmi_get_power_limit,
276 PRIVILEGE_USER);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530277
278 // <Get Asset Tag>
279 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG);
280 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_GET_ASSET_TAG, NULL, getAssetTag,
281 PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +0530282
283 // <Set Asset Tag>
284 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG);
285 ipmi_register_callback(NETFUN_GRPEXT, IPMI_CMD_DCMI_SET_ASSET_TAG, NULL, setAssetTag,
286 PRIVILEGE_OPERATOR);
Chris Austen1810bec2015-10-13 12:12:39 -0500287 return;
288}
Tom05732372016-09-06 17:21:23 +0530289// 956379