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