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