blob: f30481abc7421761e94e888a1e72ba5a952d619f [file] [log] [blame]
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001/*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2018-present Facebook.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "xyz/openbmc_project/Common/error.hpp"
19#include <ipmid/api.h>
20
21#include <array>
22#include <commandutils.hpp>
23#include <cstring>
24#include <iostream>
25#include <oemcommands.hpp>
26#include <phosphor-ipmi-host/utils.hpp>
27#include <phosphor-logging/log.hpp>
28#include <sdbusplus/bus.hpp>
29#include <string>
30#include <vector>
31
32#define SIZE_IANA_ID 3
33
34namespace ipmi
35{
36static void registerOEMFunctions() __attribute__((constructor));
37sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
38static constexpr size_t maxFRUStringLength = 0x3F;
39
40ipmi_ret_t plat_udbg_get_post_desc(uint8_t, uint8_t *, uint8_t, uint8_t *,
41 uint8_t *, uint8_t *);
42ipmi_ret_t plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t *, uint8_t *,
43 uint8_t *);
44ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t *,
45 uint8_t *);
46
47// return code: 0 successful
48int8_t getFruData(std::string &data, std::string &name)
49{
50 std::string objpath = "/xyz/openbmc_project/FruDevice";
51 std::string intf = "xyz.openbmc_project.FruDeviceManager";
52 std::string service = getService(dbus, intf, objpath);
53 ObjectValueTree valueTree = getManagedObjects(dbus, service, "/");
54 if (valueTree.empty())
55 {
56 phosphor::logging::log<phosphor::logging::level::ERR>(
57 "No object implements interface",
58 phosphor::logging::entry("INTF=%s", intf.c_str()));
59 return -1;
60 }
61
62 for (const auto &item : valueTree)
63 {
64 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
65 if (interface == item.second.end())
66 {
67 continue;
68 }
69
70 auto property = interface->second.find(name.c_str());
71 if (property == interface->second.end())
72 {
73 continue;
74 }
75
76 try
77 {
78 Value variant = property->second;
79 std::string &result =
80 sdbusplus::message::variant_ns::get<std::string>(variant);
81 if (result.size() > maxFRUStringLength)
82 {
83 phosphor::logging::log<phosphor::logging::level::ERR>(
84 "FRU serial number exceed maximum length");
85 return -1;
86 }
87 data = result;
88 return 0;
89 }
90 catch (sdbusplus::message::variant_ns::bad_variant_access &e)
91 {
92 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
93 return -1;
94 }
95 }
96 return -1;
97}
98
99typedef struct
100{
101 uint8_t cur_power_state;
102 uint8_t last_power_event;
103 uint8_t misc_power_state;
104 uint8_t front_panel_button_cap_status;
105} ipmi_get_chassis_status_t;
106
107// Todo: Needs to update this as per power policy when integrated
108//----------------------------------------------------------------------
109// Get Chassis Status commands
110//----------------------------------------------------------------------
111ipmi_ret_t ipmiGetChassisStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
112 ipmi_request_t request,
113 ipmi_response_t response,
114 ipmi_data_len_t data_len,
115 ipmi_context_t context)
116{
117 ipmi_get_chassis_status_t chassis_status;
118 uint8_t s = 2;
119
120 *data_len = 4;
121
122 // Current Power State
123 // [7] reserved
124 // [6..5] power restore policy
125 // 00b = chassis stays powered off after AC/mains returns
126 // 01b = after AC returns, power is restored to the state that was
127 // in effect when AC/mains was lost.
128 // 10b = chassis always powers up after AC/mains returns
129 // 11b = unknow
130 // Set to 00b, by observing the hardware behavior.
131 // Do we need to define a dbus property to identify the restore
132 // policy?
133
134 // [4] power control fault
135 // 1b = controller attempted to turn system power on or off, but
136 // system did not enter desired state.
137 // Set to 0b, since We don't support it..
138
139 // [3] power fault
140 // 1b = fault detected in main power subsystem.
141 // set to 0b. for we don't support it.
142
143 // [2] 1b = interlock (chassis is presently shut down because a chassis
144 // panel interlock switch is active). (IPMI 1.5)
145 // set to 0b, for we don't support it.
146
147 // [1] power overload
148 // 1b = system shutdown because of power overload condition.
149 // set to 0b, for we don't support it.
150
151 // [0] power is on
152 // 1b = system power is on
153 // 0b = system power is off(soft-off S4/S5, or mechanical off)
154
155 chassis_status.cur_power_state = ((s & 0x3) << 5) | (1 & 0x1);
156
157 // Last Power Event
158 // [7..5] – reserved
159 // [4] – 1b = last ‘Power is on’ state was entered via IPMI command
160 // [3] – 1b = last power down caused by power fault
161 // [2] – 1b = last power down caused by a power interlock being activated
162 // [1] – 1b = last power down caused by a Power overload
163 // [0] – 1b = AC failed
164 // set to 0x0, for we don't support these fields.
165
166 chassis_status.last_power_event = 0;
167
168 // Misc. Chassis State
169 // [7] – reserved
170 // [6] – 1b = Chassis Identify command and state info supported (Optional)
171 // 0b = Chassis Identify command support unspecified via this command.
172 // (The Get Command Support command , if implemented, would still
173 // indicate support for the Chassis Identify command)
174 // [5..4] – Chassis Identify State. Mandatory when bit[6] =1b, reserved
175 // (return
176 // as 00b) otherwise. Returns the present chassis identify state.
177 // Refer to the Chassis Identify command for more info.
178 // 00b = chassis identify state = Off
179 // 01b = chassis identify state = Temporary(timed) On
180 // 10b = chassis identify state = Indefinite On
181 // 11b = reserved
182 // [3] – 1b = Cooling/fan fault detected
183 // [2] – 1b = Drive Fault
184 // [1] – 1b = Front Panel Lockout active (power off and reset via chassis
185 // push-buttons disabled.)
186 // [0] – 1b = Chassis Intrusion active
187 // set to 0, for we don't support them.
188 chassis_status.misc_power_state = 0x40;
189
190 // Front Panel Button Capabilities and disable/enable status(Optional)
191 // set to 0, for we don't support them.
192 chassis_status.front_panel_button_cap_status = 0;
193
194 // Pack the actual response
195 std::memcpy(response, &chassis_status, *data_len);
196
197 return IPMI_CC_OK;
198}
199
200//----------------------------------------------------------------------
201// Get Debug Frame Info
202//----------------------------------------------------------------------
203ipmi_ret_t ipmiOemDbgGetFrameInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
204 ipmi_request_t request,
205 ipmi_response_t response,
206 ipmi_data_len_t data_len,
207 ipmi_context_t context)
208{
209 uint8_t *req = reinterpret_cast<uint8_t *>(request);
210 uint8_t *res = reinterpret_cast<uint8_t *>(response);
211 uint8_t num_frames = 3;
212
213 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
214 res[SIZE_IANA_ID] = num_frames;
215 *data_len = SIZE_IANA_ID + 1;
216
217 return IPMI_CC_OK;
218}
219
220//----------------------------------------------------------------------
221// Get Debug Updated Frames
222//----------------------------------------------------------------------
223ipmi_ret_t ipmiOemDbgGetUpdFrames(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
224 ipmi_request_t request,
225 ipmi_response_t response,
226 ipmi_data_len_t data_len,
227 ipmi_context_t context)
228{
229 uint8_t *req = reinterpret_cast<uint8_t *>(request);
230 uint8_t *res = reinterpret_cast<uint8_t *>(response);
231 uint8_t num_updates = 3;
232 *data_len = 4;
233
234 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
235 res[SIZE_IANA_ID] = num_updates;
236 *data_len = SIZE_IANA_ID + num_updates + 1;
237 res[SIZE_IANA_ID + 1] = 1; // info page update
238 res[SIZE_IANA_ID + 2] = 2; // cri sel update
239 res[SIZE_IANA_ID + 3] = 3; // cri sensor update
240
241 return IPMI_CC_OK;
242}
243
244//----------------------------------------------------------------------
245// Get Debug POST Description
246//----------------------------------------------------------------------
247ipmi_ret_t ipmiOemDbgGetPostDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
248 ipmi_request_t request,
249 ipmi_response_t response,
250 ipmi_data_len_t data_len,
251 ipmi_context_t context)
252{
253 uint8_t *req = reinterpret_cast<uint8_t *>(request);
254 uint8_t *res = reinterpret_cast<uint8_t *>(response);
255 uint8_t index = 0;
256 uint8_t next = 0;
257 uint8_t end = 0;
258 uint8_t phase = 0;
259 uint8_t count = 0;
260 int ret;
261
262 index = req[3];
263 phase = req[4];
264
265 phosphor::logging::log<phosphor::logging::level::INFO>(
266 "Get POST Description Event");
267
268 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &count, &res[8]);
269 if (ret)
270 {
271 memcpy(res, req, SIZE_IANA_ID); // IANA ID
272 *data_len = SIZE_IANA_ID;
273 return IPMI_CC_UNSPECIFIED_ERROR;
274 }
275
276 memcpy(res, req, SIZE_IANA_ID); // IANA ID
277 res[3] = index;
278 res[4] = next;
279 res[5] = phase;
280 res[6] = end;
281 res[7] = count;
282 *data_len = SIZE_IANA_ID + 5 + count;
283
284 return IPMI_CC_OK;
285}
286
287//----------------------------------------------------------------------
288// Get Debug GPIO Description
289//----------------------------------------------------------------------
290ipmi_ret_t ipmiOemDbgGetGpioDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
291 ipmi_request_t request,
292 ipmi_response_t response,
293 ipmi_data_len_t data_len,
294 ipmi_context_t context)
295{
296 uint8_t *req = reinterpret_cast<uint8_t *>(request);
297 uint8_t *res = reinterpret_cast<uint8_t *>(response);
298
299 phosphor::logging::log<phosphor::logging::level::INFO>(
300 "Get GPIO Description Event");
301
302 std::memcpy(res, req, SIZE_IANA_ID + 1); // IANA ID
303 *data_len = SIZE_IANA_ID + 1;
304
305 return IPMI_CC_OK;
306}
307
308//----------------------------------------------------------------------
309// Get Debug Frame Data
310//----------------------------------------------------------------------
311ipmi_ret_t ipmiOemDbgGetFrameData(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
312 ipmi_request_t request,
313 ipmi_response_t response,
314 ipmi_data_len_t data_len,
315 ipmi_context_t context)
316{
317 uint8_t *req = reinterpret_cast<uint8_t *>(request);
318 uint8_t *res = reinterpret_cast<uint8_t *>(response);
319 uint8_t frame;
320 uint8_t page;
321 uint8_t next;
322 uint8_t count;
323 int ret;
324
325 frame = req[3];
326 page = req[4];
327 int fr = frame;
328 int pg = page;
329
330 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
331 if (ret)
332 {
333 memcpy(res, req, SIZE_IANA_ID); // IANA ID
334 *data_len = SIZE_IANA_ID;
335 return IPMI_CC_UNSPECIFIED_ERROR;
336 }
337
338 memcpy(res, req, SIZE_IANA_ID); // IANA ID
339 res[3] = frame;
340 res[4] = page;
341 res[5] = next;
342 res[6] = count;
343 *data_len = SIZE_IANA_ID + 4 + count;
344
345 return IPMI_CC_OK;
346}
347
348//----------------------------------------------------------------------
349// Get Debug Control Panel
350//----------------------------------------------------------------------
351ipmi_ret_t ipmiOemDbgGetCtrlPanel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
352 ipmi_request_t request,
353 ipmi_response_t response,
354 ipmi_data_len_t data_len,
355 ipmi_context_t context)
356{
357 uint8_t *req = reinterpret_cast<uint8_t *>(request);
358 uint8_t *res = reinterpret_cast<uint8_t *>(response);
359
360 uint8_t panel;
361 uint8_t operation;
362 uint8_t item;
363 uint8_t count;
364 ipmi_ret_t ret;
365
366 panel = req[3];
367 operation = req[4];
368 item = req[5];
369
370 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
371
372 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
373 *data_len = SIZE_IANA_ID + count;
374
375 return ret;
376}
377
378// Todo: Need to implement all below functions for oem commands
379//----------------------------------------------------------------------
380// Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
381//----------------------------------------------------------------------
382ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
383 ipmi_request_t request, ipmi_response_t response,
384 ipmi_data_len_t data_len, ipmi_context_t context)
385{
386 uint8_t *req = reinterpret_cast<uint8_t *>(request);
387 uint8_t *res = reinterpret_cast<uint8_t *>(response);
388
389 std::memcpy(res, req, SIZE_IANA_ID + 1); // IANA ID
390 *data_len = SIZE_IANA_ID + 1;
391 *data_len = 0;
392
393 return IPMI_CC_OK;
394}
395
396//----------------------------------------------------------------------
397// Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
398//----------------------------------------------------------------------
399ipmi_ret_t ipmiOemGetBootOrder(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
400 ipmi_request_t request, ipmi_response_t response,
401 ipmi_data_len_t data_len, ipmi_context_t context)
402{
403 uint8_t *req = reinterpret_cast<uint8_t *>(request);
404 uint8_t *res = reinterpret_cast<uint8_t *>(response);
405
406 *res++ = 0x01;
407 *res++ = 0x00;
408 *res++ = 0x09;
409 *res++ = 0x02;
410 *res++ = 0x03;
411 *res++ = 0xff;
412 *data_len = 6;
413
414 return IPMI_CC_OK;
415}
416
417//----------------------------------------------------------------------
418// Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
419//----------------------------------------------------------------------
420ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
421 ipmi_request_t request,
422 ipmi_response_t response,
423 ipmi_data_len_t data_len,
424 ipmi_context_t context)
425{
426 uint8_t *req = reinterpret_cast<uint8_t *>(request);
427 uint8_t *res = reinterpret_cast<uint8_t *>(response);
428
429 *data_len = 0;
430
431 return IPMI_CC_OK;
432}
433
434//----------------------------------------------------------------------
435// Set POST start (CMD_OEM_SET_POST_START)
436//----------------------------------------------------------------------
437ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
438 ipmi_request_t request, ipmi_response_t response,
439 ipmi_data_len_t data_len, ipmi_context_t context)
440{
441 uint8_t *req = reinterpret_cast<uint8_t *>(request);
442 uint8_t *res = reinterpret_cast<uint8_t *>(response);
443
444 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
445
446 *data_len = 0;
447 return IPMI_CC_OK;
448}
449
450//----------------------------------------------------------------------
451// Set POST End (CMD_OEM_SET_POST_END)
452//----------------------------------------------------------------------
453ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
454 ipmi_request_t request, ipmi_response_t response,
455 ipmi_data_len_t data_len, ipmi_context_t context)
456{
457 uint8_t *req = reinterpret_cast<uint8_t *>(request);
458 uint8_t *res = reinterpret_cast<uint8_t *>(response);
459
460 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
461
462 *data_len = 0;
463 return IPMI_CC_OK;
464}
465
466//----------------------------------------------------------------------
467// Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
468//----------------------------------------------------------------------
469ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
470 ipmi_request_t request,
471 ipmi_response_t response,
472 ipmi_data_len_t data_len,
473 ipmi_context_t context)
474{
475 uint8_t *req = reinterpret_cast<uint8_t *>(request);
476 uint8_t *res = reinterpret_cast<uint8_t *>(response);
477
478 *data_len = 0;
479 return IPMI_CC_OK;
480}
481
482//----------------------------------------------------------------------
483// Set PPR (CMD_OEM_SET_PPR)
484//----------------------------------------------------------------------
485ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
486 ipmi_request_t request, ipmi_response_t response,
487 ipmi_data_len_t data_len, ipmi_context_t context)
488{
489 uint8_t *req = reinterpret_cast<uint8_t *>(request);
490 uint8_t *res = reinterpret_cast<uint8_t *>(response);
491
492 *data_len = 0;
493 return IPMI_CC_OK;
494}
495
496//----------------------------------------------------------------------
497// Get PPR (CMD_OEM_GET_PPR)
498//----------------------------------------------------------------------
499ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
500 ipmi_request_t request, ipmi_response_t response,
501 ipmi_data_len_t data_len, ipmi_context_t context)
502{
503 uint8_t *req = reinterpret_cast<uint8_t *>(request);
504 uint8_t *res = reinterpret_cast<uint8_t *>(response);
505
506 res[0] = 0x00;
507 *data_len = 1;
508
509 return IPMI_CC_OK;
510}
511
512static void registerOEMFunctions(void)
513{
514 phosphor::logging::log<phosphor::logging::level::INFO>(
515 "Registering OEM commands");
516 ipmiPrintAndRegister(NETFUN_CHASSIS, 1, NULL, ipmiGetChassisStatus,
517 PRIVILEGE_USER); // get chassis status
518 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
519 NULL, ipmiOemDbgGetFrameInfo,
520 PRIVILEGE_USER); // get debug frame info
521 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
522 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
523 ipmiOemDbgGetUpdFrames,
524 PRIVILEGE_USER); // get debug updated frames
525 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
526 NULL, ipmiOemDbgGetPostDesc,
527 PRIVILEGE_USER); // get debug post description
528 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
529 NULL, ipmiOemDbgGetGpioDesc,
530 PRIVILEGE_USER); // get debug gpio description
531 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
532 NULL, ipmiOemDbgGetFrameData,
533 PRIVILEGE_USER); // get debug frame data
534 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
535 NULL, ipmiOemDbgGetCtrlPanel,
536 PRIVILEGE_USER); // get debug control panel
537 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
538 ipmiOemSetDimmInfo,
539 PRIVILEGE_USER); // Set Dimm Info
540 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOOT_ORDER, NULL,
541 ipmiOemGetBootOrder,
542 PRIVILEGE_USER); // Get Boot Order
543 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL,
544 ipmiOemSetMachineCfgInfo,
545 PRIVILEGE_USER); // Set Machine Config Info
546 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL,
547 ipmiOemSetPostStart,
548 PRIVILEGE_USER); // Set POST start
549 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
550 ipmiOemSetPostEnd,
551 PRIVILEGE_USER); // Set POST End
552 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
553 ipmiOemSetBiosFlashInfo,
554 PRIVILEGE_USER); // Set Bios Flash Info
555 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr,
556 PRIVILEGE_USER); // Set PPR
557 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
558 PRIVILEGE_USER); // Get PPR
559 return;
560}
561
562} // namespace ipmi