12c07f6f0SAndrew Jeffery // SPDX-License-Identifier: Apache-2.0 22c07f6f0SAndrew Jeffery // Copyright (C) 2018 IBM Corp. 32c07f6f0SAndrew Jeffery 42c07f6f0SAndrew Jeffery #include "config.h" 52c07f6f0SAndrew Jeffery 62c07f6f0SAndrew Jeffery #include "hiomap.hpp" 72c07f6f0SAndrew Jeffery 82c07f6f0SAndrew Jeffery #include <endian.h> 92c07f6f0SAndrew Jeffery #include <host-ipmid/ipmid-api.h> 102c07f6f0SAndrew Jeffery 11*ee70196bSPatrick Venture #include <cstring> 122c07f6f0SAndrew Jeffery #include <fstream> 130a3358e7SAndrew Jeffery #include <functional> 140a3358e7SAndrew Jeffery #include <host-ipmid/ipmid-host-cmd-utils.hpp> 150a3358e7SAndrew Jeffery #include <host-ipmid/ipmid-host-cmd.hpp> 160a3358e7SAndrew Jeffery #include <iostream> 17*ee70196bSPatrick Venture #include <map> 180a3358e7SAndrew Jeffery #include <phosphor-logging/log.hpp> 192c07f6f0SAndrew Jeffery #include <sdbusplus/bus.hpp> 200a3358e7SAndrew Jeffery #include <sdbusplus/bus/match.hpp> 212c07f6f0SAndrew Jeffery #include <sdbusplus/exception.hpp> 22*ee70196bSPatrick Venture #include <string> 23*ee70196bSPatrick Venture #include <tuple> 24*ee70196bSPatrick Venture #include <utility> 252c07f6f0SAndrew Jeffery 262c07f6f0SAndrew Jeffery using namespace sdbusplus; 270a3358e7SAndrew Jeffery using namespace phosphor::host::command; 282c07f6f0SAndrew Jeffery 292c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() __attribute__((constructor)); 302c07f6f0SAndrew Jeffery 312c07f6f0SAndrew Jeffery namespace openpower 322c07f6f0SAndrew Jeffery { 332c07f6f0SAndrew Jeffery namespace flash 342c07f6f0SAndrew Jeffery { 350a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_DAEMON_READY = 1 << 7; 360a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_FLASH_CTRL_LOST = 1 << 6; 370a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_WINDOW_RESET = 1 << 1; 380a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_PROTOCOL_RESET = 1 << 0; 390a3358e7SAndrew Jeffery 400a3358e7SAndrew Jeffery constexpr auto IPMI_CMD_HIOMAP_EVENT = 0x0f; 410a3358e7SAndrew Jeffery 420a3358e7SAndrew Jeffery constexpr auto HIOMAPD_SERVICE = "xyz.openbmc_project.Hiomapd"; 430a3358e7SAndrew Jeffery constexpr auto HIOMAPD_OBJECT = "/xyz/openbmc_project/Hiomapd"; 440a3358e7SAndrew Jeffery constexpr auto HIOMAPD_IFACE = "xyz.openbmc_project.Hiomapd.Protocol"; 450a3358e7SAndrew Jeffery constexpr auto HIOMAPD_IFACE_V2 = "xyz.openbmc_project.Hiomapd.Protocol.V2"; 460a3358e7SAndrew Jeffery 470a3358e7SAndrew Jeffery constexpr auto DBUS_IFACE_PROPERTIES = "org.freedesktop.DBus.Properties"; 480a3358e7SAndrew Jeffery 490a3358e7SAndrew Jeffery struct hiomap 500a3358e7SAndrew Jeffery { 510a3358e7SAndrew Jeffery bus::bus* bus; 520a3358e7SAndrew Jeffery 530a3358e7SAndrew Jeffery /* Signals */ 540a3358e7SAndrew Jeffery bus::match::match* properties; 550a3358e7SAndrew Jeffery bus::match::match* window_reset; 560a3358e7SAndrew Jeffery bus::match::match* bmc_reboot; 570a3358e7SAndrew Jeffery 580a3358e7SAndrew Jeffery /* Protocol state */ 590a3358e7SAndrew Jeffery std::map<std::string, int> event_lookup; 600a3358e7SAndrew Jeffery uint8_t bmc_events; 6104d75136SAndrew Jeffery uint8_t seq; 620a3358e7SAndrew Jeffery }; 632c07f6f0SAndrew Jeffery 642c07f6f0SAndrew Jeffery /* TODO: Replace get/put with packed structs and direct assignment */ 655b355068SPatrick Venture template <typename T> 665b355068SPatrick Venture static inline T get(void* buf) 672c07f6f0SAndrew Jeffery { 682c07f6f0SAndrew Jeffery T t; 69*ee70196bSPatrick Venture std::memcpy(&t, buf, sizeof(t)); 702c07f6f0SAndrew Jeffery return t; 712c07f6f0SAndrew Jeffery } 722c07f6f0SAndrew Jeffery 735b355068SPatrick Venture template <typename T> 745b355068SPatrick Venture static inline void put(void* buf, T&& t) 752c07f6f0SAndrew Jeffery { 76*ee70196bSPatrick Venture std::memcpy(buf, &t, sizeof(t)); 772c07f6f0SAndrew Jeffery } 782c07f6f0SAndrew Jeffery 792c07f6f0SAndrew Jeffery typedef ipmi_ret_t (*hiomap_command)(ipmi_request_t req, ipmi_response_t resp, 802c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 812c07f6f0SAndrew Jeffery ipmi_context_t context); 822c07f6f0SAndrew Jeffery 832c07f6f0SAndrew Jeffery struct errno_cc_entry 842c07f6f0SAndrew Jeffery { 852c07f6f0SAndrew Jeffery int err; 862c07f6f0SAndrew Jeffery int cc; 872c07f6f0SAndrew Jeffery }; 882c07f6f0SAndrew Jeffery 892c07f6f0SAndrew Jeffery static const errno_cc_entry errno_cc_map[] = { 902c07f6f0SAndrew Jeffery {0, IPMI_CC_OK}, 912c07f6f0SAndrew Jeffery {EBUSY, IPMI_CC_BUSY}, 922c07f6f0SAndrew Jeffery {ENOTSUP, IPMI_CC_INVALID}, 932c07f6f0SAndrew Jeffery {ETIMEDOUT, 0xc3}, /* FIXME: Replace when defined in ipmid-api.h */ 942c07f6f0SAndrew Jeffery {ENOSPC, 0xc4}, /* FIXME: Replace when defined in ipmid-api.h */ 952c07f6f0SAndrew Jeffery {EINVAL, IPMI_CC_PARM_OUT_OF_RANGE}, 962c07f6f0SAndrew Jeffery {ENODEV, IPMI_CC_SENSOR_INVALID}, 972c07f6f0SAndrew Jeffery {EPERM, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 982c07f6f0SAndrew Jeffery {EACCES, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 992c07f6f0SAndrew Jeffery {-1, IPMI_CC_UNSPECIFIED_ERROR}, 1002c07f6f0SAndrew Jeffery }; 1012c07f6f0SAndrew Jeffery 1022c07f6f0SAndrew Jeffery static int hiomap_xlate_errno(int err) 1032c07f6f0SAndrew Jeffery { 1042c07f6f0SAndrew Jeffery const errno_cc_entry* entry = &errno_cc_map[0]; 1052c07f6f0SAndrew Jeffery 1062c07f6f0SAndrew Jeffery while (!(entry->err == err || entry->err == -1)) 1072c07f6f0SAndrew Jeffery { 1082c07f6f0SAndrew Jeffery entry++; 1092c07f6f0SAndrew Jeffery } 1102c07f6f0SAndrew Jeffery 1112c07f6f0SAndrew Jeffery return entry->cc; 1122c07f6f0SAndrew Jeffery } 1132c07f6f0SAndrew Jeffery 1140a3358e7SAndrew Jeffery static void ipmi_hiomap_event_response(IpmiCmdData cmd, bool status) 1150a3358e7SAndrew Jeffery { 1160a3358e7SAndrew Jeffery using namespace phosphor::logging; 1170a3358e7SAndrew Jeffery 1180a3358e7SAndrew Jeffery if (!status) 1190a3358e7SAndrew Jeffery { 1200a3358e7SAndrew Jeffery log<level::ERR>("Failed to deliver host command", 1210a3358e7SAndrew Jeffery entry("SEL_COMMAND=%x:%x", cmd.first, cmd.second)); 1220a3358e7SAndrew Jeffery } 1230a3358e7SAndrew Jeffery } 1240a3358e7SAndrew Jeffery 1250a3358e7SAndrew Jeffery static int hiomap_handle_property_update(struct hiomap* ctx, 1260a3358e7SAndrew Jeffery sdbusplus::message::message& msg) 1270a3358e7SAndrew Jeffery { 1280a3358e7SAndrew Jeffery std::map<std::string, sdbusplus::message::variant<bool>> msgData; 1290a3358e7SAndrew Jeffery 1300a3358e7SAndrew Jeffery std::string iface; 1310a3358e7SAndrew Jeffery msg.read(iface, msgData); 1320a3358e7SAndrew Jeffery 1330a3358e7SAndrew Jeffery for (auto const& x : msgData) 1340a3358e7SAndrew Jeffery { 1350a3358e7SAndrew Jeffery if (!ctx->event_lookup.count(x.first)) 1360a3358e7SAndrew Jeffery { 1370a3358e7SAndrew Jeffery /* Unsupported event? */ 1380a3358e7SAndrew Jeffery continue; 1390a3358e7SAndrew Jeffery } 1400a3358e7SAndrew Jeffery 1410a3358e7SAndrew Jeffery uint8_t mask = ctx->event_lookup[x.first]; 1420a3358e7SAndrew Jeffery auto value = sdbusplus::message::variant_ns::get<bool>(x.second); 1430a3358e7SAndrew Jeffery 1440a3358e7SAndrew Jeffery if (value) 1450a3358e7SAndrew Jeffery { 1460a3358e7SAndrew Jeffery ctx->bmc_events |= mask; 1470a3358e7SAndrew Jeffery } 1480a3358e7SAndrew Jeffery else 1490a3358e7SAndrew Jeffery { 1500a3358e7SAndrew Jeffery ctx->bmc_events &= ~mask; 1510a3358e7SAndrew Jeffery } 1520a3358e7SAndrew Jeffery } 1530a3358e7SAndrew Jeffery 1540a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 1550a3358e7SAndrew Jeffery 1560a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 1570a3358e7SAndrew Jeffery 1580a3358e7SAndrew Jeffery return 0; 1590a3358e7SAndrew Jeffery } 1600a3358e7SAndrew Jeffery 1610a3358e7SAndrew Jeffery static bus::match::match hiomap_match_properties(struct hiomap* ctx) 1620a3358e7SAndrew Jeffery { 1630a3358e7SAndrew Jeffery auto properties = 1640a3358e7SAndrew Jeffery bus::match::rules::propertiesChanged(HIOMAPD_OBJECT, HIOMAPD_IFACE_V2); 1650a3358e7SAndrew Jeffery 1660a3358e7SAndrew Jeffery bus::match::match match( 1670a3358e7SAndrew Jeffery *ctx->bus, properties, 1680a3358e7SAndrew Jeffery std::bind(hiomap_handle_property_update, ctx, std::placeholders::_1)); 1690a3358e7SAndrew Jeffery 1700a3358e7SAndrew Jeffery return match; 1710a3358e7SAndrew Jeffery } 1720a3358e7SAndrew Jeffery 1730a3358e7SAndrew Jeffery static int hiomap_handle_signal_v2(struct hiomap* ctx, const char* name) 1740a3358e7SAndrew Jeffery { 1750a3358e7SAndrew Jeffery ctx->bmc_events |= ctx->event_lookup[name]; 1760a3358e7SAndrew Jeffery 1770a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 1780a3358e7SAndrew Jeffery 1790a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 1800a3358e7SAndrew Jeffery 1810a3358e7SAndrew Jeffery return 0; 1820a3358e7SAndrew Jeffery } 1830a3358e7SAndrew Jeffery 1840a3358e7SAndrew Jeffery static bus::match::match hiomap_match_signal_v2(struct hiomap* ctx, 1850a3358e7SAndrew Jeffery const char* name) 1860a3358e7SAndrew Jeffery { 1870a3358e7SAndrew Jeffery using namespace bus::match; 1880a3358e7SAndrew Jeffery 1890a3358e7SAndrew Jeffery auto signals = rules::type::signal() + rules::path(HIOMAPD_OBJECT) + 1900a3358e7SAndrew Jeffery rules::interface(HIOMAPD_IFACE_V2) + rules::member(name); 1910a3358e7SAndrew Jeffery 1920a3358e7SAndrew Jeffery bus::match::match match(*ctx->bus, signals, 1930a3358e7SAndrew Jeffery std::bind(hiomap_handle_signal_v2, ctx, name)); 1940a3358e7SAndrew Jeffery 1950a3358e7SAndrew Jeffery return match; 1960a3358e7SAndrew Jeffery } 1970a3358e7SAndrew Jeffery 1980a3358e7SAndrew Jeffery static ipmi_ret_t hiomap_reset(ipmi_request_t request, ipmi_response_t response, 1990a3358e7SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 2000a3358e7SAndrew Jeffery { 2010a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 2020a3358e7SAndrew Jeffery 2030a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 2040a3358e7SAndrew Jeffery HIOMAPD_IFACE, "Reset"); 2050a3358e7SAndrew Jeffery try 2060a3358e7SAndrew Jeffery { 2070a3358e7SAndrew Jeffery ctx->bus->call(m); 2080a3358e7SAndrew Jeffery 2090a3358e7SAndrew Jeffery *data_len = 0; 2100a3358e7SAndrew Jeffery } 2110a3358e7SAndrew Jeffery catch (const exception::SdBusError& e) 2120a3358e7SAndrew Jeffery { 2130a3358e7SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 2140a3358e7SAndrew Jeffery } 2150a3358e7SAndrew Jeffery 2160a3358e7SAndrew Jeffery return IPMI_CC_OK; 2170a3358e7SAndrew Jeffery } 2180a3358e7SAndrew Jeffery 2192c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_get_info(ipmi_request_t request, 2202c07f6f0SAndrew Jeffery ipmi_response_t response, 2212c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 2222c07f6f0SAndrew Jeffery ipmi_context_t context) 2232c07f6f0SAndrew Jeffery { 2240a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 2250a3358e7SAndrew Jeffery 2262c07f6f0SAndrew Jeffery if (*data_len < 1) 2272c07f6f0SAndrew Jeffery { 2282c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 2292c07f6f0SAndrew Jeffery } 2302c07f6f0SAndrew Jeffery 2312c07f6f0SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 2320a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 2330a3358e7SAndrew Jeffery HIOMAPD_IFACE, "GetInfo"); 2342c07f6f0SAndrew Jeffery m.append(reqdata[0]); 2352c07f6f0SAndrew Jeffery 2362c07f6f0SAndrew Jeffery try 2372c07f6f0SAndrew Jeffery { 2380a3358e7SAndrew Jeffery auto reply = ctx->bus->call(m); 2392c07f6f0SAndrew Jeffery 2402c07f6f0SAndrew Jeffery uint8_t version; 2412c07f6f0SAndrew Jeffery uint8_t blockSizeShift; 2422c07f6f0SAndrew Jeffery uint16_t timeout; 2432c07f6f0SAndrew Jeffery reply.read(version, blockSizeShift, timeout); 2442c07f6f0SAndrew Jeffery 2452c07f6f0SAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 2462c07f6f0SAndrew Jeffery 2472c07f6f0SAndrew Jeffery /* FIXME: Assumes v2! */ 2482c07f6f0SAndrew Jeffery put(&respdata[0], version); 2492c07f6f0SAndrew Jeffery put(&respdata[1], blockSizeShift); 2502c07f6f0SAndrew Jeffery put(&respdata[2], htole16(timeout)); 2512c07f6f0SAndrew Jeffery 2522c07f6f0SAndrew Jeffery *data_len = 4; 2532c07f6f0SAndrew Jeffery } 2542c07f6f0SAndrew Jeffery catch (const exception::SdBusError& e) 2552c07f6f0SAndrew Jeffery { 2562c07f6f0SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 2572c07f6f0SAndrew Jeffery } 2582c07f6f0SAndrew Jeffery 2592c07f6f0SAndrew Jeffery return IPMI_CC_OK; 2602c07f6f0SAndrew Jeffery } 2612c07f6f0SAndrew Jeffery 262db688e9fSAndrew Jeffery static ipmi_ret_t hiomap_get_flash_info(ipmi_request_t request, 263db688e9fSAndrew Jeffery ipmi_response_t response, 264db688e9fSAndrew Jeffery ipmi_data_len_t data_len, 265db688e9fSAndrew Jeffery ipmi_context_t context) 266db688e9fSAndrew Jeffery { 267db688e9fSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 268db688e9fSAndrew Jeffery 269db688e9fSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 270db688e9fSAndrew Jeffery HIOMAPD_IFACE_V2, "GetFlashInfo"); 271db688e9fSAndrew Jeffery try 272db688e9fSAndrew Jeffery { 273db688e9fSAndrew Jeffery auto reply = ctx->bus->call(m); 274db688e9fSAndrew Jeffery 275db688e9fSAndrew Jeffery uint16_t flashSize, eraseSize; 276db688e9fSAndrew Jeffery reply.read(flashSize, eraseSize); 277db688e9fSAndrew Jeffery 278db688e9fSAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 279db688e9fSAndrew Jeffery put(&respdata[0], htole16(flashSize)); 280db688e9fSAndrew Jeffery put(&respdata[2], htole16(eraseSize)); 281db688e9fSAndrew Jeffery 282db688e9fSAndrew Jeffery *data_len = 4; 283db688e9fSAndrew Jeffery } 284db688e9fSAndrew Jeffery catch (const exception::SdBusError& e) 285db688e9fSAndrew Jeffery { 286db688e9fSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 287db688e9fSAndrew Jeffery } 288db688e9fSAndrew Jeffery 289db688e9fSAndrew Jeffery return IPMI_CC_OK; 290db688e9fSAndrew Jeffery } 291db688e9fSAndrew Jeffery 292a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_window(struct hiomap* ctx, bool ro, 293a00f59baSAndrew Jeffery ipmi_request_t request, 294a00f59baSAndrew Jeffery ipmi_response_t response, 295a00f59baSAndrew Jeffery ipmi_data_len_t data_len) 296a00f59baSAndrew Jeffery { 297a00f59baSAndrew Jeffery if (*data_len < 4) 298a00f59baSAndrew Jeffery { 299a00f59baSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 300a00f59baSAndrew Jeffery } 301a00f59baSAndrew Jeffery 302a00f59baSAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 303a00f59baSAndrew Jeffery auto windowType = ro ? "CreateReadWindow" : "CreateWriteWindow"; 304a00f59baSAndrew Jeffery 305a00f59baSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 306a00f59baSAndrew Jeffery HIOMAPD_IFACE_V2, windowType); 307a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); 308a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); 309a00f59baSAndrew Jeffery 310a00f59baSAndrew Jeffery try 311a00f59baSAndrew Jeffery { 312a00f59baSAndrew Jeffery auto reply = ctx->bus->call(m); 313a00f59baSAndrew Jeffery 314a00f59baSAndrew Jeffery uint16_t lpcAddress, size, offset; 315a00f59baSAndrew Jeffery reply.read(lpcAddress, size, offset); 316a00f59baSAndrew Jeffery 317a00f59baSAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 318a00f59baSAndrew Jeffery 319a00f59baSAndrew Jeffery /* FIXME: Assumes v2! */ 320a00f59baSAndrew Jeffery put(&respdata[0], htole16(lpcAddress)); 321a00f59baSAndrew Jeffery put(&respdata[2], htole16(size)); 322a00f59baSAndrew Jeffery put(&respdata[4], htole16(offset)); 323a00f59baSAndrew Jeffery 324a00f59baSAndrew Jeffery *data_len = 6; 325a00f59baSAndrew Jeffery } 326a00f59baSAndrew Jeffery catch (const exception::SdBusError& e) 327a00f59baSAndrew Jeffery { 328a00f59baSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 329a00f59baSAndrew Jeffery } 330a00f59baSAndrew Jeffery 331a00f59baSAndrew Jeffery return IPMI_CC_OK; 332a00f59baSAndrew Jeffery } 333a00f59baSAndrew Jeffery 334a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_read_window(ipmi_request_t request, 335a00f59baSAndrew Jeffery ipmi_response_t response, 336a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 337a00f59baSAndrew Jeffery ipmi_context_t context) 338a00f59baSAndrew Jeffery { 339a00f59baSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 340a00f59baSAndrew Jeffery 341a00f59baSAndrew Jeffery return hiomap_create_window(ctx, true, request, response, data_len); 342a00f59baSAndrew Jeffery } 343a00f59baSAndrew Jeffery 344a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_write_window(ipmi_request_t request, 345a00f59baSAndrew Jeffery ipmi_response_t response, 346a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 347a00f59baSAndrew Jeffery ipmi_context_t context) 348a00f59baSAndrew Jeffery { 349a00f59baSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 350a00f59baSAndrew Jeffery 351a00f59baSAndrew Jeffery return hiomap_create_window(ctx, false, request, response, data_len); 352a00f59baSAndrew Jeffery } 353a00f59baSAndrew Jeffery 354b52822cdSAndrew Jeffery static ipmi_ret_t hiomap_close_window(ipmi_request_t request, 355b52822cdSAndrew Jeffery ipmi_response_t response, 356b52822cdSAndrew Jeffery ipmi_data_len_t data_len, 357b52822cdSAndrew Jeffery ipmi_context_t context) 358b52822cdSAndrew Jeffery { 359b52822cdSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 360b52822cdSAndrew Jeffery 361b52822cdSAndrew Jeffery if (*data_len < 1) 362b52822cdSAndrew Jeffery { 363b52822cdSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 364b52822cdSAndrew Jeffery } 365b52822cdSAndrew Jeffery 366b52822cdSAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 367b52822cdSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 368b52822cdSAndrew Jeffery HIOMAPD_IFACE_V2, "CloseWindow"); 369b52822cdSAndrew Jeffery m.append(reqdata[0]); 370b52822cdSAndrew Jeffery 371b52822cdSAndrew Jeffery try 372b52822cdSAndrew Jeffery { 373b52822cdSAndrew Jeffery auto reply = ctx->bus->call(m); 374b52822cdSAndrew Jeffery 375b52822cdSAndrew Jeffery *data_len = 0; 376b52822cdSAndrew Jeffery } 377b52822cdSAndrew Jeffery catch (const exception::SdBusError& e) 378b52822cdSAndrew Jeffery { 379b52822cdSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 380b52822cdSAndrew Jeffery } 381b52822cdSAndrew Jeffery 382b52822cdSAndrew Jeffery return IPMI_CC_OK; 383b52822cdSAndrew Jeffery } 384b52822cdSAndrew Jeffery 3859847f1c2SAndrew Jeffery static ipmi_ret_t hiomap_mark_dirty(ipmi_request_t request, 3869847f1c2SAndrew Jeffery ipmi_response_t response, 3879847f1c2SAndrew Jeffery ipmi_data_len_t data_len, 3889847f1c2SAndrew Jeffery ipmi_context_t context) 3899847f1c2SAndrew Jeffery { 3909847f1c2SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 3919847f1c2SAndrew Jeffery 3929847f1c2SAndrew Jeffery if (*data_len < 4) 3939847f1c2SAndrew Jeffery { 3949847f1c2SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 3959847f1c2SAndrew Jeffery } 3969847f1c2SAndrew Jeffery 3979847f1c2SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 3989847f1c2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 3999847f1c2SAndrew Jeffery HIOMAPD_IFACE_V2, "MarkDirty"); 4009847f1c2SAndrew Jeffery /* FIXME: Assumes v2 */ 4019847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 4029847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 4039847f1c2SAndrew Jeffery 4049847f1c2SAndrew Jeffery try 4059847f1c2SAndrew Jeffery { 4069847f1c2SAndrew Jeffery auto reply = ctx->bus->call(m); 4079847f1c2SAndrew Jeffery 4089847f1c2SAndrew Jeffery *data_len = 0; 4099847f1c2SAndrew Jeffery } 4109847f1c2SAndrew Jeffery catch (const exception::SdBusError& e) 4119847f1c2SAndrew Jeffery { 4129847f1c2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4139847f1c2SAndrew Jeffery } 4149847f1c2SAndrew Jeffery 4159847f1c2SAndrew Jeffery return IPMI_CC_OK; 4169847f1c2SAndrew Jeffery } 4179847f1c2SAndrew Jeffery 4187b225fb2SAndrew Jeffery static ipmi_ret_t hiomap_flush(ipmi_request_t request, ipmi_response_t response, 4197b225fb2SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 4207b225fb2SAndrew Jeffery { 4217b225fb2SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 4227b225fb2SAndrew Jeffery 4237b225fb2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 4247b225fb2SAndrew Jeffery HIOMAPD_IFACE_V2, "Flush"); 4257b225fb2SAndrew Jeffery 4267b225fb2SAndrew Jeffery try 4277b225fb2SAndrew Jeffery { 4287b225fb2SAndrew Jeffery /* FIXME: No argument call assumes v2 */ 4297b225fb2SAndrew Jeffery auto reply = ctx->bus->call(m); 4307b225fb2SAndrew Jeffery 4317b225fb2SAndrew Jeffery *data_len = 0; 4327b225fb2SAndrew Jeffery } 4337b225fb2SAndrew Jeffery catch (const exception::SdBusError& e) 4347b225fb2SAndrew Jeffery { 4357b225fb2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4367b225fb2SAndrew Jeffery } 4377b225fb2SAndrew Jeffery 4387b225fb2SAndrew Jeffery return IPMI_CC_OK; 4397b225fb2SAndrew Jeffery } 4407b225fb2SAndrew Jeffery 44199f277a1SAndrew Jeffery static ipmi_ret_t hiomap_ack(ipmi_request_t request, ipmi_response_t response, 44299f277a1SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 44399f277a1SAndrew Jeffery { 44499f277a1SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 44599f277a1SAndrew Jeffery 44699f277a1SAndrew Jeffery if (*data_len < 1) 44799f277a1SAndrew Jeffery { 44899f277a1SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 44999f277a1SAndrew Jeffery } 45099f277a1SAndrew Jeffery 45199f277a1SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 45299f277a1SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 45399f277a1SAndrew Jeffery HIOMAPD_IFACE_V2, "Ack"); 45499f277a1SAndrew Jeffery auto acked = reqdata[0]; 45599f277a1SAndrew Jeffery m.append(acked); 45699f277a1SAndrew Jeffery 45799f277a1SAndrew Jeffery try 45899f277a1SAndrew Jeffery { 45999f277a1SAndrew Jeffery auto reply = ctx->bus->call(m); 46099f277a1SAndrew Jeffery 46199f277a1SAndrew Jeffery /* Update our cache: Necessary because the signals do not carry a value 46299f277a1SAndrew Jeffery */ 46399f277a1SAndrew Jeffery ctx->bmc_events &= ~acked; 46499f277a1SAndrew Jeffery 46599f277a1SAndrew Jeffery *data_len = 0; 46699f277a1SAndrew Jeffery } 46799f277a1SAndrew Jeffery catch (const exception::SdBusError& e) 46899f277a1SAndrew Jeffery { 46999f277a1SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 47099f277a1SAndrew Jeffery } 47199f277a1SAndrew Jeffery 47299f277a1SAndrew Jeffery return IPMI_CC_OK; 47399f277a1SAndrew Jeffery } 47499f277a1SAndrew Jeffery 475a1e35b85SAndrew Jeffery static ipmi_ret_t hiomap_erase(ipmi_request_t request, ipmi_response_t response, 476a1e35b85SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 477a1e35b85SAndrew Jeffery { 478a1e35b85SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 479a1e35b85SAndrew Jeffery 480a1e35b85SAndrew Jeffery if (*data_len < 4) 481a1e35b85SAndrew Jeffery { 482a1e35b85SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 483a1e35b85SAndrew Jeffery } 484a1e35b85SAndrew Jeffery 485a1e35b85SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 486a1e35b85SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 487a1e35b85SAndrew Jeffery HIOMAPD_IFACE_V2, "Erase"); 488a1e35b85SAndrew Jeffery /* FIXME: Assumes v2 */ 489a1e35b85SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 490a1e35b85SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 491a1e35b85SAndrew Jeffery 492a1e35b85SAndrew Jeffery try 493a1e35b85SAndrew Jeffery { 494a1e35b85SAndrew Jeffery auto reply = ctx->bus->call(m); 495a1e35b85SAndrew Jeffery 496a1e35b85SAndrew Jeffery *data_len = 0; 497a1e35b85SAndrew Jeffery } 498a1e35b85SAndrew Jeffery catch (const exception::SdBusError& e) 499a1e35b85SAndrew Jeffery { 500a1e35b85SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 501a1e35b85SAndrew Jeffery } 502a1e35b85SAndrew Jeffery 503a1e35b85SAndrew Jeffery return IPMI_CC_OK; 504a1e35b85SAndrew Jeffery } 505a1e35b85SAndrew Jeffery 50604d75136SAndrew Jeffery #define HIOMAP_C_RESET 1 50704d75136SAndrew Jeffery #define HIOMAP_C_GET_INFO 2 50804d75136SAndrew Jeffery #define HIOMAP_C_GET_FLASH_INFO 3 50904d75136SAndrew Jeffery #define HIOMAP_C_CREATE_READ_WINDOW 4 51004d75136SAndrew Jeffery #define HIOMAP_C_CLOSE_WINDOW 5 51104d75136SAndrew Jeffery #define HIOMAP_C_CREATE_WRITE_WINDOW 6 51204d75136SAndrew Jeffery #define HIOMAP_C_MARK_DIRTY 7 51304d75136SAndrew Jeffery #define HIOMAP_C_FLUSH 8 51404d75136SAndrew Jeffery #define HIOMAP_C_ACK 9 51504d75136SAndrew Jeffery #define HIOMAP_C_ERASE 10 51604d75136SAndrew Jeffery 5172c07f6f0SAndrew Jeffery static const hiomap_command hiomap_commands[] = { 51804d75136SAndrew Jeffery [0] = NULL, /* Invalid command ID */ 51904d75136SAndrew Jeffery [HIOMAP_C_RESET] = hiomap_reset, 52004d75136SAndrew Jeffery [HIOMAP_C_GET_INFO] = hiomap_get_info, 52104d75136SAndrew Jeffery [HIOMAP_C_GET_FLASH_INFO] = hiomap_get_flash_info, 52204d75136SAndrew Jeffery [HIOMAP_C_CREATE_READ_WINDOW] = hiomap_create_read_window, 52304d75136SAndrew Jeffery [HIOMAP_C_CLOSE_WINDOW] = hiomap_close_window, 52404d75136SAndrew Jeffery [HIOMAP_C_CREATE_WRITE_WINDOW] = hiomap_create_write_window, 52504d75136SAndrew Jeffery [HIOMAP_C_MARK_DIRTY] = hiomap_mark_dirty, 52604d75136SAndrew Jeffery [HIOMAP_C_FLUSH] = hiomap_flush, 52704d75136SAndrew Jeffery [HIOMAP_C_ACK] = hiomap_ack, 52804d75136SAndrew Jeffery [HIOMAP_C_ERASE] = hiomap_erase, 5292c07f6f0SAndrew Jeffery }; 5302c07f6f0SAndrew Jeffery 5312c07f6f0SAndrew Jeffery /* FIXME: Define this in the "right" place, wherever that is */ 5322c07f6f0SAndrew Jeffery /* FIXME: Double evaluation */ 5332c07f6f0SAndrew Jeffery #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 5342c07f6f0SAndrew Jeffery 5352c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_dispatch(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 5362c07f6f0SAndrew Jeffery ipmi_request_t request, 5372c07f6f0SAndrew Jeffery ipmi_response_t response, 5382c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 5392c07f6f0SAndrew Jeffery ipmi_context_t context) 5402c07f6f0SAndrew Jeffery { 5410a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 5420a3358e7SAndrew Jeffery 5432c07f6f0SAndrew Jeffery if (*data_len < 2) 5442c07f6f0SAndrew Jeffery { 5452c07f6f0SAndrew Jeffery *data_len = 0; 5462c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 5472c07f6f0SAndrew Jeffery } 5482c07f6f0SAndrew Jeffery 5492c07f6f0SAndrew Jeffery uint8_t* ipmi_req = (uint8_t*)request; 5502c07f6f0SAndrew Jeffery uint8_t* ipmi_resp = (uint8_t*)response; 5512c07f6f0SAndrew Jeffery uint8_t hiomap_cmd = ipmi_req[0]; 5522c07f6f0SAndrew Jeffery 5532c07f6f0SAndrew Jeffery if (hiomap_cmd == 0 || hiomap_cmd > ARRAY_SIZE(hiomap_commands) - 1) 5542c07f6f0SAndrew Jeffery { 5552c07f6f0SAndrew Jeffery *data_len = 0; 5562c07f6f0SAndrew Jeffery return IPMI_CC_PARM_OUT_OF_RANGE; 5572c07f6f0SAndrew Jeffery } 55804d75136SAndrew Jeffery 55904d75136SAndrew Jeffery bool is_unversioned = 56004d75136SAndrew Jeffery (hiomap_cmd == HIOMAP_C_RESET || hiomap_cmd == HIOMAP_C_GET_INFO || 56104d75136SAndrew Jeffery hiomap_cmd == HIOMAP_C_ACK); 56204d75136SAndrew Jeffery if (!is_unversioned && ctx->seq == ipmi_req[1]) 56304d75136SAndrew Jeffery { 56404d75136SAndrew Jeffery *data_len = 0; 56504d75136SAndrew Jeffery return IPMI_CC_INVALID_FIELD_REQUEST; 56604d75136SAndrew Jeffery } 56704d75136SAndrew Jeffery 56804d75136SAndrew Jeffery ctx->seq = ipmi_req[1]; 56904d75136SAndrew Jeffery 5702c07f6f0SAndrew Jeffery uint8_t* flash_req = ipmi_req + 2; 5712c07f6f0SAndrew Jeffery size_t flash_len = *data_len - 2; 5722c07f6f0SAndrew Jeffery uint8_t* flash_resp = ipmi_resp + 2; 5732c07f6f0SAndrew Jeffery 5742c07f6f0SAndrew Jeffery ipmi_ret_t cc = 5752c07f6f0SAndrew Jeffery hiomap_commands[hiomap_cmd](flash_req, flash_resp, &flash_len, context); 5762c07f6f0SAndrew Jeffery if (cc != IPMI_CC_OK) 5772c07f6f0SAndrew Jeffery { 5782c07f6f0SAndrew Jeffery *data_len = 0; 5792c07f6f0SAndrew Jeffery return cc; 5802c07f6f0SAndrew Jeffery } 5812c07f6f0SAndrew Jeffery 5822c07f6f0SAndrew Jeffery /* Populate the response command and sequence */ 5830a3358e7SAndrew Jeffery ipmi_resp[0] = hiomap_cmd; 58404d75136SAndrew Jeffery ipmi_resp[1] = ctx->seq; 5852c07f6f0SAndrew Jeffery 5862c07f6f0SAndrew Jeffery *data_len = flash_len + 2; 5872c07f6f0SAndrew Jeffery 5882c07f6f0SAndrew Jeffery return cc; 5892c07f6f0SAndrew Jeffery } 5902c07f6f0SAndrew Jeffery } // namespace flash 5912c07f6f0SAndrew Jeffery } // namespace openpower 5922c07f6f0SAndrew Jeffery 5932c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() 5942c07f6f0SAndrew Jeffery { 5950a3358e7SAndrew Jeffery using namespace openpower::flash; 5960a3358e7SAndrew Jeffery 5970a3358e7SAndrew Jeffery /* FIXME: Clean this up? Can we unregister? */ 5980a3358e7SAndrew Jeffery struct hiomap* ctx = new hiomap(); 5990a3358e7SAndrew Jeffery 6000a3358e7SAndrew Jeffery /* Initialise mapping from signal and property names to status bit */ 6010a3358e7SAndrew Jeffery ctx->event_lookup["DaemonReady"] = BMC_EVENT_DAEMON_READY; 6020a3358e7SAndrew Jeffery ctx->event_lookup["FlashControlLost"] = BMC_EVENT_FLASH_CTRL_LOST; 6030a3358e7SAndrew Jeffery ctx->event_lookup["WindowReset"] = BMC_EVENT_WINDOW_RESET; 6040a3358e7SAndrew Jeffery ctx->event_lookup["ProtocolReset"] = BMC_EVENT_PROTOCOL_RESET; 6050a3358e7SAndrew Jeffery 6060a3358e7SAndrew Jeffery ctx->bus = new bus::bus(ipmid_get_sd_bus_connection()); 6070a3358e7SAndrew Jeffery 6080a3358e7SAndrew Jeffery /* Initialise signal handling */ 6090a3358e7SAndrew Jeffery 6100a3358e7SAndrew Jeffery /* 6110a3358e7SAndrew Jeffery * Can't use temporaries here because that causes SEGFAULTs due to slot 6120a3358e7SAndrew Jeffery * destruction (!?), so enjoy the weird wrapping. 6130a3358e7SAndrew Jeffery */ 6140a3358e7SAndrew Jeffery ctx->properties = 6150a3358e7SAndrew Jeffery new bus::match::match(std::move(hiomap_match_properties(ctx))); 6160a3358e7SAndrew Jeffery ctx->bmc_reboot = new bus::match::match( 6170a3358e7SAndrew Jeffery std::move(hiomap_match_signal_v2(ctx, "ProtocolReset"))); 6180a3358e7SAndrew Jeffery ctx->window_reset = new bus::match::match( 6190a3358e7SAndrew Jeffery std::move(hiomap_match_signal_v2(ctx, "WindowReset"))); 6200a3358e7SAndrew Jeffery 6210a3358e7SAndrew Jeffery ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, ctx, 6222c07f6f0SAndrew Jeffery openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE); 6232c07f6f0SAndrew Jeffery } 624