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