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