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