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