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