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