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