xref: /openbmc/fb-ipmi-oem/src/oemcommands.cpp (revision 77ee489f)
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     int 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 netfn, ipmi_cmd_t cmd,
428                                   ipmi_request_t request,
429                                   ipmi_response_t response,
430                                   ipmi_data_len_t data_len,
431                                   ipmi_context_t context)
432 {
433     uint8_t* req = reinterpret_cast<uint8_t*>(request);
434     uint8_t* res = reinterpret_cast<uint8_t*>(response);
435     uint8_t num_frames = 3;
436 
437     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
438     res[SIZE_IANA_ID] = num_frames;
439     *data_len = SIZE_IANA_ID + 1;
440 
441     return IPMI_CC_OK;
442 }
443 
444 //----------------------------------------------------------------------
445 // Get Debug Updated Frames
446 //----------------------------------------------------------------------
447 ipmi_ret_t ipmiOemDbgGetUpdFrames(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
448                                   ipmi_request_t request,
449                                   ipmi_response_t response,
450                                   ipmi_data_len_t data_len,
451                                   ipmi_context_t context)
452 {
453     uint8_t* req = reinterpret_cast<uint8_t*>(request);
454     uint8_t* res = reinterpret_cast<uint8_t*>(response);
455     uint8_t num_updates = 3;
456     *data_len = 4;
457 
458     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
459     res[SIZE_IANA_ID] = num_updates;
460     *data_len = SIZE_IANA_ID + num_updates + 1;
461     res[SIZE_IANA_ID + 1] = 1; // info page update
462     res[SIZE_IANA_ID + 2] = 2; // cri sel update
463     res[SIZE_IANA_ID + 3] = 3; // cri sensor update
464 
465     return IPMI_CC_OK;
466 }
467 
468 //----------------------------------------------------------------------
469 // Get Debug POST Description
470 //----------------------------------------------------------------------
471 ipmi_ret_t ipmiOemDbgGetPostDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
472                                  ipmi_request_t request,
473                                  ipmi_response_t response,
474                                  ipmi_data_len_t data_len,
475                                  ipmi_context_t context)
476 {
477     uint8_t* req = reinterpret_cast<uint8_t*>(request);
478     uint8_t* res = reinterpret_cast<uint8_t*>(response);
479     uint8_t index = 0;
480     uint8_t next = 0;
481     uint8_t end = 0;
482     uint8_t phase = 0;
483     uint8_t descLen = 0;
484     int ret;
485 
486     index = req[3];
487     phase = req[4];
488 
489     ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
490     if (ret)
491     {
492         memcpy(res, req, SIZE_IANA_ID); // IANA ID
493         *data_len = SIZE_IANA_ID;
494         return IPMI_CC_UNSPECIFIED_ERROR;
495     }
496 
497     memcpy(res, req, SIZE_IANA_ID); // IANA ID
498     res[3] = index;
499     res[4] = next;
500     res[5] = phase;
501     res[6] = end;
502     res[7] = descLen;
503     *data_len = SIZE_IANA_ID + 5 + descLen;
504 
505     return IPMI_CC_OK;
506 }
507 
508 //----------------------------------------------------------------------
509 // Get Debug GPIO Description
510 //----------------------------------------------------------------------
511 ipmi_ret_t ipmiOemDbgGetGpioDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
512                                  ipmi_request_t request,
513                                  ipmi_response_t response,
514                                  ipmi_data_len_t data_len,
515                                  ipmi_context_t context)
516 {
517     uint8_t* req = reinterpret_cast<uint8_t*>(request);
518     uint8_t* res = reinterpret_cast<uint8_t*>(response);
519 
520     uint8_t index = 0;
521     uint8_t next = 0;
522     uint8_t level = 0;
523     uint8_t pinDef = 0;
524     uint8_t descLen = 0;
525     int ret;
526 
527     index = req[3];
528 
529     ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
530                                   &res[8]);
531     if (ret)
532     {
533         memcpy(res, req, SIZE_IANA_ID); // IANA ID
534         *data_len = SIZE_IANA_ID;
535         return IPMI_CC_UNSPECIFIED_ERROR;
536     }
537 
538     memcpy(res, req, SIZE_IANA_ID); // IANA ID
539     res[3] = index;
540     res[4] = next;
541     res[5] = level;
542     res[6] = pinDef;
543     res[7] = descLen;
544     *data_len = SIZE_IANA_ID + 5 + descLen;
545 
546     return IPMI_CC_OK;
547 }
548 
549 //----------------------------------------------------------------------
550 // Get Debug Frame Data
551 //----------------------------------------------------------------------
552 ipmi_ret_t ipmiOemDbgGetFrameData(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
553                                   ipmi_request_t request,
554                                   ipmi_response_t response,
555                                   ipmi_data_len_t data_len,
556                                   ipmi_context_t context)
557 {
558     uint8_t* req = reinterpret_cast<uint8_t*>(request);
559     uint8_t* res = reinterpret_cast<uint8_t*>(response);
560     uint8_t frame;
561     uint8_t page;
562     uint8_t next;
563     uint8_t count;
564     int ret;
565 
566     frame = req[3];
567     page = req[4];
568     int fr = frame;
569     int pg = page;
570 
571     ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
572     if (ret)
573     {
574         memcpy(res, req, SIZE_IANA_ID); // IANA ID
575         *data_len = SIZE_IANA_ID;
576         return IPMI_CC_UNSPECIFIED_ERROR;
577     }
578 
579     memcpy(res, req, SIZE_IANA_ID); // IANA ID
580     res[3] = frame;
581     res[4] = page;
582     res[5] = next;
583     res[6] = count;
584     *data_len = SIZE_IANA_ID + 4 + count;
585 
586     return IPMI_CC_OK;
587 }
588 
589 //----------------------------------------------------------------------
590 // Get Debug Control Panel
591 //----------------------------------------------------------------------
592 ipmi_ret_t ipmiOemDbgGetCtrlPanel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
593                                   ipmi_request_t request,
594                                   ipmi_response_t response,
595                                   ipmi_data_len_t data_len,
596                                   ipmi_context_t context)
597 {
598     uint8_t* req = reinterpret_cast<uint8_t*>(request);
599     uint8_t* res = reinterpret_cast<uint8_t*>(response);
600 
601     uint8_t panel;
602     uint8_t operation;
603     uint8_t item;
604     uint8_t count;
605     ipmi_ret_t ret;
606 
607     panel = req[3];
608     operation = req[4];
609     item = req[5];
610 
611     ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
612 
613     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
614     *data_len = SIZE_IANA_ID + count;
615 
616     return ret;
617 }
618 
619 //----------------------------------------------------------------------
620 // Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
621 //----------------------------------------------------------------------
622 ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
623                               ipmi_request_t request, ipmi_response_t response,
624                               ipmi_data_len_t data_len, ipmi_context_t context)
625 {
626     uint8_t* req = reinterpret_cast<uint8_t*>(request);
627 
628     uint8_t index = req[0];
629     uint8_t type = req[1];
630     uint16_t speed;
631     uint32_t size;
632 
633     memcpy(&speed, &req[2], 2);
634     memcpy(&size, &req[4], 4);
635 
636     std::stringstream ss;
637     ss << std::hex;
638     ss << std::setw(2) << std::setfill('0') << (int)index;
639 
640     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
641     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
642     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
643     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
644 
645     flushOemData();
646 
647     *data_len = 0;
648 
649     return IPMI_CC_OK;
650 }
651 
652 //----------------------------------------------------------------------
653 // Get Board ID (CMD_OEM_GET_BOARD_ID)
654 //----------------------------------------------------------------------
655 ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
656                              ipmi_request_t request, ipmi_response_t response,
657                              ipmi_data_len_t data_len, ipmi_context_t context)
658 {
659     uint8_t* req = reinterpret_cast<uint8_t*>(request);
660     uint8_t* res = reinterpret_cast<uint8_t*>(response);
661 
662     /* TODO: Needs to implement this after GPIO implementation */
663     *data_len = 0;
664 
665     return IPMI_CC_OK;
666 }
667 
668 /* Helper functions to set boot order */
669 void setBootOrder(std::string bootObjPath, uint8_t* data,
670                   std::string bootOrderKey)
671 {
672     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
673 
674     // SETTING BOOT MODE PROPERTY
675     uint8_t bootModeBit = data[0] & 0x06;
676     auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit);
677 
678     std::string bootOption =
679         sdbusplus::message::convert_to_string<boot::BootMode>(bootValue);
680 
681     std::string service =
682         getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
683     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
684                     ipmi::boot::bootModeProp, bootOption);
685 
686     // SETTING BOOT SOURCE PROPERTY
687     auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(data[1]);
688     std::string bootSource =
689         sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder);
690 
691     service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
692     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
693                     ipmi::boot::bootSourceProp, bootSource);
694 
695     // SETTING BOOT TYPE PROPERTY
696     uint8_t bootTypeBit = data[0] & 0x01;
697     auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit);
698 
699     std::string bootType =
700         sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal);
701 
702     service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
703 
704     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
705                     ipmi::boot::bootTypeProp, bootType);
706 
707     nlohmann::json bootMode;
708     uint8_t mode = data[0];
709     int i;
710 
711     bootMode["UEFI"] = (mode & BOOT_MODE_UEFI ? true : false);
712     bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR ? true : false);
713     bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT ? true : false);
714     bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG ? true : false);
715     oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
716 
717     /* Initialize boot sequence array */
718     oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
719     for (i = 1; i < SIZE_BOOT_ORDER; i++)
720     {
721         if (data[i] >= BOOT_SEQ_ARRAY_SIZE)
722             oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
723         else
724             oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = bootSeq[data[i]];
725     }
726 
727     flushOemData();
728 }
729 
730 //----------------------------------------------------------------------
731 // Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
732 //----------------------------------------------------------------------
733 ipmi::RspType<std::vector<uint8_t>>
734     ipmiOemSetBootOrder(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
735 {
736 
737     uint8_t bootSeq[SIZE_BOOT_ORDER];
738     size_t len = data.size();
739 
740     if (len != SIZE_BOOT_ORDER)
741     {
742         phosphor::logging::log<phosphor::logging::level::ERR>(
743             "Invalid Boot order length received");
744         return ipmi::responseReqDataLenInvalid();
745     }
746 
747     std::copy(std::begin(data), std::end(data), bootSeq);
748     std::optional<size_t> hostId = ipmi::boot::findHost(ctx->hostIdx);
749 
750     if (!hostId)
751     {
752         phosphor::logging::log<phosphor::logging::level::ERR>(
753             "Invalid Host Id received");
754         return ipmi::responseInvalidCommand();
755     }
756     auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
757 
758     setBootOrder(bootObjPath, bootSeq, hostName);
759 
760     return ipmi::responseSuccess(data);
761 }
762 
763 //----------------------------------------------------------------------
764 // Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
765 //----------------------------------------------------------------------
766 ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>
767     ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
768 {
769     uint8_t bootSeq[SIZE_BOOT_ORDER];
770     uint8_t mode = 0;
771 
772     std::optional<size_t> hostId = ipmi::boot::findHost(ctx->hostIdx);
773 
774     if (!hostId)
775     {
776         phosphor::logging::log<phosphor::logging::level::ERR>(
777             "Invalid Host Id received");
778         return ipmi::responseInvalidCommand();
779     }
780     auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
781 
782     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
783 
784     // GETTING PROPERTY OF MODE INTERFACE
785 
786     std::string service =
787         getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
788     Value variant =
789         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
790                         ipmi::boot::bootModeProp);
791 
792     auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>(
793         std::get<std::string>(variant));
794 
795     uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
796 
797     // GETTING PROPERTY OF SOURCE INTERFACE
798 
799     service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
800     variant =
801         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
802                         ipmi::boot::bootSourceProp);
803 
804     auto bootSource = sdbusplus::message::convert_from_string<boot::BootSource>(
805         std::get<std::string>(variant));
806 
807     uint8_t bootOrder = ipmi::boot::sourceDbusToIpmi.at(bootSource);
808 
809     // GETTING PROPERTY OF TYPE INTERFACE
810 
811     service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
812     variant =
813         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
814                         ipmi::boot::bootTypeProp);
815 
816     auto bootType = sdbusplus::message::convert_from_string<boot::BootType>(
817         std::get<std::string>(variant));
818 
819     uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType);
820 
821     uint8_t bootVal = bootOption | bootTypeVal;
822 
823     if (oemData.find(hostName) == oemData.end())
824     {
825         /* Return default boot order 0100090203ff */
826         uint8_t defaultBoot[SIZE_BOOT_ORDER] = {
827             BOOT_MODE_UEFI,      bootMap["USB_DEV"], bootMap["NET_IPV6"],
828             bootMap["SATA_HDD"], bootMap["SATA_CD"], 0xff};
829 
830         memcpy(bootSeq, defaultBoot, SIZE_BOOT_ORDER);
831         phosphor::logging::log<phosphor::logging::level::INFO>(
832             "Set default boot order");
833         setBootOrder(bootObjPath, defaultBoot, hostName);
834     }
835     else
836     {
837         nlohmann::json bootMode = oemData[hostName][KEY_BOOT_MODE];
838         if (bootMode["UEFI"])
839             mode |= BOOT_MODE_UEFI;
840         if (bootMode["CMOS_CLR"])
841             mode |= BOOT_MODE_CMOS_CLR;
842         if (bootMode["BOOT_FLAG"])
843             mode |= BOOT_MODE_BOOT_FLAG;
844 
845         bootSeq[0] = mode;
846 
847         for (int i = 1; i < SIZE_BOOT_ORDER; i++)
848         {
849             std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
850             if (bootMap.find(seqStr) != bootMap.end())
851                 bootSeq[i] = bootMap[seqStr];
852             else
853                 bootSeq[i] = 0xff;
854         }
855     }
856 
857     return ipmi::responseSuccess(bootVal, bootOrder, bootSeq[2], bootSeq[3],
858                                  bootSeq[4], bootSeq[5]);
859 }
860 // Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
861 //----------------------------------------------------------------------
862 ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
863                                     ipmi_request_t request,
864                                     ipmi_response_t response,
865                                     ipmi_data_len_t data_len,
866                                     ipmi_context_t context)
867 {
868     machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
869     uint8_t len = *data_len;
870 
871     *data_len = 0;
872 
873     if (len < sizeof(machineConfigInfo_t))
874     {
875         phosphor::logging::log<phosphor::logging::level::ERR>(
876             "Invalid machine configuration length received");
877         return IPMI_CC_REQ_DATA_LEN_INVALID;
878     }
879 
880     if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
881         oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
882     else
883         oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
884             chassisType[req->chassis_type];
885 
886     if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
887         oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
888     else
889         oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
890 
891     oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
892     oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
893     oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
894     oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
895 
896     if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
897         oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
898     else
899         oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
900 
901     oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
902     int i = 0;
903     if (req->pcie_card_loc & BIT_0)
904         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
905     if (req->pcie_card_loc & BIT_1)
906         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
907     if (req->pcie_card_loc & BIT_2)
908         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
909     if (req->pcie_card_loc & BIT_3)
910         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
911 
912     if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
913         oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
914     else
915         oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
916             pcieType[req->slot1_pcie_type];
917 
918     if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
919         oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
920     else
921         oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
922             pcieType[req->slot2_pcie_type];
923 
924     if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
925         oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
926     else
927         oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
928             pcieType[req->slot3_pcie_type];
929 
930     if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
931         oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
932     else
933         oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
934             pcieType[req->slot4_pcie_type];
935 
936     oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
937 
938     flushOemData();
939 
940     return IPMI_CC_OK;
941 }
942 
943 //----------------------------------------------------------------------
944 // Set POST start (CMD_OEM_SET_POST_START)
945 //----------------------------------------------------------------------
946 ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
947                                ipmi_request_t request, ipmi_response_t response,
948                                ipmi_data_len_t data_len, ipmi_context_t context)
949 {
950     phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
951 
952     /* Do nothing, return success */
953     *data_len = 0;
954     return IPMI_CC_OK;
955 }
956 
957 //----------------------------------------------------------------------
958 // Set POST End (CMD_OEM_SET_POST_END)
959 //----------------------------------------------------------------------
960 ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
961                              ipmi_request_t request, ipmi_response_t response,
962                              ipmi_data_len_t data_len, ipmi_context_t context)
963 {
964     struct timespec ts;
965 
966     phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
967 
968     *data_len = 0;
969 
970     // Timestamp post end time.
971     clock_gettime(CLOCK_REALTIME, &ts);
972     oemData[KEY_TS_SLED] = ts.tv_sec;
973     flushOemData();
974 
975     // Sync time with system
976     // TODO: Add code for syncing time
977 
978     return IPMI_CC_OK;
979 }
980 
981 //----------------------------------------------------------------------
982 // Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
983 //----------------------------------------------------------------------
984 // Inform BMC about PPIN data of 8 bytes for each CPU
985 //
986 // Request:
987 // Byte 1:8 – CPU0 PPIN data
988 // Optional:
989 // Byte 9:16 – CPU1 PPIN data
990 //
991 // Response:
992 // Byte 1 – Completion Code
993 ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
994                               ipmi_request_t request, ipmi_response_t response,
995                               ipmi_data_len_t data_len, ipmi_context_t context)
996 {
997     uint8_t* req = reinterpret_cast<uint8_t*>(request);
998     std::string ppinStr;
999     int len;
1000 
1001     if (*data_len > SIZE_CPU_PPIN * 2)
1002         len = SIZE_CPU_PPIN * 2;
1003     else
1004         len = *data_len;
1005     *data_len = 0;
1006 
1007     ppinStr = bytesToStr(req, len);
1008     oemData[KEY_PPIN_INFO] = ppinStr.c_str();
1009     flushOemData();
1010 
1011     return IPMI_CC_OK;
1012 }
1013 
1014 //----------------------------------------------------------------------
1015 // Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
1016 //----------------------------------------------------------------------
1017 ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1018                                 ipmi_request_t request,
1019                                 ipmi_response_t response,
1020                                 ipmi_data_len_t data_len,
1021                                 ipmi_context_t context)
1022 {
1023     /* Do nothing, return success */
1024     *data_len = 0;
1025     return IPMI_CC_OK;
1026 }
1027 
1028 // Helper function to set guid at offset in EEPROM
1029 static int setGUID(off_t offset, uint8_t* guid)
1030 {
1031     int fd = -1;
1032     ssize_t len;
1033     int ret = 0;
1034 
1035     errno = 0;
1036 
1037     // Check if file is present
1038     if (access(FRU_EEPROM, F_OK) == -1)
1039     {
1040         std::cerr << "Unable to access: " << FRU_EEPROM << std::endl;
1041         return errno;
1042     }
1043 
1044     // Open the file
1045     fd = open(FRU_EEPROM, O_WRONLY);
1046     if (fd == -1)
1047     {
1048         std::cerr << "Unable to open: " << FRU_EEPROM << std::endl;
1049         return errno;
1050     }
1051 
1052     // seek to the offset
1053     lseek(fd, offset, SEEK_SET);
1054 
1055     // Write bytes to location
1056     len = write(fd, guid, GUID_SIZE);
1057     if (len != GUID_SIZE)
1058     {
1059         phosphor::logging::log<phosphor::logging::level::ERR>(
1060             "GUID write data to EEPROM failed");
1061         ret = errno;
1062     }
1063 
1064     close(fd);
1065     return ret;
1066 }
1067 
1068 //----------------------------------------------------------------------
1069 // Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1070 //----------------------------------------------------------------------
1071 #if BIC_ENABLED
1072 ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx, uint8_t cmdReq,
1073                                      std::vector<uint8_t> reqData)
1074 {
1075     std::vector<uint8_t> respData;
1076 
1077     if (reqData.size() != GUID_SIZE) // 16bytes
1078     {
1079 
1080         return ipmi::responseReqDataLenInvalid();
1081     }
1082 
1083     auto ptrReqData = reqData.insert(reqData.begin(), reqData.size());
1084 
1085     uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1086 
1087     if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1088         return ipmi::responseUnspecifiedError();
1089 
1090     return ipmi::responseSuccess();
1091 }
1092 
1093 #else
1094 ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1095                                 ipmi_request_t request,
1096                                 ipmi_response_t response,
1097                                 ipmi_data_len_t data_len,
1098                                 ipmi_context_t context)
1099 {
1100     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1101 
1102     if (*data_len != GUID_SIZE) // 16bytes
1103     {
1104         *data_len = 0;
1105         return IPMI_CC_REQ_DATA_LEN_INVALID;
1106     }
1107 
1108     *data_len = 0;
1109 
1110     if (setGUID(OFFSET_SYS_GUID, req))
1111     {
1112         return IPMI_CC_UNSPECIFIED_ERROR;
1113     }
1114     return IPMI_CC_OK;
1115 }
1116 #endif
1117 
1118 //----------------------------------------------------------------------
1119 // Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1120 //----------------------------------------------------------------------
1121 ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1122                                    ipmi_request_t request,
1123                                    ipmi_response_t response,
1124                                    ipmi_data_len_t data_len,
1125                                    ipmi_context_t context)
1126 {
1127     /* Do nothing, return success */
1128     *data_len = 0;
1129     return IPMI_CC_OK;
1130 }
1131 
1132 //----------------------------------------------------------------------
1133 // Set PPR (CMD_OEM_SET_PPR)
1134 //----------------------------------------------------------------------
1135 ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1136                          ipmi_request_t request, ipmi_response_t response,
1137                          ipmi_data_len_t data_len, ipmi_context_t context)
1138 {
1139     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1140     uint8_t pprCnt, pprAct, pprIndex;
1141     uint8_t selParam = req[0];
1142     uint8_t len = *data_len;
1143     std::stringstream ss;
1144     std::string str;
1145 
1146     *data_len = 0;
1147 
1148     switch (selParam)
1149     {
1150         case PPR_ACTION:
1151             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1152                 oemData[KEY_PPR].end())
1153                 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1154 
1155             pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1156             if (pprCnt == 0)
1157                 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1158 
1159             pprAct = req[1];
1160             /* Check if ppr is enabled or disabled */
1161             if (!(pprAct & 0x80))
1162                 pprAct = 0;
1163 
1164             oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1165             break;
1166         case PPR_ROW_COUNT:
1167             if (req[1] > 100)
1168                 return IPMI_CC_PARM_OUT_OF_RANGE;
1169 
1170             oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1171             break;
1172         case PPR_ROW_ADDR:
1173             pprIndex = req[1];
1174             if (pprIndex > 100)
1175                 return IPMI_CC_PARM_OUT_OF_RANGE;
1176 
1177             if (len < PPR_ROW_ADDR_LEN + 1)
1178             {
1179                 phosphor::logging::log<phosphor::logging::level::ERR>(
1180                     "Invalid PPR Row Address length received");
1181                 return IPMI_CC_REQ_DATA_LEN_INVALID;
1182             }
1183 
1184             ss << std::hex;
1185             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1186 
1187             oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1188 
1189             str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1190             oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1191             break;
1192         case PPR_HISTORY_DATA:
1193             pprIndex = req[1];
1194             if (pprIndex > 100)
1195                 return IPMI_CC_PARM_OUT_OF_RANGE;
1196 
1197             if (len < PPR_HST_DATA_LEN + 1)
1198             {
1199                 phosphor::logging::log<phosphor::logging::level::ERR>(
1200                     "Invalid PPR history data length received");
1201                 return IPMI_CC_REQ_DATA_LEN_INVALID;
1202             }
1203 
1204             ss << std::hex;
1205             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1206 
1207             oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1208 
1209             str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1210             oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1211             break;
1212         default:
1213             return IPMI_CC_PARM_OUT_OF_RANGE;
1214             break;
1215     }
1216 
1217     flushOemData();
1218 
1219     return IPMI_CC_OK;
1220 }
1221 
1222 //----------------------------------------------------------------------
1223 // Get PPR (CMD_OEM_GET_PPR)
1224 //----------------------------------------------------------------------
1225 ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1226                          ipmi_request_t request, ipmi_response_t response,
1227                          ipmi_data_len_t data_len, ipmi_context_t context)
1228 {
1229     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1230     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1231     uint8_t pprCnt, pprIndex;
1232     uint8_t selParam = req[0];
1233     std::stringstream ss;
1234     std::string str;
1235 
1236     /* Any failure will return zero length data */
1237     *data_len = 0;
1238 
1239     switch (selParam)
1240     {
1241         case PPR_ACTION:
1242             res[0] = 0;
1243             *data_len = 1;
1244 
1245             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1246                 oemData[KEY_PPR].end())
1247             {
1248                 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1249                 if (pprCnt != 0)
1250                 {
1251                     if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1252                         oemData[KEY_PPR].end())
1253                     {
1254                         res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1255                     }
1256                 }
1257             }
1258             break;
1259         case PPR_ROW_COUNT:
1260             res[0] = 0;
1261             *data_len = 1;
1262             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1263                 oemData[KEY_PPR].end())
1264                 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1265             break;
1266         case PPR_ROW_ADDR:
1267             pprIndex = req[1];
1268             if (pprIndex > 100)
1269                 return IPMI_CC_PARM_OUT_OF_RANGE;
1270 
1271             ss << std::hex;
1272             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1273 
1274             if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1275                 return IPMI_CC_PARM_OUT_OF_RANGE;
1276 
1277             if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1278                 oemData[KEY_PPR][ss.str()].end())
1279                 return IPMI_CC_PARM_OUT_OF_RANGE;
1280 
1281             str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1282             *data_len = strToBytes(str, res);
1283             break;
1284         case PPR_HISTORY_DATA:
1285             pprIndex = req[1];
1286             if (pprIndex > 100)
1287                 return IPMI_CC_PARM_OUT_OF_RANGE;
1288 
1289             ss << std::hex;
1290             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1291 
1292             if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1293                 return IPMI_CC_PARM_OUT_OF_RANGE;
1294 
1295             if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1296                 oemData[KEY_PPR][ss.str()].end())
1297                 return IPMI_CC_PARM_OUT_OF_RANGE;
1298 
1299             str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1300             *data_len = strToBytes(str, res);
1301             break;
1302         default:
1303             return IPMI_CC_PARM_OUT_OF_RANGE;
1304             break;
1305     }
1306 
1307     return IPMI_CC_OK;
1308 }
1309 
1310 /* FB OEM QC Commands */
1311 
1312 //----------------------------------------------------------------------
1313 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1314 //----------------------------------------------------------------------
1315 //"Request:
1316 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1317 // Byte 4 – Processor Index, 0 base
1318 // Byte 5 – Parameter Selector
1319 // Byte 6..N – Configuration parameter data (see below for Parameters
1320 // of Processor Information)
1321 // Response:
1322 // Byte 1 – Completion code
1323 //
1324 // Parameter#1: (Processor Product Name)
1325 //
1326 // Byte 1..48 –Product name(ASCII code)
1327 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1328 //
1329 // Param#2: Processor Basic Information
1330 // Byte 1 – Core Number
1331 // Byte 2 – Thread Number (LSB)
1332 // Byte 3 – Thread Number (MSB)
1333 // Byte 4 – Processor frequency in MHz (LSB)
1334 // Byte 5 – Processor frequency in MHz (MSB)
1335 // Byte 6..7 – Revision
1336 //
1337 ipmi_ret_t ipmiOemQSetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1338                                ipmi_request_t request, ipmi_response_t response,
1339                                ipmi_data_len_t data_len, ipmi_context_t context)
1340 {
1341     qProcInfo_t* req = reinterpret_cast<qProcInfo_t*>(request);
1342     uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
1343     std::stringstream ss;
1344     std::string str;
1345     uint8_t len = *data_len;
1346 
1347     *data_len = 0;
1348 
1349     /* check for requested data params */
1350     if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
1351     {
1352         phosphor::logging::log<phosphor::logging::level::ERR>(
1353             "Invalid parameter received");
1354         return IPMI_CC_PARM_OUT_OF_RANGE;
1355     }
1356 
1357     len = len - 5; // Get Actual data length
1358 
1359     ss << std::hex;
1360     ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
1361     oemData[KEY_Q_PROC_INFO][ss.str()][KEY_PROC_INDEX] = req->procIndex;
1362 
1363     str = bytesToStr(req->data, len);
1364     oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]] = str.c_str();
1365     flushOemData();
1366 
1367     return IPMI_CC_OK;
1368 }
1369 
1370 //----------------------------------------------------------------------
1371 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1372 //----------------------------------------------------------------------
1373 // Request:
1374 // Byte 1:3 –  Manufacturer ID – XXYYZZ h, LSB first
1375 // Byte 4 – Processor Index, 0 base
1376 // Byte 5 – Parameter Selector
1377 // Response:
1378 // Byte 1 – Completion code
1379 // Byte 2..N – Configuration Parameter Data (see below for Parameters
1380 // of Processor Information)
1381 //
1382 // Parameter#1: (Processor Product Name)
1383 //
1384 // Byte 1..48 –Product name(ASCII code)
1385 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1386 //
1387 // Param#2: Processor Basic Information
1388 // Byte 1 – Core Number
1389 // Byte 2 – Thread Number (LSB)
1390 // Byte 3 – Thread Number (MSB)
1391 // Byte 4 – Processor frequency in MHz (LSB)
1392 // Byte 5 – Processor frequency in MHz (MSB)
1393 // Byte 6..7 – Revision
1394 //
1395 ipmi_ret_t ipmiOemQGetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1396                                ipmi_request_t request, ipmi_response_t response,
1397                                ipmi_data_len_t data_len, ipmi_context_t context)
1398 {
1399     qProcInfo_t* req = reinterpret_cast<qProcInfo_t*>(request);
1400     uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
1401     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1402     std::stringstream ss;
1403     std::string str;
1404 
1405     *data_len = 0;
1406 
1407     /* check for requested data params */
1408     if (req->paramSel < 1 || req->paramSel >= numParam)
1409     {
1410         phosphor::logging::log<phosphor::logging::level::ERR>(
1411             "Invalid parameter received");
1412         return IPMI_CC_PARM_OUT_OF_RANGE;
1413     }
1414 
1415     ss << std::hex;
1416     ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
1417 
1418     if (oemData[KEY_Q_PROC_INFO].find(ss.str()) ==
1419         oemData[KEY_Q_PROC_INFO].end())
1420         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1421 
1422     if (oemData[KEY_Q_PROC_INFO][ss.str()].find(cpuInfoKey[req->paramSel]) ==
1423         oemData[KEY_Q_PROC_INFO][ss.str()].end())
1424         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1425 
1426     str = oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]];
1427     *data_len = strToBytes(str, res);
1428 
1429     return IPMI_CC_OK;
1430 }
1431 
1432 //----------------------------------------------------------------------
1433 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1434 //----------------------------------------------------------------------
1435 // Request:
1436 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1437 // Byte 4 – DIMM Index, 0 base
1438 // Byte 5 – Parameter Selector
1439 // Byte 6..N – Configuration parameter data (see below for Parameters
1440 // of DIMM Information)
1441 // Response:
1442 // Byte 1 – Completion code
1443 //
1444 // Param#1 (DIMM Location):
1445 // Byte 1 – DIMM Present
1446 // Byte 1 – DIMM Present
1447 // 01h – Present
1448 // FFh – Not Present
1449 // Byte 2 – Node Number, 0 base
1450 // Byte 3 – Channel Number , 0 base
1451 // Byte 4 – DIMM Number , 0 base
1452 //
1453 // Param#2 (DIMM Type):
1454 // Byte 1 – DIMM Type
1455 // Bit [7:6]
1456 // For DDR3
1457 //  00 – Normal Voltage (1.5V)
1458 //  01 – Ultra Low Voltage (1.25V)
1459 //  10 – Low Voltage (1.35V)
1460 //  11 – Reserved
1461 // For DDR4
1462 //  00 – Reserved
1463 //  01 – Reserved
1464 //  10 – Reserved
1465 //  11 – Normal Voltage (1.2V)
1466 // Bit [5:0]
1467 //  0x00 – SDRAM
1468 //  0x01 – DDR-1 RAM
1469 //  0x02 – Rambus
1470 //  0x03 – DDR-2 RAM
1471 //  0x04 – FBDIMM
1472 //  0x05 – DDR-3 RAM
1473 //  0x06 – DDR-4 RAM
1474 //
1475 // Param#3 (DIMM Speed):
1476 // Byte 1..2 – DIMM speed in MHz, LSB
1477 // Byte 3..6 – DIMM size in Mbytes, LSB
1478 //
1479 // Param#4 (Module Part Number):
1480 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1481 //
1482 // Param#5 (Module Serial Number):
1483 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1484 //
1485 // Param#6 (Module Manufacturer ID):
1486 // Byte 1 - Module Manufacturer ID, LSB
1487 // Byte 2 - Module Manufacturer ID, MSB
1488 //
1489 ipmi_ret_t ipmiOemQSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1490                                ipmi_request_t request, ipmi_response_t response,
1491                                ipmi_data_len_t data_len, ipmi_context_t context)
1492 {
1493     qDimmInfo_t* req = reinterpret_cast<qDimmInfo_t*>(request);
1494     uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
1495     std::stringstream ss;
1496     std::string str;
1497     uint8_t len = *data_len;
1498 
1499     *data_len = 0;
1500 
1501     /* check for requested data params */
1502     if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
1503     {
1504         phosphor::logging::log<phosphor::logging::level::ERR>(
1505             "Invalid parameter received");
1506         return IPMI_CC_PARM_OUT_OF_RANGE;
1507     }
1508 
1509     len = len - 5; // Get Actual data length
1510 
1511     ss << std::hex;
1512     ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
1513     oemData[KEY_Q_DIMM_INFO][ss.str()][KEY_DIMM_INDEX] = req->dimmIndex;
1514 
1515     str = bytesToStr(req->data, len);
1516     oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]] =
1517         str.c_str();
1518     flushOemData();
1519 
1520     return IPMI_CC_OK;
1521 }
1522 
1523 //----------------------------------------------------------------------
1524 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1525 //----------------------------------------------------------------------
1526 // Request:
1527 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1528 // Byte 4 – DIMM Index, 0 base
1529 // Byte 5 – Parameter Selector
1530 // Byte 6..N – Configuration parameter data (see below for Parameters
1531 // of DIMM Information)
1532 // Response:
1533 // Byte 1 – Completion code
1534 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1535 // of DIMM Information)
1536 //
1537 // Param#1 (DIMM Location):
1538 // Byte 1 – DIMM Present
1539 // Byte 1 – DIMM Present
1540 // 01h – Present
1541 // FFh – Not Present
1542 // Byte 2 – Node Number, 0 base
1543 // Byte 3 – Channel Number , 0 base
1544 // Byte 4 – DIMM Number , 0 base
1545 //
1546 // Param#2 (DIMM Type):
1547 // Byte 1 – DIMM Type
1548 // Bit [7:6]
1549 // For DDR3
1550 //  00 – Normal Voltage (1.5V)
1551 //  01 – Ultra Low Voltage (1.25V)
1552 //  10 – Low Voltage (1.35V)
1553 //  11 – Reserved
1554 // For DDR4
1555 //  00 – Reserved
1556 //  01 – Reserved
1557 //  10 – Reserved
1558 //  11 – Normal Voltage (1.2V)
1559 // Bit [5:0]
1560 //  0x00 – SDRAM
1561 //  0x01 – DDR-1 RAM
1562 //  0x02 – Rambus
1563 //  0x03 – DDR-2 RAM
1564 //  0x04 – FBDIMM
1565 //  0x05 – DDR-3 RAM
1566 //  0x06 – DDR-4 RAM
1567 //
1568 // Param#3 (DIMM Speed):
1569 // Byte 1..2 – DIMM speed in MHz, LSB
1570 // Byte 3..6 – DIMM size in Mbytes, LSB
1571 //
1572 // Param#4 (Module Part Number):
1573 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1574 //
1575 // Param#5 (Module Serial Number):
1576 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1577 //
1578 // Param#6 (Module Manufacturer ID):
1579 // Byte 1 - Module Manufacturer ID, LSB
1580 // Byte 2 - Module Manufacturer ID, MSB
1581 //
1582 ipmi_ret_t ipmiOemQGetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1583                                ipmi_request_t request, ipmi_response_t response,
1584                                ipmi_data_len_t data_len, ipmi_context_t context)
1585 {
1586     qDimmInfo_t* req = reinterpret_cast<qDimmInfo_t*>(request);
1587     uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
1588     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1589     std::stringstream ss;
1590     std::string str;
1591 
1592     *data_len = 0;
1593 
1594     /* check for requested data params */
1595     if (req->paramSel < 1 || req->paramSel >= numParam)
1596     {
1597         phosphor::logging::log<phosphor::logging::level::ERR>(
1598             "Invalid parameter received");
1599         return IPMI_CC_PARM_OUT_OF_RANGE;
1600     }
1601 
1602     ss << std::hex;
1603     ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
1604 
1605     if (oemData[KEY_Q_DIMM_INFO].find(ss.str()) ==
1606         oemData[KEY_Q_DIMM_INFO].end())
1607         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1608 
1609     if (oemData[KEY_Q_DIMM_INFO][ss.str()].find(dimmInfoKey[req->paramSel]) ==
1610         oemData[KEY_Q_DIMM_INFO][ss.str()].end())
1611         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1612 
1613     str = oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]];
1614     *data_len = strToBytes(str, res);
1615 
1616     return IPMI_CC_OK;
1617 }
1618 
1619 //----------------------------------------------------------------------
1620 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
1621 //----------------------------------------------------------------------
1622 // BIOS issue this command to provide HDD information to BMC.
1623 //
1624 // BIOS just can get information by standard ATA / SMART command for
1625 // OB SATA controller.
1626 // BIOS can get
1627 // 1.     Serial Number
1628 // 2.     Model Name
1629 // 3.     HDD FW Version
1630 // 4.     HDD Capacity
1631 // 5.     HDD WWN
1632 //
1633 //  Use Get HDD info Param #5 to know the MAX HDD info index.
1634 //
1635 //  Request:
1636 //  Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1637 //  Byte 4 –
1638 //  [7:4] Reserved
1639 //  [3:0] HDD Controller Type
1640 //     0x00 – BIOS
1641 //     0x01 – Expander
1642 //     0x02 – LSI
1643 //  Byte 5 – HDD Info Index, 0 base
1644 //  Byte 6 – Parameter Selector
1645 //  Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
1646 //  Information)
1647 //
1648 //  Response:
1649 //  Byte 1 – Completion Code
1650 //
1651 //  Param#0 (HDD Location):
1652 //  Byte 1 – Controller
1653 //    [7:3] Device Number
1654 //    [2:0] Function Number
1655 //  For Intel C610 series (Wellsburg)
1656 //    D31:F2 (0xFA) – SATA control 1
1657 //    D31:F5 (0xFD) – SATA control 2
1658 //    D17:F4 (0x8C) – sSata control
1659 //  Byte 2 – Port Number
1660 //  Byte 3 – Location (0xFF: No HDD Present)
1661 //  BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
1662 //  #1~4, #6,  #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
1663 //  the HDD present. BMC or other people who know the HDD location has
1664 //  responsibility for update Location info
1665 //
1666 //  Param#1 (Serial Number):
1667 //  Bytes 1..33: HDD Serial Number
1668 //
1669 //  Param#2 (Model Name):
1670 //  Byte 1..33 – HDD Model Name
1671 //
1672 //  Param#3 (HDD FW Version):
1673 //  Byte 1..17 –HDD FW version
1674 //
1675 //  Param#4 (Capacity):
1676 //  Byte 1..4 –HDD Block Size, LSB
1677 //  Byte 5..12 - HDD Block Number, LSB
1678 //  HDD Capacity = HDD Block size * HDD BLock number  (Unit Byte)
1679 //
1680 //  Param#5 (Max HDD Quantity):
1681 //  Byte 1 - Max HDD Quantity
1682 //  Max supported port numbers in this PCH
1683 //
1684 //  Param#6 (HDD Type)
1685 //  Byte 1 – HDD Type
1686 //  0h – Reserved
1687 //  1h – SAS
1688 //  2h – SATA
1689 //  3h – PCIE SSD (NVME)
1690 //
1691 //  Param#7 (HDD WWN)
1692 //  Data 1...8: HDD World Wide Name, LSB
1693 //
1694 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1695                                 ipmi_request_t request,
1696                                 ipmi_response_t response,
1697                                 ipmi_data_len_t data_len,
1698                                 ipmi_context_t context)
1699 {
1700     qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1701     uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1702     uint8_t ctrlType = req->hddCtrlType & 0x0f;
1703     std::stringstream ss;
1704     std::string str;
1705     uint8_t len = *data_len;
1706 
1707     *data_len = 0;
1708 
1709     /* check for requested data params */
1710     if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam ||
1711         ctrlType > 2)
1712     {
1713         phosphor::logging::log<phosphor::logging::level::ERR>(
1714             "Invalid parameter received");
1715         return IPMI_CC_PARM_OUT_OF_RANGE;
1716     }
1717 
1718     len = len - 6; // Get Actual data length
1719 
1720     ss << std::hex;
1721     ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1722     oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
1723     oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
1724         req->hddIndex;
1725 
1726     str = bytesToStr(req->data, len);
1727     oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1728            [driveInfoKey[req->paramSel]] = str.c_str();
1729     flushOemData();
1730 
1731     return IPMI_CC_OK;
1732 }
1733 
1734 //----------------------------------------------------------------------
1735 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
1736 //----------------------------------------------------------------------
1737 // BMC needs to check HDD presented or not first. If NOT presented, return
1738 // completion code 0xD5.
1739 //
1740 // Request:
1741 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1742 // Byte 4 –
1743 //[7:4] Reserved
1744 //[3:0] HDD Controller Type
1745 //   0x00 – BIOS
1746 //   0x01 – Expander
1747 //   0x02 – LSI
1748 // Byte 5 – HDD Index, 0 base
1749 // Byte 6 – Parameter Selector (See Above Set HDD Information)
1750 // Response:
1751 // Byte 1 – Completion Code
1752 //   0xD5 – Not support in current status (HDD Not Present)
1753 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
1754 // Information)
1755 //
1756 ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1757                                 ipmi_request_t request,
1758                                 ipmi_response_t response,
1759                                 ipmi_data_len_t data_len,
1760                                 ipmi_context_t context)
1761 {
1762     qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1763     uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1764     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1765     uint8_t ctrlType = req->hddCtrlType & 0x0f;
1766     std::stringstream ss;
1767     std::string str;
1768 
1769     *data_len = 0;
1770 
1771     /* check for requested data params */
1772     if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2)
1773     {
1774         phosphor::logging::log<phosphor::logging::level::ERR>(
1775             "Invalid parameter received");
1776         return IPMI_CC_PARM_OUT_OF_RANGE;
1777     }
1778 
1779     if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
1780         oemData[KEY_Q_DRIVE_INFO].end())
1781         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1782 
1783     ss << std::hex;
1784     ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1785 
1786     if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
1787         oemData[KEY_Q_DRIVE_INFO].end())
1788         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1789 
1790     if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
1791             dimmInfoKey[req->paramSel]) ==
1792         oemData[KEY_Q_DRIVE_INFO][ss.str()].end())
1793         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1794 
1795     str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1796                  [dimmInfoKey[req->paramSel]];
1797     *data_len = strToBytes(str, res);
1798 
1799     return IPMI_CC_OK;
1800 }
1801 
1802 /* Helper function for sending DCMI commands to ME and getting response back */
1803 ipmi::RspType<std::vector<uint8_t>> sendDCMICmd(uint8_t cmd,
1804                                                 std::vector<uint8_t>& cmdData)
1805 {
1806     std::vector<uint8_t> respData;
1807 
1808     /* Add group id as first byte to request for ME command */
1809     cmdData.insert(cmdData.begin(), groupDCMI);
1810 
1811     if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
1812         return ipmi::responseUnspecifiedError();
1813 
1814     /* Remove group id as first byte as it will be added by IPMID */
1815     respData.erase(respData.begin());
1816 
1817     return ipmi::responseSuccess(std::move(respData));
1818 }
1819 
1820 /* DCMI Command handellers. */
1821 
1822 ipmi::RspType<std::vector<uint8_t>>
1823     ipmiOemDCMIGetPowerReading(std::vector<uint8_t> reqData)
1824 {
1825     return sendDCMICmd(ipmi::dcmi::cmdGetPowerReading, reqData);
1826 }
1827 
1828 ipmi::RspType<std::vector<uint8_t>>
1829     ipmiOemDCMIGetPowerLimit(std::vector<uint8_t> reqData)
1830 {
1831     return sendDCMICmd(ipmi::dcmi::cmdGetPowerLimit, reqData);
1832 }
1833 
1834 ipmi::RspType<std::vector<uint8_t>>
1835     ipmiOemDCMISetPowerLimit(std::vector<uint8_t> reqData)
1836 {
1837     return sendDCMICmd(ipmi::dcmi::cmdSetPowerLimit, reqData);
1838 }
1839 
1840 ipmi::RspType<std::vector<uint8_t>>
1841     ipmiOemDCMIApplyPowerLimit(std::vector<uint8_t> reqData)
1842 {
1843     return sendDCMICmd(ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
1844 }
1845 
1846 static void registerOEMFunctions(void)
1847 {
1848     /* Get OEM data from json file */
1849     std::ifstream file(JSON_OEM_DATA_FILE);
1850     if (file)
1851     {
1852         file >> oemData;
1853         file.close();
1854     }
1855 
1856     phosphor::logging::log<phosphor::logging::level::INFO>(
1857         "Registering OEM commands");
1858 
1859     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
1860                          NULL, ipmiOemDbgGetFrameInfo,
1861                          PRIVILEGE_USER); // get debug frame info
1862     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
1863                          CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
1864                          ipmiOemDbgGetUpdFrames,
1865                          PRIVILEGE_USER); // get debug updated frames
1866     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
1867                          NULL, ipmiOemDbgGetPostDesc,
1868                          PRIVILEGE_USER); // get debug post description
1869     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
1870                          NULL, ipmiOemDbgGetGpioDesc,
1871                          PRIVILEGE_USER); // get debug gpio description
1872     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
1873                          NULL, ipmiOemDbgGetFrameData,
1874                          PRIVILEGE_USER); // get debug frame data
1875     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
1876                          NULL, ipmiOemDbgGetCtrlPanel,
1877                          PRIVILEGE_USER); // get debug control panel
1878     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
1879                          ipmiOemSetDimmInfo,
1880                          PRIVILEGE_USER); // Set Dimm Info
1881     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL,
1882                          ipmiOemGetBoardID,
1883                          PRIVILEGE_USER); // Get Board ID
1884     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL,
1885                          ipmiOemSetMachineCfgInfo,
1886                          PRIVILEGE_USER); // Set Machine Config Info
1887     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL,
1888                          ipmiOemSetPostStart,
1889                          PRIVILEGE_USER); // Set POST start
1890     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
1891                          ipmiOemSetPostEnd,
1892                          PRIVILEGE_USER); // Set POST End
1893     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL,
1894                          ipmiOemSetPPINInfo,
1895                          PRIVILEGE_USER); // Set PPIN Info
1896 #if BIC_ENABLED
1897 
1898     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1899                           ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
1900                           ipmiOemSetSystemGuid);
1901 #else
1902 
1903     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL,
1904                          ipmiOemSetSystemGuid,
1905                          PRIVILEGE_USER); // Set System GUID
1906 #endif
1907     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL,
1908                          ipmiOemSetAdrTrigger,
1909                          PRIVILEGE_USER); // Set ADR Trigger
1910     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
1911                          ipmiOemSetBiosFlashInfo,
1912                          PRIVILEGE_USER); // Set Bios Flash Info
1913     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr,
1914                          PRIVILEGE_USER); // Set PPR
1915     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
1916                          PRIVILEGE_USER); // Get PPR
1917     /* FB OEM QC Commands */
1918     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_PROC_INFO, NULL,
1919                          ipmiOemQSetProcInfo,
1920                          PRIVILEGE_USER); // Set Proc Info
1921     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_PROC_INFO, NULL,
1922                          ipmiOemQGetProcInfo,
1923                          PRIVILEGE_USER); // Get Proc Info
1924     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DIMM_INFO, NULL,
1925                          ipmiOemQSetDimmInfo,
1926                          PRIVILEGE_USER); // Set Dimm Info
1927     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DIMM_INFO, NULL,
1928                          ipmiOemQGetDimmInfo,
1929                          PRIVILEGE_USER); // Get Dimm Info
1930     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
1931                          ipmiOemQSetDriveInfo,
1932                          PRIVILEGE_USER); // Set Drive Info
1933     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
1934                          ipmiOemQGetDriveInfo,
1935                          PRIVILEGE_USER); // Get Drive Info
1936 
1937     /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
1938     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1939                                ipmi::dcmi::cmdGetPowerReading,
1940                                ipmi::Privilege::User,
1941                                ipmiOemDCMIGetPowerReading); // Get Power Reading
1942 
1943     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1944                                ipmi::dcmi::cmdGetPowerLimit,
1945                                ipmi::Privilege::User,
1946                                ipmiOemDCMIGetPowerLimit); // Get Power Limit
1947 
1948     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1949                                ipmi::dcmi::cmdSetPowerLimit,
1950                                ipmi::Privilege::Operator,
1951                                ipmiOemDCMISetPowerLimit); // Set Power Limit
1952 
1953     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1954                                ipmi::dcmi::cmdActDeactivatePwrLimit,
1955                                ipmi::Privilege::Operator,
1956                                ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
1957 
1958     /* FB OEM BOOT ORDER COMMANDS */
1959     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1960                           CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
1961                           ipmiOemGetBootOrder); // Get Boot Order
1962 
1963     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1964                           CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
1965                           ipmiOemSetBootOrder); // Set Boot Order
1966 
1967     return;
1968 }
1969 
1970 } // namespace ipmi
1971