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