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