xref: /openbmc/fb-ipmi-oem/src/oemcommands.cpp (revision 35d12546)
1 /*
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 <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
20 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
21 
22 #include <ipmid/api.hpp>
23 #include <ipmid/utils.hpp>
24 #include <commandutils.hpp>
25 #include <nlohmann/json.hpp>
26 #include <oemcommands.hpp>
27 #include <phosphor-logging/log.hpp>
28 #include <sdbusplus/bus.hpp>
29 
30 #include <ipmid/api.hpp>
31 #include <ipmid/api-types.hpp>
32 
33 #include <array>
34 #include <cstring>
35 #include <fstream>
36 #include <iomanip>
37 #include <iostream>
38 #include <sstream>
39 #include <string>
40 #include <vector>
41 
42 #define SIZE_IANA_ID 3
43 
44 namespace ipmi
45 {
46 
47 using namespace phosphor::logging;
48 
49 static void registerOEMFunctions() __attribute__((constructor));
50 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
51 static constexpr size_t maxFRUStringLength = 0x3F;
52 constexpr uint8_t cmdSetSystemGuid = 0xEF;
53 
54 int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*,
55                             uint8_t*);
56 int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*,
57                             uint8_t*);
58 ipmi_ret_t plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*,
59                                     uint8_t*);
60 ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*,
61                                    uint8_t*);
62 int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&);
63 
64 int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
65                std::vector<uint8_t>&);
66 
67 nlohmann::json oemData __attribute__((init_priority(101)));
68 
69 static constexpr size_t GUID_SIZE = 16;
70 // TODO Make offset and location runtime configurable to ensure we
71 // can make each define their own locations.
72 static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
73 static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
74 
75 enum class LanParam : uint8_t
76 {
77     INPROGRESS = 0,
78     AUTHSUPPORT = 1,
79     AUTHENABLES = 2,
80     IP = 3,
81     IPSRC = 4,
82     MAC = 5,
83     SUBNET = 6,
84     GATEWAY = 12,
85     VLAN = 20,
86     CIPHER_SUITE_COUNT = 22,
87     CIPHER_SUITE_ENTRIES = 23,
88     IPV6 = 59,
89 };
90 
91 namespace network
92 {
93 
94 constexpr auto ROOT = "/xyz/openbmc_project/network";
95 constexpr auto SERVICE = "xyz.openbmc_project.Network";
96 constexpr auto IPV4_TYPE = "ipv4";
97 constexpr auto IPV6_TYPE = "ipv6";
98 constexpr auto IPV4_PREFIX = "169.254";
99 constexpr auto IPV6_PREFIX = "fe80";
100 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
101 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
102 
103 bool isLinkLocalIP(const std::string& address)
104 {
105     return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
106 }
107 
108 DbusObjectInfo getIPObject(sdbusplus::bus::bus& bus,
109                            const std::string& interface,
110                            const std::string& serviceRoot,
111                            const std::string& match)
112 {
113     auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
114 
115     if (objectTree.empty())
116     {
117         log<level::ERR>("No Object has implemented the IP interface",
118                         entry("INTERFACE=%s", interface.c_str()));
119     }
120 
121     DbusObjectInfo objectInfo;
122 
123     for (auto& object : objectTree)
124     {
125         auto variant =
126             ipmi::getDbusProperty(bus, object.second.begin()->first,
127                                   object.first, IP_INTERFACE, "Address");
128 
129         objectInfo = std::make_pair(object.first, object.second.begin()->first);
130 
131         // if LinkLocalIP found look for Non-LinkLocalIP
132         if (isLinkLocalIP(std::get<std::string>(variant)))
133         {
134             continue;
135         }
136         else
137         {
138             break;
139         }
140     }
141     return objectInfo;
142 }
143 
144 } // namespace network
145 
146 namespace boot
147 {
148 
149 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
150 using IpmiValue = uint8_t;
151 
152 std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
153     {0x0f, Source::Sources::Default},
154     {0x00, Source::Sources::RemovableMedia},
155     {0x01, Source::Sources::Network},
156     {0x02, Source::Sources::Disk},
157     {0x03, Source::Sources::ExternalMedia},
158     {0x09, Source::Sources::Network}};
159 
160 std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
161     {0x06, Mode::Modes::Setup}, {0x00, Mode::Modes::Regular}};
162 
163 std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
164     {Source::Sources::Default, 0x0f},
165     {Source::Sources::RemovableMedia, 0x00},
166     {Source::Sources::Network, 0x01},
167     {Source::Sources::Disk, 0x02},
168     {Source::Sources::ExternalMedia, 0x03}};
169 
170 std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
171     {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, 0x00}};
172 
173 static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
174 static constexpr auto bootSourceIntf =
175     "xyz.openbmc_project.Control.Boot.Source";
176 static constexpr auto bootSourceProp = "BootSource";
177 static constexpr auto bootModeProp = "BootMode";
178 
179 auto instances(std::string s)
180 {
181     std::string delimiter = " ";
182     size_t pos = 0;
183     std::string token;
184     std::vector<std::string> host;
185 
186     while ((pos = s.find(delimiter)) != std::string::npos)
187     {
188         token = s.substr(0, pos);
189         host.push_back(token);
190         s.erase(0, pos + delimiter.length());
191     }
192     host.push_back(s);
193 
194     return host;
195 }
196 
197 std::optional<size_t> findHost(size_t id)
198 {
199     std::string str = INSTANCES;
200     size_t hostId;
201 
202     if (INSTANCES == "0")
203     {
204         hostId = id;
205     }
206     else
207     {
208         static const auto hosts = instances(str);
209         std::string num = std::to_string(id + 1);
210         auto instance = std::lower_bound(hosts.begin(), hosts.end(), num);
211 
212         if ((instance == hosts.end()) || (*instance != num))
213         {
214             return std::nullopt;
215         }
216         hostId = id + 1;
217     }
218 
219     return hostId;
220 }
221 
222 std::tuple<std::string, std::string> objPath(size_t id)
223 {
224     std::string hostName = "host" + std::to_string(id);
225     std::string bootObjPath =
226         "/xyz/openbmc_project/control/" + hostName + "/boot";
227     return std::make_tuple(std::move(bootObjPath), std::move(hostName));
228 }
229 
230 } // namespace boot
231 
232 //----------------------------------------------------------------------
233 // Helper functions for storing oem data
234 //----------------------------------------------------------------------
235 
236 void flushOemData()
237 {
238     std::ofstream file(JSON_OEM_DATA_FILE);
239     file << oemData;
240     file.close();
241     return;
242 }
243 
244 std::string bytesToStr(uint8_t* byte, int len)
245 {
246     std::stringstream ss;
247     int i;
248 
249     ss << std::hex;
250     for (i = 0; i < len; i++)
251     {
252         ss << std::setw(2) << std::setfill('0') << (int)byte[i];
253     }
254 
255     return ss.str();
256 }
257 
258 int strToBytes(std::string& str, uint8_t* data)
259 {
260     std::string sstr;
261     int i;
262 
263     for (i = 0; i < (str.length()) / 2; i++)
264     {
265         sstr = str.substr(i * 2, 2);
266         data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
267     }
268     return i;
269 }
270 
271 ipmi_ret_t getNetworkData(uint8_t lan_param, char* data)
272 {
273     ipmi_ret_t rc = IPMI_CC_OK;
274     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
275 
276     const std::string ethdevice = "eth0";
277 
278     switch (static_cast<LanParam>(lan_param))
279     {
280         case LanParam::IP:
281         {
282             auto ethIP = ethdevice + "/" + ipmi::network::IPV4_TYPE;
283             std::string ipaddress;
284             auto ipObjectInfo = ipmi::network::getIPObject(
285                 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT, ethIP);
286 
287             auto properties = ipmi::getAllDbusProperties(
288                 bus, ipObjectInfo.second, ipObjectInfo.first,
289                 ipmi::network::IP_INTERFACE);
290 
291             ipaddress = std::get<std::string>(properties["Address"]);
292 
293             std::strcpy(data, ipaddress.c_str());
294         }
295         break;
296 
297         case LanParam::IPV6:
298         {
299             auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE;
300             std::string ipaddress;
301             auto ipObjectInfo = ipmi::network::getIPObject(
302                 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT, ethIP);
303 
304             auto properties = ipmi::getAllDbusProperties(
305                 bus, ipObjectInfo.second, ipObjectInfo.first,
306                 ipmi::network::IP_INTERFACE);
307 
308             ipaddress = std::get<std::string>(properties["Address"]);
309 
310             std::strcpy(data, ipaddress.c_str());
311         }
312         break;
313 
314         case LanParam::MAC:
315         {
316             std::string macAddress;
317             auto macObjectInfo =
318                 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
319                                     ipmi::network::ROOT, ethdevice);
320 
321             auto variant = ipmi::getDbusProperty(
322                 bus, macObjectInfo.second, macObjectInfo.first,
323                 ipmi::network::MAC_INTERFACE, "MACAddress");
324 
325             macAddress = std::get<std::string>(variant);
326 
327             sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
328                    (data), (data + 1), (data + 2), (data + 3), (data + 4),
329                    (data + 5));
330             std::strcpy(data, macAddress.c_str());
331         }
332         break;
333 
334         default:
335             rc = IPMI_CC_PARM_OUT_OF_RANGE;
336     }
337     return rc;
338 }
339 
340 // return code: 0 successful
341 int8_t getFruData(std::string& data, std::string& name)
342 {
343     std::string objpath = "/xyz/openbmc_project/FruDevice";
344     std::string intf = "xyz.openbmc_project.FruDeviceManager";
345     std::string service = getService(dbus, intf, objpath);
346     ObjectValueTree valueTree = getManagedObjects(dbus, service, "/");
347     if (valueTree.empty())
348     {
349         phosphor::logging::log<phosphor::logging::level::ERR>(
350             "No object implements interface",
351             phosphor::logging::entry("INTF=%s", intf.c_str()));
352         return -1;
353     }
354 
355     for (const auto& item : valueTree)
356     {
357         auto interface = item.second.find("xyz.openbmc_project.FruDevice");
358         if (interface == item.second.end())
359         {
360             continue;
361         }
362 
363         auto property = interface->second.find(name.c_str());
364         if (property == interface->second.end())
365         {
366             continue;
367         }
368 
369         try
370         {
371             Value variant = property->second;
372             std::string& result = std::get<std::string>(variant);
373             if (result.size() > maxFRUStringLength)
374             {
375                 phosphor::logging::log<phosphor::logging::level::ERR>(
376                     "FRU serial number exceed maximum length");
377                 return -1;
378             }
379             data = result;
380             return 0;
381         }
382         catch (const std::bad_variant_access& e)
383         {
384             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
385             return -1;
386         }
387     }
388     return -1;
389 }
390 
391 typedef struct
392 {
393     uint8_t cur_power_state;
394     uint8_t last_power_event;
395     uint8_t misc_power_state;
396     uint8_t front_panel_button_cap_status;
397 } ipmi_get_chassis_status_t;
398 
399 //----------------------------------------------------------------------
400 // Get Debug Frame Info
401 //----------------------------------------------------------------------
402 ipmi_ret_t ipmiOemDbgGetFrameInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
403                                   ipmi_request_t request,
404                                   ipmi_response_t response,
405                                   ipmi_data_len_t data_len,
406                                   ipmi_context_t context)
407 {
408     uint8_t* req = reinterpret_cast<uint8_t*>(request);
409     uint8_t* res = reinterpret_cast<uint8_t*>(response);
410     uint8_t num_frames = 3;
411 
412     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
413     res[SIZE_IANA_ID] = num_frames;
414     *data_len = SIZE_IANA_ID + 1;
415 
416     return IPMI_CC_OK;
417 }
418 
419 //----------------------------------------------------------------------
420 // Get Debug Updated Frames
421 //----------------------------------------------------------------------
422 ipmi_ret_t ipmiOemDbgGetUpdFrames(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
423                                   ipmi_request_t request,
424                                   ipmi_response_t response,
425                                   ipmi_data_len_t data_len,
426                                   ipmi_context_t context)
427 {
428     uint8_t* req = reinterpret_cast<uint8_t*>(request);
429     uint8_t* res = reinterpret_cast<uint8_t*>(response);
430     uint8_t num_updates = 3;
431     *data_len = 4;
432 
433     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
434     res[SIZE_IANA_ID] = num_updates;
435     *data_len = SIZE_IANA_ID + num_updates + 1;
436     res[SIZE_IANA_ID + 1] = 1; // info page update
437     res[SIZE_IANA_ID + 2] = 2; // cri sel update
438     res[SIZE_IANA_ID + 3] = 3; // cri sensor update
439 
440     return IPMI_CC_OK;
441 }
442 
443 //----------------------------------------------------------------------
444 // Get Debug POST Description
445 //----------------------------------------------------------------------
446 ipmi_ret_t ipmiOemDbgGetPostDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
447                                  ipmi_request_t request,
448                                  ipmi_response_t response,
449                                  ipmi_data_len_t data_len,
450                                  ipmi_context_t context)
451 {
452     uint8_t* req = reinterpret_cast<uint8_t*>(request);
453     uint8_t* res = reinterpret_cast<uint8_t*>(response);
454     uint8_t index = 0;
455     uint8_t next = 0;
456     uint8_t end = 0;
457     uint8_t phase = 0;
458     uint8_t descLen = 0;
459     int ret;
460 
461     index = req[3];
462     phase = req[4];
463 
464     ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
465     if (ret)
466     {
467         memcpy(res, req, SIZE_IANA_ID); // IANA ID
468         *data_len = SIZE_IANA_ID;
469         return IPMI_CC_UNSPECIFIED_ERROR;
470     }
471 
472     memcpy(res, req, SIZE_IANA_ID); // IANA ID
473     res[3] = index;
474     res[4] = next;
475     res[5] = phase;
476     res[6] = end;
477     res[7] = descLen;
478     *data_len = SIZE_IANA_ID + 5 + descLen;
479 
480     return IPMI_CC_OK;
481 }
482 
483 //----------------------------------------------------------------------
484 // Get Debug GPIO Description
485 //----------------------------------------------------------------------
486 ipmi_ret_t ipmiOemDbgGetGpioDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
487                                  ipmi_request_t request,
488                                  ipmi_response_t response,
489                                  ipmi_data_len_t data_len,
490                                  ipmi_context_t context)
491 {
492     uint8_t* req = reinterpret_cast<uint8_t*>(request);
493     uint8_t* res = reinterpret_cast<uint8_t*>(response);
494 
495     uint8_t index = 0;
496     uint8_t next = 0;
497     uint8_t level = 0;
498     uint8_t pinDef = 0;
499     uint8_t descLen = 0;
500     int ret;
501 
502     index = req[3];
503 
504     ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
505                                   &res[8]);
506     if (ret)
507     {
508         memcpy(res, req, SIZE_IANA_ID); // IANA ID
509         *data_len = SIZE_IANA_ID;
510         return IPMI_CC_UNSPECIFIED_ERROR;
511     }
512 
513     memcpy(res, req, SIZE_IANA_ID); // IANA ID
514     res[3] = index;
515     res[4] = next;
516     res[5] = level;
517     res[6] = pinDef;
518     res[7] = descLen;
519     *data_len = SIZE_IANA_ID + 5 + descLen;
520 
521     return IPMI_CC_OK;
522 }
523 
524 //----------------------------------------------------------------------
525 // Get Debug Frame Data
526 //----------------------------------------------------------------------
527 ipmi_ret_t ipmiOemDbgGetFrameData(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
528                                   ipmi_request_t request,
529                                   ipmi_response_t response,
530                                   ipmi_data_len_t data_len,
531                                   ipmi_context_t context)
532 {
533     uint8_t* req = reinterpret_cast<uint8_t*>(request);
534     uint8_t* res = reinterpret_cast<uint8_t*>(response);
535     uint8_t frame;
536     uint8_t page;
537     uint8_t next;
538     uint8_t count;
539     int ret;
540 
541     frame = req[3];
542     page = req[4];
543     int fr = frame;
544     int pg = page;
545 
546     ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
547     if (ret)
548     {
549         memcpy(res, req, SIZE_IANA_ID); // IANA ID
550         *data_len = SIZE_IANA_ID;
551         return IPMI_CC_UNSPECIFIED_ERROR;
552     }
553 
554     memcpy(res, req, SIZE_IANA_ID); // IANA ID
555     res[3] = frame;
556     res[4] = page;
557     res[5] = next;
558     res[6] = count;
559     *data_len = SIZE_IANA_ID + 4 + count;
560 
561     return IPMI_CC_OK;
562 }
563 
564 //----------------------------------------------------------------------
565 // Get Debug Control Panel
566 //----------------------------------------------------------------------
567 ipmi_ret_t ipmiOemDbgGetCtrlPanel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
568                                   ipmi_request_t request,
569                                   ipmi_response_t response,
570                                   ipmi_data_len_t data_len,
571                                   ipmi_context_t context)
572 {
573     uint8_t* req = reinterpret_cast<uint8_t*>(request);
574     uint8_t* res = reinterpret_cast<uint8_t*>(response);
575 
576     uint8_t panel;
577     uint8_t operation;
578     uint8_t item;
579     uint8_t count;
580     ipmi_ret_t ret;
581 
582     panel = req[3];
583     operation = req[4];
584     item = req[5];
585 
586     ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
587 
588     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
589     *data_len = SIZE_IANA_ID + count;
590 
591     return ret;
592 }
593 
594 //----------------------------------------------------------------------
595 // Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
596 //----------------------------------------------------------------------
597 ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
598                               ipmi_request_t request, ipmi_response_t response,
599                               ipmi_data_len_t data_len, ipmi_context_t context)
600 {
601     uint8_t* req = reinterpret_cast<uint8_t*>(request);
602 
603     uint8_t index = req[0];
604     uint8_t type = req[1];
605     uint16_t speed;
606     uint32_t size;
607 
608     memcpy(&speed, &req[2], 2);
609     memcpy(&size, &req[4], 4);
610 
611     std::stringstream ss;
612     ss << std::hex;
613     ss << std::setw(2) << std::setfill('0') << (int)index;
614 
615     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
616     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
617     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
618     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
619 
620     flushOemData();
621 
622     *data_len = 0;
623 
624     return IPMI_CC_OK;
625 }
626 
627 //----------------------------------------------------------------------
628 // Get Board ID (CMD_OEM_GET_BOARD_ID)
629 //----------------------------------------------------------------------
630 ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
631                              ipmi_request_t request, ipmi_response_t response,
632                              ipmi_data_len_t data_len, ipmi_context_t context)
633 {
634     uint8_t* req = reinterpret_cast<uint8_t*>(request);
635     uint8_t* res = reinterpret_cast<uint8_t*>(response);
636 
637     /* TODO: Needs to implement this after GPIO implementation */
638     *data_len = 0;
639 
640     return IPMI_CC_OK;
641 }
642 
643 /* Helper functions to set boot order */
644 void setBootOrder(std::string bootObjPath, uint8_t* data,
645                   std::string bootOrderKey)
646 {
647 
648     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
649 
650     // SETTING BOOT MODE PROPERTY
651     auto bootValue = ipmi::boot::modeIpmiToDbus.find((data[0]));
652     std::string bootOption =
653         ipmi::boot::Mode::convertModesToString((bootValue->second));
654 
655     std::string service =
656         getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
657     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
658                     ipmi::boot::bootModeProp, bootOption);
659 
660     // SETTING BOOT SOURCE PROPERTY
661     auto bootOrder = ipmi::boot::sourceIpmiToDbus.find((data[1]));
662     std::string bootSource =
663         ipmi::boot::Source::convertSourcesToString((bootOrder->second));
664 
665     service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
666     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
667                     ipmi::boot::bootSourceProp, bootSource);
668 
669     nlohmann::json bootMode;
670     uint8_t mode = data[0];
671     int i;
672 
673     bootMode["UEFI"] = (mode & BOOT_MODE_UEFI ? true : false);
674     bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR ? true : false);
675     bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT ? true : false);
676     bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG ? true : false);
677     oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
678 
679     /* Initialize boot sequence array */
680     oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
681     for (i = 1; i < SIZE_BOOT_ORDER; i++)
682     {
683         if (data[i] >= BOOT_SEQ_ARRAY_SIZE)
684             oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
685         else
686             oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = bootSeq[data[i]];
687     }
688 
689     flushOemData();
690 }
691 
692 //----------------------------------------------------------------------
693 // Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
694 //----------------------------------------------------------------------
695 ipmi::RspType<std::vector<uint8_t>>
696     ipmiOemSetBootOrder(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
697 {
698 
699     uint8_t bootSeq[SIZE_BOOT_ORDER];
700     size_t len = data.size();
701 
702     if (len != SIZE_BOOT_ORDER)
703     {
704         phosphor::logging::log<phosphor::logging::level::ERR>(
705             "Invalid Boot order length received");
706         return ipmi::responseReqDataLenInvalid();
707     }
708 
709     std::copy(std::begin(data), std::end(data), bootSeq);
710     std::optional<size_t> hostId = ipmi::boot::findHost(ctx->hostIdx);
711 
712     if (!hostId)
713     {
714         phosphor::logging::log<phosphor::logging::level::ERR>(
715             "Invalid Host Id received");
716         return ipmi::responseInvalidCommand();
717     }
718     auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
719 
720     setBootOrder(bootObjPath, bootSeq, hostName);
721 
722     return ipmi::responseSuccess(data);
723 }
724 
725 //----------------------------------------------------------------------
726 // Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
727 //----------------------------------------------------------------------
728 ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>
729     ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
730 {
731     uint8_t bootOption, bootOrder;
732     uint8_t bootSeq[SIZE_BOOT_ORDER];
733     uint8_t mode = 0;
734 
735     std::optional<size_t> hostId = ipmi::boot::findHost(ctx->hostIdx);
736 
737     if (!hostId)
738     {
739         phosphor::logging::log<phosphor::logging::level::ERR>(
740             "Invalid Host Id received");
741         return ipmi::responseInvalidCommand();
742     }
743     auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
744 
745     // GETTING PROPERTY OF MODE INTERFACE
746 
747     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
748 
749     std::string service =
750         getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
751     Value variant =
752         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
753                         ipmi::boot::bootModeProp);
754 
755     auto bootMode = ipmi::boot::Mode::convertModesFromString(
756         std::get<std::string>(variant));
757 
758     bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
759 
760     // GETTING PROPERTY OF SOURCE INTERFACE
761 
762     service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
763     variant =
764         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
765                         ipmi::boot::bootSourceProp);
766     auto bootSource = ipmi::boot::Source::convertSourcesFromString(
767         std::get<std::string>(variant));
768 
769     bootOrder = ipmi::boot::sourceDbusToIpmi.at(bootSource);
770 
771     if (oemData.find(hostName) == oemData.end())
772     {
773         /* Return default boot order 0100090203ff */
774         uint8_t defaultBoot[SIZE_BOOT_ORDER] = {
775             BOOT_MODE_UEFI,      bootMap["USB_DEV"], bootMap["NET_IPV6"],
776             bootMap["SATA_HDD"], bootMap["SATA_CD"], 0xff};
777 
778         memcpy(bootSeq, defaultBoot, SIZE_BOOT_ORDER);
779         phosphor::logging::log<phosphor::logging::level::INFO>(
780             "Set default boot order");
781         setBootOrder(bootObjPath, defaultBoot, hostName);
782     }
783     else
784     {
785         nlohmann::json bootMode = oemData[hostName][KEY_BOOT_MODE];
786         if (bootMode["UEFI"])
787             mode |= BOOT_MODE_UEFI;
788         if (bootMode["CMOS_CLR"])
789             mode |= BOOT_MODE_CMOS_CLR;
790         if (bootMode["BOOT_FLAG"])
791             mode |= BOOT_MODE_BOOT_FLAG;
792 
793         bootSeq[0] = mode;
794 
795         for (int i = 1; i < SIZE_BOOT_ORDER; i++)
796         {
797             std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
798             if (bootMap.find(seqStr) != bootMap.end())
799                 bootSeq[i] = bootMap[seqStr];
800             else
801                 bootSeq[i] = 0xff;
802         }
803     }
804 
805     return ipmi::responseSuccess(bootOption, bootOrder, bootSeq[2], bootSeq[3],
806                                  bootSeq[4], bootSeq[5]);
807 }
808 // Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
809 //----------------------------------------------------------------------
810 ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
811                                     ipmi_request_t request,
812                                     ipmi_response_t response,
813                                     ipmi_data_len_t data_len,
814                                     ipmi_context_t context)
815 {
816     machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
817     uint8_t len = *data_len;
818 
819     *data_len = 0;
820 
821     if (len < sizeof(machineConfigInfo_t))
822     {
823         phosphor::logging::log<phosphor::logging::level::ERR>(
824             "Invalid machine configuration length received");
825         return IPMI_CC_REQ_DATA_LEN_INVALID;
826     }
827 
828     if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
829         oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
830     else
831         oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
832             chassisType[req->chassis_type];
833 
834     if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
835         oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
836     else
837         oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
838 
839     oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
840     oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
841     oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
842     oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
843 
844     if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
845         oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
846     else
847         oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
848 
849     oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
850     int i = 0;
851     if (req->pcie_card_loc & BIT_0)
852         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
853     if (req->pcie_card_loc & BIT_1)
854         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
855     if (req->pcie_card_loc & BIT_2)
856         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
857     if (req->pcie_card_loc & BIT_3)
858         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
859 
860     if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
861         oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
862     else
863         oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
864             pcieType[req->slot1_pcie_type];
865 
866     if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
867         oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
868     else
869         oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
870             pcieType[req->slot2_pcie_type];
871 
872     if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
873         oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
874     else
875         oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
876             pcieType[req->slot3_pcie_type];
877 
878     if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
879         oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
880     else
881         oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
882             pcieType[req->slot4_pcie_type];
883 
884     oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
885 
886     flushOemData();
887 
888     return IPMI_CC_OK;
889 }
890 
891 //----------------------------------------------------------------------
892 // Set POST start (CMD_OEM_SET_POST_START)
893 //----------------------------------------------------------------------
894 ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
895                                ipmi_request_t request, ipmi_response_t response,
896                                ipmi_data_len_t data_len, ipmi_context_t context)
897 {
898     phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
899 
900     /* Do nothing, return success */
901     *data_len = 0;
902     return IPMI_CC_OK;
903 }
904 
905 //----------------------------------------------------------------------
906 // Set POST End (CMD_OEM_SET_POST_END)
907 //----------------------------------------------------------------------
908 ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
909                              ipmi_request_t request, ipmi_response_t response,
910                              ipmi_data_len_t data_len, ipmi_context_t context)
911 {
912     struct timespec ts;
913 
914     phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
915 
916     *data_len = 0;
917 
918     // Timestamp post end time.
919     clock_gettime(CLOCK_REALTIME, &ts);
920     oemData[KEY_TS_SLED] = ts.tv_sec;
921     flushOemData();
922 
923     // Sync time with system
924     // TODO: Add code for syncing time
925 
926     return IPMI_CC_OK;
927 }
928 
929 //----------------------------------------------------------------------
930 // Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
931 //----------------------------------------------------------------------
932 // Inform BMC about PPIN data of 8 bytes for each CPU
933 //
934 // Request:
935 // Byte 1:8 – CPU0 PPIN data
936 // Optional:
937 // Byte 9:16 – CPU1 PPIN data
938 //
939 // Response:
940 // Byte 1 – Completion Code
941 ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
942                               ipmi_request_t request, ipmi_response_t response,
943                               ipmi_data_len_t data_len, ipmi_context_t context)
944 {
945     uint8_t* req = reinterpret_cast<uint8_t*>(request);
946     std::string ppinStr;
947     int len;
948 
949     if (*data_len > SIZE_CPU_PPIN * 2)
950         len = SIZE_CPU_PPIN * 2;
951     else
952         len = *data_len;
953     *data_len = 0;
954 
955     ppinStr = bytesToStr(req, len);
956     oemData[KEY_PPIN_INFO] = ppinStr.c_str();
957     flushOemData();
958 
959     return IPMI_CC_OK;
960 }
961 
962 //----------------------------------------------------------------------
963 // Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
964 //----------------------------------------------------------------------
965 ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
966                                 ipmi_request_t request,
967                                 ipmi_response_t response,
968                                 ipmi_data_len_t data_len,
969                                 ipmi_context_t context)
970 {
971     /* Do nothing, return success */
972     *data_len = 0;
973     return IPMI_CC_OK;
974 }
975 
976 // Helper function to set guid at offset in EEPROM
977 static int setGUID(off_t offset, uint8_t* guid)
978 {
979     int fd = -1;
980     ssize_t len;
981     int ret = 0;
982 
983     errno = 0;
984 
985     // Check if file is present
986     if (access(FRU_EEPROM, F_OK) == -1)
987     {
988         std::cerr << "Unable to access: " << FRU_EEPROM << std::endl;
989         return errno;
990     }
991 
992     // Open the file
993     fd = open(FRU_EEPROM, O_WRONLY);
994     if (fd == -1)
995     {
996         std::cerr << "Unable to open: " << FRU_EEPROM << std::endl;
997         return errno;
998     }
999 
1000     // seek to the offset
1001     lseek(fd, offset, SEEK_SET);
1002 
1003     // Write bytes to location
1004     len = write(fd, guid, GUID_SIZE);
1005     if (len != GUID_SIZE)
1006     {
1007         phosphor::logging::log<phosphor::logging::level::ERR>(
1008             "GUID write data to EEPROM failed");
1009         ret = errno;
1010     }
1011 
1012     close(fd);
1013     return ret;
1014 }
1015 
1016 //----------------------------------------------------------------------
1017 // Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1018 //----------------------------------------------------------------------
1019 #if BIC_ENABLED
1020 ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx, uint8_t cmdReq,
1021                                      std::vector<uint8_t> reqData)
1022 {
1023     std::vector<uint8_t> respData;
1024 
1025     if (reqData.size() != GUID_SIZE) // 16bytes
1026     {
1027 
1028         return ipmi::responseReqDataLenInvalid();
1029     }
1030 
1031     auto ptrReqData = reqData.insert(reqData.begin(), reqData.size());
1032 
1033     uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1034 
1035     if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1036         return ipmi::responseUnspecifiedError();
1037 
1038     return ipmi::responseSuccess();
1039 }
1040 
1041 #else
1042 ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1043                                 ipmi_request_t request,
1044                                 ipmi_response_t response,
1045                                 ipmi_data_len_t data_len,
1046                                 ipmi_context_t context)
1047 {
1048     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1049 
1050     if (*data_len != GUID_SIZE) // 16bytes
1051     {
1052         *data_len = 0;
1053         return IPMI_CC_REQ_DATA_LEN_INVALID;
1054     }
1055 
1056     *data_len = 0;
1057 
1058     if (setGUID(OFFSET_SYS_GUID, req))
1059     {
1060         return IPMI_CC_UNSPECIFIED_ERROR;
1061     }
1062     return IPMI_CC_OK;
1063 }
1064 #endif
1065 
1066 //----------------------------------------------------------------------
1067 // Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1068 //----------------------------------------------------------------------
1069 ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1070                                    ipmi_request_t request,
1071                                    ipmi_response_t response,
1072                                    ipmi_data_len_t data_len,
1073                                    ipmi_context_t context)
1074 {
1075     /* Do nothing, return success */
1076     *data_len = 0;
1077     return IPMI_CC_OK;
1078 }
1079 
1080 //----------------------------------------------------------------------
1081 // Set PPR (CMD_OEM_SET_PPR)
1082 //----------------------------------------------------------------------
1083 ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1084                          ipmi_request_t request, ipmi_response_t response,
1085                          ipmi_data_len_t data_len, ipmi_context_t context)
1086 {
1087     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1088     uint8_t pprCnt, pprAct, pprIndex;
1089     uint8_t selParam = req[0];
1090     uint8_t len = *data_len;
1091     std::stringstream ss;
1092     std::string str;
1093 
1094     *data_len = 0;
1095 
1096     switch (selParam)
1097     {
1098         case PPR_ACTION:
1099             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1100                 oemData[KEY_PPR].end())
1101                 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1102 
1103             pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1104             if (pprCnt == 0)
1105                 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1106 
1107             pprAct = req[1];
1108             /* Check if ppr is enabled or disabled */
1109             if (!(pprAct & 0x80))
1110                 pprAct = 0;
1111 
1112             oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1113             break;
1114         case PPR_ROW_COUNT:
1115             if (req[1] > 100)
1116                 return IPMI_CC_PARM_OUT_OF_RANGE;
1117 
1118             oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1119             break;
1120         case PPR_ROW_ADDR:
1121             pprIndex = req[1];
1122             if (pprIndex > 100)
1123                 return IPMI_CC_PARM_OUT_OF_RANGE;
1124 
1125             if (len < PPR_ROW_ADDR_LEN + 1)
1126             {
1127                 phosphor::logging::log<phosphor::logging::level::ERR>(
1128                     "Invalid PPR Row Address length received");
1129                 return IPMI_CC_REQ_DATA_LEN_INVALID;
1130             }
1131 
1132             ss << std::hex;
1133             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1134 
1135             oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1136 
1137             str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1138             oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1139             break;
1140         case PPR_HISTORY_DATA:
1141             pprIndex = req[1];
1142             if (pprIndex > 100)
1143                 return IPMI_CC_PARM_OUT_OF_RANGE;
1144 
1145             if (len < PPR_HST_DATA_LEN + 1)
1146             {
1147                 phosphor::logging::log<phosphor::logging::level::ERR>(
1148                     "Invalid PPR history data length received");
1149                 return IPMI_CC_REQ_DATA_LEN_INVALID;
1150             }
1151 
1152             ss << std::hex;
1153             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1154 
1155             oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1156 
1157             str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1158             oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1159             break;
1160         default:
1161             return IPMI_CC_PARM_OUT_OF_RANGE;
1162             break;
1163     }
1164 
1165     flushOemData();
1166 
1167     return IPMI_CC_OK;
1168 }
1169 
1170 //----------------------------------------------------------------------
1171 // Get PPR (CMD_OEM_GET_PPR)
1172 //----------------------------------------------------------------------
1173 ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1174                          ipmi_request_t request, ipmi_response_t response,
1175                          ipmi_data_len_t data_len, ipmi_context_t context)
1176 {
1177     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1178     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1179     uint8_t pprCnt, pprIndex;
1180     uint8_t selParam = req[0];
1181     std::stringstream ss;
1182     std::string str;
1183 
1184     /* Any failure will return zero length data */
1185     *data_len = 0;
1186 
1187     switch (selParam)
1188     {
1189         case PPR_ACTION:
1190             res[0] = 0;
1191             *data_len = 1;
1192 
1193             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1194                 oemData[KEY_PPR].end())
1195             {
1196                 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1197                 if (pprCnt != 0)
1198                 {
1199                     if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1200                         oemData[KEY_PPR].end())
1201                     {
1202                         res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1203                     }
1204                 }
1205             }
1206             break;
1207         case PPR_ROW_COUNT:
1208             res[0] = 0;
1209             *data_len = 1;
1210             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1211                 oemData[KEY_PPR].end())
1212                 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1213             break;
1214         case PPR_ROW_ADDR:
1215             pprIndex = req[1];
1216             if (pprIndex > 100)
1217                 return IPMI_CC_PARM_OUT_OF_RANGE;
1218 
1219             ss << std::hex;
1220             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1221 
1222             if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1223                 return IPMI_CC_PARM_OUT_OF_RANGE;
1224 
1225             if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1226                 oemData[KEY_PPR][ss.str()].end())
1227                 return IPMI_CC_PARM_OUT_OF_RANGE;
1228 
1229             str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1230             *data_len = strToBytes(str, res);
1231             break;
1232         case PPR_HISTORY_DATA:
1233             pprIndex = req[1];
1234             if (pprIndex > 100)
1235                 return IPMI_CC_PARM_OUT_OF_RANGE;
1236 
1237             ss << std::hex;
1238             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1239 
1240             if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1241                 return IPMI_CC_PARM_OUT_OF_RANGE;
1242 
1243             if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1244                 oemData[KEY_PPR][ss.str()].end())
1245                 return IPMI_CC_PARM_OUT_OF_RANGE;
1246 
1247             str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1248             *data_len = strToBytes(str, res);
1249             break;
1250         default:
1251             return IPMI_CC_PARM_OUT_OF_RANGE;
1252             break;
1253     }
1254 
1255     return IPMI_CC_OK;
1256 }
1257 
1258 /* FB OEM QC Commands */
1259 
1260 //----------------------------------------------------------------------
1261 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1262 //----------------------------------------------------------------------
1263 //"Request:
1264 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1265 // Byte 4 – Processor Index, 0 base
1266 // Byte 5 – Parameter Selector
1267 // Byte 6..N – Configuration parameter data (see below for Parameters
1268 // of Processor Information)
1269 // Response:
1270 // Byte 1 – Completion code
1271 //
1272 // Parameter#1: (Processor Product Name)
1273 //
1274 // Byte 1..48 –Product name(ASCII code)
1275 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1276 //
1277 // Param#2: Processor Basic Information
1278 // Byte 1 – Core Number
1279 // Byte 2 – Thread Number (LSB)
1280 // Byte 3 – Thread Number (MSB)
1281 // Byte 4 – Processor frequency in MHz (LSB)
1282 // Byte 5 – Processor frequency in MHz (MSB)
1283 // Byte 6..7 – Revision
1284 //
1285 ipmi_ret_t ipmiOemQSetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1286                                ipmi_request_t request, ipmi_response_t response,
1287                                ipmi_data_len_t data_len, ipmi_context_t context)
1288 {
1289     qProcInfo_t* req = reinterpret_cast<qProcInfo_t*>(request);
1290     uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
1291     std::stringstream ss;
1292     std::string str;
1293     uint8_t len = *data_len;
1294 
1295     *data_len = 0;
1296 
1297     /* check for requested data params */
1298     if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
1299     {
1300         phosphor::logging::log<phosphor::logging::level::ERR>(
1301             "Invalid parameter received");
1302         return IPMI_CC_PARM_OUT_OF_RANGE;
1303     }
1304 
1305     len = len - 5; // Get Actual data length
1306 
1307     ss << std::hex;
1308     ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
1309     oemData[KEY_Q_PROC_INFO][ss.str()][KEY_PROC_INDEX] = req->procIndex;
1310 
1311     str = bytesToStr(req->data, len);
1312     oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]] = str.c_str();
1313     flushOemData();
1314 
1315     return IPMI_CC_OK;
1316 }
1317 
1318 //----------------------------------------------------------------------
1319 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1320 //----------------------------------------------------------------------
1321 // Request:
1322 // Byte 1:3 –  Manufacturer ID – XXYYZZ h, LSB first
1323 // Byte 4 – Processor Index, 0 base
1324 // Byte 5 – Parameter Selector
1325 // Response:
1326 // Byte 1 – Completion code
1327 // Byte 2..N – Configuration Parameter Data (see below for Parameters
1328 // of Processor Information)
1329 //
1330 // Parameter#1: (Processor Product Name)
1331 //
1332 // Byte 1..48 –Product name(ASCII code)
1333 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1334 //
1335 // Param#2: Processor Basic Information
1336 // Byte 1 – Core Number
1337 // Byte 2 – Thread Number (LSB)
1338 // Byte 3 – Thread Number (MSB)
1339 // Byte 4 – Processor frequency in MHz (LSB)
1340 // Byte 5 – Processor frequency in MHz (MSB)
1341 // Byte 6..7 – Revision
1342 //
1343 ipmi_ret_t ipmiOemQGetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1344                                ipmi_request_t request, ipmi_response_t response,
1345                                ipmi_data_len_t data_len, ipmi_context_t context)
1346 {
1347     qProcInfo_t* req = reinterpret_cast<qProcInfo_t*>(request);
1348     uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
1349     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1350     std::stringstream ss;
1351     std::string str;
1352 
1353     *data_len = 0;
1354 
1355     /* check for requested data params */
1356     if (req->paramSel < 1 || req->paramSel >= numParam)
1357     {
1358         phosphor::logging::log<phosphor::logging::level::ERR>(
1359             "Invalid parameter received");
1360         return IPMI_CC_PARM_OUT_OF_RANGE;
1361     }
1362 
1363     ss << std::hex;
1364     ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
1365 
1366     if (oemData[KEY_Q_PROC_INFO].find(ss.str()) ==
1367         oemData[KEY_Q_PROC_INFO].end())
1368         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1369 
1370     if (oemData[KEY_Q_PROC_INFO][ss.str()].find(cpuInfoKey[req->paramSel]) ==
1371         oemData[KEY_Q_PROC_INFO][ss.str()].end())
1372         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1373 
1374     str = oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]];
1375     *data_len = strToBytes(str, res);
1376 
1377     return IPMI_CC_OK;
1378 }
1379 
1380 //----------------------------------------------------------------------
1381 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1382 //----------------------------------------------------------------------
1383 // Request:
1384 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1385 // Byte 4 – DIMM Index, 0 base
1386 // Byte 5 – Parameter Selector
1387 // Byte 6..N – Configuration parameter data (see below for Parameters
1388 // of DIMM Information)
1389 // Response:
1390 // Byte 1 – Completion code
1391 //
1392 // Param#1 (DIMM Location):
1393 // Byte 1 – DIMM Present
1394 // Byte 1 – DIMM Present
1395 // 01h – Present
1396 // FFh – Not Present
1397 // Byte 2 – Node Number, 0 base
1398 // Byte 3 – Channel Number , 0 base
1399 // Byte 4 – DIMM Number , 0 base
1400 //
1401 // Param#2 (DIMM Type):
1402 // Byte 1 – DIMM Type
1403 // Bit [7:6]
1404 // For DDR3
1405 //  00 – Normal Voltage (1.5V)
1406 //  01 – Ultra Low Voltage (1.25V)
1407 //  10 – Low Voltage (1.35V)
1408 //  11 – Reserved
1409 // For DDR4
1410 //  00 – Reserved
1411 //  01 – Reserved
1412 //  10 – Reserved
1413 //  11 – Normal Voltage (1.2V)
1414 // Bit [5:0]
1415 //  0x00 – SDRAM
1416 //  0x01 – DDR-1 RAM
1417 //  0x02 – Rambus
1418 //  0x03 – DDR-2 RAM
1419 //  0x04 – FBDIMM
1420 //  0x05 – DDR-3 RAM
1421 //  0x06 – DDR-4 RAM
1422 //
1423 // Param#3 (DIMM Speed):
1424 // Byte 1..2 – DIMM speed in MHz, LSB
1425 // Byte 3..6 – DIMM size in Mbytes, LSB
1426 //
1427 // Param#4 (Module Part Number):
1428 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1429 //
1430 // Param#5 (Module Serial Number):
1431 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1432 //
1433 // Param#6 (Module Manufacturer ID):
1434 // Byte 1 - Module Manufacturer ID, LSB
1435 // Byte 2 - Module Manufacturer ID, MSB
1436 //
1437 ipmi_ret_t ipmiOemQSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1438                                ipmi_request_t request, ipmi_response_t response,
1439                                ipmi_data_len_t data_len, ipmi_context_t context)
1440 {
1441     qDimmInfo_t* req = reinterpret_cast<qDimmInfo_t*>(request);
1442     uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
1443     std::stringstream ss;
1444     std::string str;
1445     uint8_t len = *data_len;
1446 
1447     *data_len = 0;
1448 
1449     /* check for requested data params */
1450     if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
1451     {
1452         phosphor::logging::log<phosphor::logging::level::ERR>(
1453             "Invalid parameter received");
1454         return IPMI_CC_PARM_OUT_OF_RANGE;
1455     }
1456 
1457     len = len - 5; // Get Actual data length
1458 
1459     ss << std::hex;
1460     ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
1461     oemData[KEY_Q_DIMM_INFO][ss.str()][KEY_DIMM_INDEX] = req->dimmIndex;
1462 
1463     str = bytesToStr(req->data, len);
1464     oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]] =
1465         str.c_str();
1466     flushOemData();
1467 
1468     return IPMI_CC_OK;
1469 }
1470 
1471 //----------------------------------------------------------------------
1472 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1473 //----------------------------------------------------------------------
1474 // Request:
1475 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1476 // Byte 4 – DIMM Index, 0 base
1477 // Byte 5 – Parameter Selector
1478 // Byte 6..N – Configuration parameter data (see below for Parameters
1479 // of DIMM Information)
1480 // Response:
1481 // Byte 1 – Completion code
1482 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1483 // of DIMM Information)
1484 //
1485 // Param#1 (DIMM Location):
1486 // Byte 1 – DIMM Present
1487 // Byte 1 – DIMM Present
1488 // 01h – Present
1489 // FFh – Not Present
1490 // Byte 2 – Node Number, 0 base
1491 // Byte 3 – Channel Number , 0 base
1492 // Byte 4 – DIMM Number , 0 base
1493 //
1494 // Param#2 (DIMM Type):
1495 // Byte 1 – DIMM Type
1496 // Bit [7:6]
1497 // For DDR3
1498 //  00 – Normal Voltage (1.5V)
1499 //  01 – Ultra Low Voltage (1.25V)
1500 //  10 – Low Voltage (1.35V)
1501 //  11 – Reserved
1502 // For DDR4
1503 //  00 – Reserved
1504 //  01 – Reserved
1505 //  10 – Reserved
1506 //  11 – Normal Voltage (1.2V)
1507 // Bit [5:0]
1508 //  0x00 – SDRAM
1509 //  0x01 – DDR-1 RAM
1510 //  0x02 – Rambus
1511 //  0x03 – DDR-2 RAM
1512 //  0x04 – FBDIMM
1513 //  0x05 – DDR-3 RAM
1514 //  0x06 – DDR-4 RAM
1515 //
1516 // Param#3 (DIMM Speed):
1517 // Byte 1..2 – DIMM speed in MHz, LSB
1518 // Byte 3..6 – DIMM size in Mbytes, LSB
1519 //
1520 // Param#4 (Module Part Number):
1521 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1522 //
1523 // Param#5 (Module Serial Number):
1524 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1525 //
1526 // Param#6 (Module Manufacturer ID):
1527 // Byte 1 - Module Manufacturer ID, LSB
1528 // Byte 2 - Module Manufacturer ID, MSB
1529 //
1530 ipmi_ret_t ipmiOemQGetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1531                                ipmi_request_t request, ipmi_response_t response,
1532                                ipmi_data_len_t data_len, ipmi_context_t context)
1533 {
1534     qDimmInfo_t* req = reinterpret_cast<qDimmInfo_t*>(request);
1535     uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
1536     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1537     std::stringstream ss;
1538     std::string str;
1539 
1540     *data_len = 0;
1541 
1542     /* check for requested data params */
1543     if (req->paramSel < 1 || req->paramSel >= numParam)
1544     {
1545         phosphor::logging::log<phosphor::logging::level::ERR>(
1546             "Invalid parameter received");
1547         return IPMI_CC_PARM_OUT_OF_RANGE;
1548     }
1549 
1550     ss << std::hex;
1551     ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
1552 
1553     if (oemData[KEY_Q_DIMM_INFO].find(ss.str()) ==
1554         oemData[KEY_Q_DIMM_INFO].end())
1555         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1556 
1557     if (oemData[KEY_Q_DIMM_INFO][ss.str()].find(dimmInfoKey[req->paramSel]) ==
1558         oemData[KEY_Q_DIMM_INFO][ss.str()].end())
1559         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1560 
1561     str = oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]];
1562     *data_len = strToBytes(str, res);
1563 
1564     return IPMI_CC_OK;
1565 }
1566 
1567 //----------------------------------------------------------------------
1568 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
1569 //----------------------------------------------------------------------
1570 // BIOS issue this command to provide HDD information to BMC.
1571 //
1572 // BIOS just can get information by standard ATA / SMART command for
1573 // OB SATA controller.
1574 // BIOS can get
1575 // 1.     Serial Number
1576 // 2.     Model Name
1577 // 3.     HDD FW Version
1578 // 4.     HDD Capacity
1579 // 5.     HDD WWN
1580 //
1581 //  Use Get HDD info Param #5 to know the MAX HDD info index.
1582 //
1583 //  Request:
1584 //  Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1585 //  Byte 4 –
1586 //  [7:4] Reserved
1587 //  [3:0] HDD Controller Type
1588 //     0x00 – BIOS
1589 //     0x01 – Expander
1590 //     0x02 – LSI
1591 //  Byte 5 – HDD Info Index, 0 base
1592 //  Byte 6 – Parameter Selector
1593 //  Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
1594 //  Information)
1595 //
1596 //  Response:
1597 //  Byte 1 – Completion Code
1598 //
1599 //  Param#0 (HDD Location):
1600 //  Byte 1 – Controller
1601 //    [7:3] Device Number
1602 //    [2:0] Function Number
1603 //  For Intel C610 series (Wellsburg)
1604 //    D31:F2 (0xFA) – SATA control 1
1605 //    D31:F5 (0xFD) – SATA control 2
1606 //    D17:F4 (0x8C) – sSata control
1607 //  Byte 2 – Port Number
1608 //  Byte 3 – Location (0xFF: No HDD Present)
1609 //  BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
1610 //  #1~4, #6,  #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
1611 //  the HDD present. BMC or other people who know the HDD location has
1612 //  responsibility for update Location info
1613 //
1614 //  Param#1 (Serial Number):
1615 //  Bytes 1..33: HDD Serial Number
1616 //
1617 //  Param#2 (Model Name):
1618 //  Byte 1..33 – HDD Model Name
1619 //
1620 //  Param#3 (HDD FW Version):
1621 //  Byte 1..17 –HDD FW version
1622 //
1623 //  Param#4 (Capacity):
1624 //  Byte 1..4 –HDD Block Size, LSB
1625 //  Byte 5..12 - HDD Block Number, LSB
1626 //  HDD Capacity = HDD Block size * HDD BLock number  (Unit Byte)
1627 //
1628 //  Param#5 (Max HDD Quantity):
1629 //  Byte 1 - Max HDD Quantity
1630 //  Max supported port numbers in this PCH
1631 //
1632 //  Param#6 (HDD Type)
1633 //  Byte 1 – HDD Type
1634 //  0h – Reserved
1635 //  1h – SAS
1636 //  2h – SATA
1637 //  3h – PCIE SSD (NVME)
1638 //
1639 //  Param#7 (HDD WWN)
1640 //  Data 1...8: HDD World Wide Name, LSB
1641 //
1642 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1643                                 ipmi_request_t request,
1644                                 ipmi_response_t response,
1645                                 ipmi_data_len_t data_len,
1646                                 ipmi_context_t context)
1647 {
1648     qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1649     uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1650     uint8_t ctrlType = req->hddCtrlType & 0x0f;
1651     std::stringstream ss;
1652     std::string str;
1653     uint8_t len = *data_len;
1654 
1655     *data_len = 0;
1656 
1657     /* check for requested data params */
1658     if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam ||
1659         ctrlType > 2)
1660     {
1661         phosphor::logging::log<phosphor::logging::level::ERR>(
1662             "Invalid parameter received");
1663         return IPMI_CC_PARM_OUT_OF_RANGE;
1664     }
1665 
1666     len = len - 6; // Get Actual data length
1667 
1668     ss << std::hex;
1669     ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1670     oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
1671     oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
1672         req->hddIndex;
1673 
1674     str = bytesToStr(req->data, len);
1675     oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1676            [driveInfoKey[req->paramSel]] = str.c_str();
1677     flushOemData();
1678 
1679     return IPMI_CC_OK;
1680 }
1681 
1682 //----------------------------------------------------------------------
1683 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
1684 //----------------------------------------------------------------------
1685 // BMC needs to check HDD presented or not first. If NOT presented, return
1686 // completion code 0xD5.
1687 //
1688 // Request:
1689 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1690 // Byte 4 –
1691 //[7:4] Reserved
1692 //[3:0] HDD Controller Type
1693 //   0x00 – BIOS
1694 //   0x01 – Expander
1695 //   0x02 – LSI
1696 // Byte 5 – HDD Index, 0 base
1697 // Byte 6 – Parameter Selector (See Above Set HDD Information)
1698 // Response:
1699 // Byte 1 – Completion Code
1700 //   0xD5 – Not support in current status (HDD Not Present)
1701 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
1702 // Information)
1703 //
1704 ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1705                                 ipmi_request_t request,
1706                                 ipmi_response_t response,
1707                                 ipmi_data_len_t data_len,
1708                                 ipmi_context_t context)
1709 {
1710     qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1711     uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1712     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1713     uint8_t ctrlType = req->hddCtrlType & 0x0f;
1714     std::stringstream ss;
1715     std::string str;
1716 
1717     *data_len = 0;
1718 
1719     /* check for requested data params */
1720     if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2)
1721     {
1722         phosphor::logging::log<phosphor::logging::level::ERR>(
1723             "Invalid parameter received");
1724         return IPMI_CC_PARM_OUT_OF_RANGE;
1725     }
1726 
1727     if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
1728         oemData[KEY_Q_DRIVE_INFO].end())
1729         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1730 
1731     ss << std::hex;
1732     ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1733 
1734     if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
1735         oemData[KEY_Q_DRIVE_INFO].end())
1736         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1737 
1738     if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
1739             dimmInfoKey[req->paramSel]) ==
1740         oemData[KEY_Q_DRIVE_INFO][ss.str()].end())
1741         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1742 
1743     str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1744                  [dimmInfoKey[req->paramSel]];
1745     *data_len = strToBytes(str, res);
1746 
1747     return IPMI_CC_OK;
1748 }
1749 
1750 /* Helper function for sending DCMI commands to ME and getting response back */
1751 ipmi::RspType<std::vector<uint8_t>> sendDCMICmd(uint8_t cmd,
1752                                                 std::vector<uint8_t>& cmdData)
1753 {
1754     std::vector<uint8_t> respData;
1755 
1756     /* Add group id as first byte to request for ME command */
1757     cmdData.insert(cmdData.begin(), groupDCMI);
1758 
1759     if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
1760         return ipmi::responseUnspecifiedError();
1761 
1762     /* Remove group id as first byte as it will be added by IPMID */
1763     respData.erase(respData.begin());
1764 
1765     return ipmi::responseSuccess(std::move(respData));
1766 }
1767 
1768 /* DCMI Command handellers. */
1769 
1770 ipmi::RspType<std::vector<uint8_t>>
1771     ipmiOemDCMIGetPowerReading(std::vector<uint8_t> reqData)
1772 {
1773     return sendDCMICmd(ipmi::dcmi::cmdGetPowerReading, reqData);
1774 }
1775 
1776 ipmi::RspType<std::vector<uint8_t>>
1777     ipmiOemDCMIGetPowerLimit(std::vector<uint8_t> reqData)
1778 {
1779     return sendDCMICmd(ipmi::dcmi::cmdGetPowerLimit, reqData);
1780 }
1781 
1782 ipmi::RspType<std::vector<uint8_t>>
1783     ipmiOemDCMISetPowerLimit(std::vector<uint8_t> reqData)
1784 {
1785     return sendDCMICmd(ipmi::dcmi::cmdSetPowerLimit, reqData);
1786 }
1787 
1788 ipmi::RspType<std::vector<uint8_t>>
1789     ipmiOemDCMIApplyPowerLimit(std::vector<uint8_t> reqData)
1790 {
1791     return sendDCMICmd(ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
1792 }
1793 
1794 static void registerOEMFunctions(void)
1795 {
1796     /* Get OEM data from json file */
1797     std::ifstream file(JSON_OEM_DATA_FILE);
1798     if (file)
1799     {
1800         file >> oemData;
1801         file.close();
1802     }
1803 
1804     phosphor::logging::log<phosphor::logging::level::INFO>(
1805         "Registering OEM commands");
1806 
1807     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
1808                          NULL, ipmiOemDbgGetFrameInfo,
1809                          PRIVILEGE_USER); // get debug frame info
1810     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
1811                          CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
1812                          ipmiOemDbgGetUpdFrames,
1813                          PRIVILEGE_USER); // get debug updated frames
1814     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
1815                          NULL, ipmiOemDbgGetPostDesc,
1816                          PRIVILEGE_USER); // get debug post description
1817     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
1818                          NULL, ipmiOemDbgGetGpioDesc,
1819                          PRIVILEGE_USER); // get debug gpio description
1820     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
1821                          NULL, ipmiOemDbgGetFrameData,
1822                          PRIVILEGE_USER); // get debug frame data
1823     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
1824                          NULL, ipmiOemDbgGetCtrlPanel,
1825                          PRIVILEGE_USER); // get debug control panel
1826     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
1827                          ipmiOemSetDimmInfo,
1828                          PRIVILEGE_USER); // Set Dimm Info
1829     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL,
1830                          ipmiOemGetBoardID,
1831                          PRIVILEGE_USER); // Get Board ID
1832     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL,
1833                          ipmiOemSetMachineCfgInfo,
1834                          PRIVILEGE_USER); // Set Machine Config Info
1835     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL,
1836                          ipmiOemSetPostStart,
1837                          PRIVILEGE_USER); // Set POST start
1838     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
1839                          ipmiOemSetPostEnd,
1840                          PRIVILEGE_USER); // Set POST End
1841     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL,
1842                          ipmiOemSetPPINInfo,
1843                          PRIVILEGE_USER); // Set PPIN Info
1844 #if BIC_ENABLED
1845 
1846     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1847                           ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
1848                           ipmiOemSetSystemGuid);
1849 #else
1850 
1851     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL,
1852                          ipmiOemSetSystemGuid,
1853                          PRIVILEGE_USER); // Set System GUID
1854 #endif
1855     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL,
1856                          ipmiOemSetAdrTrigger,
1857                          PRIVILEGE_USER); // Set ADR Trigger
1858     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
1859                          ipmiOemSetBiosFlashInfo,
1860                          PRIVILEGE_USER); // Set Bios Flash Info
1861     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr,
1862                          PRIVILEGE_USER); // Set PPR
1863     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
1864                          PRIVILEGE_USER); // Get PPR
1865     /* FB OEM QC Commands */
1866     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_PROC_INFO, NULL,
1867                          ipmiOemQSetProcInfo,
1868                          PRIVILEGE_USER); // Set Proc Info
1869     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_PROC_INFO, NULL,
1870                          ipmiOemQGetProcInfo,
1871                          PRIVILEGE_USER); // Get Proc Info
1872     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DIMM_INFO, NULL,
1873                          ipmiOemQSetDimmInfo,
1874                          PRIVILEGE_USER); // Set Dimm Info
1875     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DIMM_INFO, NULL,
1876                          ipmiOemQGetDimmInfo,
1877                          PRIVILEGE_USER); // Get Dimm Info
1878     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
1879                          ipmiOemQSetDriveInfo,
1880                          PRIVILEGE_USER); // Set Drive Info
1881     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
1882                          ipmiOemQGetDriveInfo,
1883                          PRIVILEGE_USER); // Get Drive Info
1884 
1885     /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
1886     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1887                                ipmi::dcmi::cmdGetPowerReading,
1888                                ipmi::Privilege::User,
1889                                ipmiOemDCMIGetPowerReading); // Get Power Reading
1890 
1891     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1892                                ipmi::dcmi::cmdGetPowerLimit,
1893                                ipmi::Privilege::User,
1894                                ipmiOemDCMIGetPowerLimit); // Get Power Limit
1895 
1896     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1897                                ipmi::dcmi::cmdSetPowerLimit,
1898                                ipmi::Privilege::Operator,
1899                                ipmiOemDCMISetPowerLimit); // Set Power Limit
1900 
1901     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1902                                ipmi::dcmi::cmdActDeactivatePwrLimit,
1903                                ipmi::Privilege::Operator,
1904                                ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
1905 
1906     /* FB OEM BOOT ORDER COMMANDS */
1907     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1908                           CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
1909                           ipmiOemGetBootOrder); // Get Boot Order
1910 
1911     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1912                           CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
1913                           ipmiOemSetBootOrder); // Set Boot Order
1914 
1915     return;
1916 }
1917 
1918 } // namespace ipmi
1919