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 #include <string.h> 112c07f6f0SAndrew Jeffery #include <systemd/sd-bus.h> 122c07f6f0SAndrew Jeffery 132c07f6f0SAndrew Jeffery #include <fstream> 140a3358e7SAndrew Jeffery #include <functional> 150a3358e7SAndrew Jeffery #include <host-ipmid/ipmid-host-cmd-utils.hpp> 160a3358e7SAndrew Jeffery #include <host-ipmid/ipmid-host-cmd.hpp> 170a3358e7SAndrew Jeffery #include <iostream> 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> 222c07f6f0SAndrew Jeffery 232c07f6f0SAndrew Jeffery using namespace sdbusplus; 240a3358e7SAndrew Jeffery using namespace phosphor::host::command; 252c07f6f0SAndrew Jeffery 262c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() __attribute__((constructor)); 272c07f6f0SAndrew Jeffery 282c07f6f0SAndrew Jeffery namespace openpower 292c07f6f0SAndrew Jeffery { 302c07f6f0SAndrew Jeffery namespace flash 312c07f6f0SAndrew Jeffery { 320a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_DAEMON_READY = 1 << 7; 330a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_FLASH_CTRL_LOST = 1 << 6; 340a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_WINDOW_RESET = 1 << 1; 350a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_PROTOCOL_RESET = 1 << 0; 360a3358e7SAndrew Jeffery 370a3358e7SAndrew Jeffery constexpr auto IPMI_CMD_HIOMAP_EVENT = 0x0f; 380a3358e7SAndrew Jeffery 390a3358e7SAndrew Jeffery constexpr auto HIOMAPD_SERVICE = "xyz.openbmc_project.Hiomapd"; 400a3358e7SAndrew Jeffery constexpr auto HIOMAPD_OBJECT = "/xyz/openbmc_project/Hiomapd"; 410a3358e7SAndrew Jeffery constexpr auto HIOMAPD_IFACE = "xyz.openbmc_project.Hiomapd.Protocol"; 420a3358e7SAndrew Jeffery constexpr auto HIOMAPD_IFACE_V2 = "xyz.openbmc_project.Hiomapd.Protocol.V2"; 430a3358e7SAndrew Jeffery 440a3358e7SAndrew Jeffery constexpr auto DBUS_IFACE_PROPERTIES = "org.freedesktop.DBus.Properties"; 450a3358e7SAndrew Jeffery 460a3358e7SAndrew Jeffery struct hiomap 470a3358e7SAndrew Jeffery { 480a3358e7SAndrew Jeffery bus::bus *bus; 490a3358e7SAndrew Jeffery 500a3358e7SAndrew Jeffery /* Signals */ 510a3358e7SAndrew Jeffery bus::match::match *properties; 520a3358e7SAndrew Jeffery bus::match::match *window_reset; 530a3358e7SAndrew Jeffery bus::match::match *bmc_reboot; 540a3358e7SAndrew Jeffery 550a3358e7SAndrew Jeffery /* Protocol state */ 560a3358e7SAndrew Jeffery std::map<std::string, int> event_lookup; 570a3358e7SAndrew Jeffery uint8_t bmc_events; 580a3358e7SAndrew Jeffery }; 592c07f6f0SAndrew Jeffery 602c07f6f0SAndrew Jeffery /* TODO: Replace get/put with packed structs and direct assignment */ 612c07f6f0SAndrew Jeffery template <typename T> static inline T get(void *buf) 622c07f6f0SAndrew Jeffery { 632c07f6f0SAndrew Jeffery T t; 642c07f6f0SAndrew Jeffery memcpy(&t, buf, sizeof(t)); 652c07f6f0SAndrew Jeffery return t; 662c07f6f0SAndrew Jeffery } 672c07f6f0SAndrew Jeffery 682c07f6f0SAndrew Jeffery template <typename T> static inline void put(void *buf, T &&t) 692c07f6f0SAndrew Jeffery { 702c07f6f0SAndrew Jeffery memcpy(buf, &t, sizeof(t)); 712c07f6f0SAndrew Jeffery } 722c07f6f0SAndrew Jeffery 732c07f6f0SAndrew Jeffery typedef ipmi_ret_t (*hiomap_command)(ipmi_request_t req, ipmi_response_t resp, 742c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 752c07f6f0SAndrew Jeffery ipmi_context_t context); 762c07f6f0SAndrew Jeffery 772c07f6f0SAndrew Jeffery struct errno_cc_entry 782c07f6f0SAndrew Jeffery { 792c07f6f0SAndrew Jeffery int err; 802c07f6f0SAndrew Jeffery int cc; 812c07f6f0SAndrew Jeffery }; 822c07f6f0SAndrew Jeffery 832c07f6f0SAndrew Jeffery static const errno_cc_entry errno_cc_map[] = { 842c07f6f0SAndrew Jeffery {0, IPMI_CC_OK}, 852c07f6f0SAndrew Jeffery {EBUSY, IPMI_CC_BUSY}, 862c07f6f0SAndrew Jeffery {ENOTSUP, IPMI_CC_INVALID}, 872c07f6f0SAndrew Jeffery {ETIMEDOUT, 0xc3}, /* FIXME: Replace when defined in ipmid-api.h */ 882c07f6f0SAndrew Jeffery {ENOSPC, 0xc4}, /* FIXME: Replace when defined in ipmid-api.h */ 892c07f6f0SAndrew Jeffery {EINVAL, IPMI_CC_PARM_OUT_OF_RANGE}, 902c07f6f0SAndrew Jeffery {ENODEV, IPMI_CC_SENSOR_INVALID}, 912c07f6f0SAndrew Jeffery {EPERM, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 922c07f6f0SAndrew Jeffery {EACCES, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 932c07f6f0SAndrew Jeffery {-1, IPMI_CC_UNSPECIFIED_ERROR}, 942c07f6f0SAndrew Jeffery }; 952c07f6f0SAndrew Jeffery 962c07f6f0SAndrew Jeffery static int hiomap_xlate_errno(int err) 972c07f6f0SAndrew Jeffery { 982c07f6f0SAndrew Jeffery const errno_cc_entry *entry = &errno_cc_map[0]; 992c07f6f0SAndrew Jeffery 1002c07f6f0SAndrew Jeffery while (!(entry->err == err || entry->err == -1)) 1012c07f6f0SAndrew Jeffery { 1022c07f6f0SAndrew Jeffery entry++; 1032c07f6f0SAndrew Jeffery } 1042c07f6f0SAndrew Jeffery 1052c07f6f0SAndrew Jeffery return entry->cc; 1062c07f6f0SAndrew Jeffery } 1072c07f6f0SAndrew Jeffery 1080a3358e7SAndrew Jeffery static void ipmi_hiomap_event_response(IpmiCmdData cmd, bool status) 1090a3358e7SAndrew Jeffery { 1100a3358e7SAndrew Jeffery using namespace phosphor::logging; 1110a3358e7SAndrew Jeffery 1120a3358e7SAndrew Jeffery if (!status) 1130a3358e7SAndrew Jeffery { 1140a3358e7SAndrew Jeffery log<level::ERR>("Failed to deliver host command", 1150a3358e7SAndrew Jeffery entry("SEL_COMMAND=%x:%x", cmd.first, cmd.second)); 1160a3358e7SAndrew Jeffery } 1170a3358e7SAndrew Jeffery } 1180a3358e7SAndrew Jeffery 1190a3358e7SAndrew Jeffery static int hiomap_handle_property_update(struct hiomap *ctx, 1200a3358e7SAndrew Jeffery sdbusplus::message::message &msg) 1210a3358e7SAndrew Jeffery { 1220a3358e7SAndrew Jeffery std::map<std::string, sdbusplus::message::variant<bool>> msgData; 1230a3358e7SAndrew Jeffery 1240a3358e7SAndrew Jeffery std::string iface; 1250a3358e7SAndrew Jeffery msg.read(iface, msgData); 1260a3358e7SAndrew Jeffery 1270a3358e7SAndrew Jeffery for (auto const &x : msgData) 1280a3358e7SAndrew Jeffery { 1290a3358e7SAndrew Jeffery if (!ctx->event_lookup.count(x.first)) 1300a3358e7SAndrew Jeffery { 1310a3358e7SAndrew Jeffery /* Unsupported event? */ 1320a3358e7SAndrew Jeffery continue; 1330a3358e7SAndrew Jeffery } 1340a3358e7SAndrew Jeffery 1350a3358e7SAndrew Jeffery uint8_t mask = ctx->event_lookup[x.first]; 1360a3358e7SAndrew Jeffery auto value = sdbusplus::message::variant_ns::get<bool>(x.second); 1370a3358e7SAndrew Jeffery 1380a3358e7SAndrew Jeffery if (value) 1390a3358e7SAndrew Jeffery { 1400a3358e7SAndrew Jeffery ctx->bmc_events |= mask; 1410a3358e7SAndrew Jeffery } 1420a3358e7SAndrew Jeffery else 1430a3358e7SAndrew Jeffery { 1440a3358e7SAndrew Jeffery ctx->bmc_events &= ~mask; 1450a3358e7SAndrew Jeffery } 1460a3358e7SAndrew Jeffery } 1470a3358e7SAndrew Jeffery 1480a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 1490a3358e7SAndrew Jeffery 1500a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 1510a3358e7SAndrew Jeffery 1520a3358e7SAndrew Jeffery return 0; 1530a3358e7SAndrew Jeffery } 1540a3358e7SAndrew Jeffery 1550a3358e7SAndrew Jeffery static bus::match::match hiomap_match_properties(struct hiomap *ctx) 1560a3358e7SAndrew Jeffery { 1570a3358e7SAndrew Jeffery auto properties = 1580a3358e7SAndrew Jeffery bus::match::rules::propertiesChanged(HIOMAPD_OBJECT, HIOMAPD_IFACE_V2); 1590a3358e7SAndrew Jeffery 1600a3358e7SAndrew Jeffery bus::match::match match( 1610a3358e7SAndrew Jeffery *ctx->bus, properties, 1620a3358e7SAndrew Jeffery std::bind(hiomap_handle_property_update, ctx, std::placeholders::_1)); 1630a3358e7SAndrew Jeffery 1640a3358e7SAndrew Jeffery return match; 1650a3358e7SAndrew Jeffery } 1660a3358e7SAndrew Jeffery 1670a3358e7SAndrew Jeffery static int hiomap_handle_signal_v2(struct hiomap *ctx, const char *name) 1680a3358e7SAndrew Jeffery { 1690a3358e7SAndrew Jeffery ctx->bmc_events |= ctx->event_lookup[name]; 1700a3358e7SAndrew Jeffery 1710a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 1720a3358e7SAndrew Jeffery 1730a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 1740a3358e7SAndrew Jeffery 1750a3358e7SAndrew Jeffery return 0; 1760a3358e7SAndrew Jeffery } 1770a3358e7SAndrew Jeffery 1780a3358e7SAndrew Jeffery static bus::match::match hiomap_match_signal_v2(struct hiomap *ctx, 1790a3358e7SAndrew Jeffery const char *name) 1800a3358e7SAndrew Jeffery { 1810a3358e7SAndrew Jeffery using namespace bus::match; 1820a3358e7SAndrew Jeffery 1830a3358e7SAndrew Jeffery auto signals = rules::type::signal() + rules::path(HIOMAPD_OBJECT) + 1840a3358e7SAndrew Jeffery rules::interface(HIOMAPD_IFACE_V2) + rules::member(name); 1850a3358e7SAndrew Jeffery 1860a3358e7SAndrew Jeffery bus::match::match match(*ctx->bus, signals, 1870a3358e7SAndrew Jeffery std::bind(hiomap_handle_signal_v2, ctx, name)); 1880a3358e7SAndrew Jeffery 1890a3358e7SAndrew Jeffery return match; 1900a3358e7SAndrew Jeffery } 1910a3358e7SAndrew Jeffery 1920a3358e7SAndrew Jeffery static ipmi_ret_t hiomap_reset(ipmi_request_t request, ipmi_response_t response, 1930a3358e7SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 1940a3358e7SAndrew Jeffery { 1950a3358e7SAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 1960a3358e7SAndrew Jeffery 1970a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 1980a3358e7SAndrew Jeffery HIOMAPD_IFACE, "Reset"); 1990a3358e7SAndrew Jeffery try 2000a3358e7SAndrew Jeffery { 2010a3358e7SAndrew Jeffery ctx->bus->call(m); 2020a3358e7SAndrew Jeffery 2030a3358e7SAndrew Jeffery *data_len = 0; 2040a3358e7SAndrew Jeffery } 2050a3358e7SAndrew Jeffery catch (const exception::SdBusError &e) 2060a3358e7SAndrew Jeffery { 2070a3358e7SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 2080a3358e7SAndrew Jeffery } 2090a3358e7SAndrew Jeffery 2100a3358e7SAndrew Jeffery return IPMI_CC_OK; 2110a3358e7SAndrew Jeffery } 2120a3358e7SAndrew Jeffery 2132c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_get_info(ipmi_request_t request, 2142c07f6f0SAndrew Jeffery ipmi_response_t response, 2152c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 2162c07f6f0SAndrew Jeffery ipmi_context_t context) 2172c07f6f0SAndrew Jeffery { 2180a3358e7SAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 2190a3358e7SAndrew Jeffery 2202c07f6f0SAndrew Jeffery if (*data_len < 1) 2212c07f6f0SAndrew Jeffery { 2222c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 2232c07f6f0SAndrew Jeffery } 2242c07f6f0SAndrew Jeffery 2252c07f6f0SAndrew Jeffery uint8_t *reqdata = (uint8_t *)request; 2260a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 2270a3358e7SAndrew Jeffery HIOMAPD_IFACE, "GetInfo"); 2282c07f6f0SAndrew Jeffery m.append(reqdata[0]); 2292c07f6f0SAndrew Jeffery 2302c07f6f0SAndrew Jeffery try 2312c07f6f0SAndrew Jeffery { 2320a3358e7SAndrew Jeffery auto reply = ctx->bus->call(m); 2332c07f6f0SAndrew Jeffery 2342c07f6f0SAndrew Jeffery uint8_t version; 2352c07f6f0SAndrew Jeffery uint8_t blockSizeShift; 2362c07f6f0SAndrew Jeffery uint16_t timeout; 2372c07f6f0SAndrew Jeffery reply.read(version, blockSizeShift, timeout); 2382c07f6f0SAndrew Jeffery 2392c07f6f0SAndrew Jeffery uint8_t *respdata = (uint8_t *)response; 2402c07f6f0SAndrew Jeffery 2412c07f6f0SAndrew Jeffery /* FIXME: Assumes v2! */ 2422c07f6f0SAndrew Jeffery put(&respdata[0], version); 2432c07f6f0SAndrew Jeffery put(&respdata[1], blockSizeShift); 2442c07f6f0SAndrew Jeffery put(&respdata[2], htole16(timeout)); 2452c07f6f0SAndrew Jeffery 2462c07f6f0SAndrew Jeffery *data_len = 4; 2472c07f6f0SAndrew Jeffery } 2482c07f6f0SAndrew Jeffery catch (const exception::SdBusError &e) 2492c07f6f0SAndrew Jeffery { 2502c07f6f0SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 2512c07f6f0SAndrew Jeffery } 2522c07f6f0SAndrew Jeffery 2532c07f6f0SAndrew Jeffery return IPMI_CC_OK; 2542c07f6f0SAndrew Jeffery } 2552c07f6f0SAndrew Jeffery 256db688e9fSAndrew Jeffery static ipmi_ret_t hiomap_get_flash_info(ipmi_request_t request, 257db688e9fSAndrew Jeffery ipmi_response_t response, 258db688e9fSAndrew Jeffery ipmi_data_len_t data_len, 259db688e9fSAndrew Jeffery ipmi_context_t context) 260db688e9fSAndrew Jeffery { 261db688e9fSAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 262db688e9fSAndrew Jeffery 263db688e9fSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 264db688e9fSAndrew Jeffery HIOMAPD_IFACE_V2, "GetFlashInfo"); 265db688e9fSAndrew Jeffery try 266db688e9fSAndrew Jeffery { 267db688e9fSAndrew Jeffery auto reply = ctx->bus->call(m); 268db688e9fSAndrew Jeffery 269db688e9fSAndrew Jeffery uint16_t flashSize, eraseSize; 270db688e9fSAndrew Jeffery reply.read(flashSize, eraseSize); 271db688e9fSAndrew Jeffery 272db688e9fSAndrew Jeffery uint8_t *respdata = (uint8_t *)response; 273db688e9fSAndrew Jeffery put(&respdata[0], htole16(flashSize)); 274db688e9fSAndrew Jeffery put(&respdata[2], htole16(eraseSize)); 275db688e9fSAndrew Jeffery 276db688e9fSAndrew Jeffery *data_len = 4; 277db688e9fSAndrew Jeffery } 278db688e9fSAndrew Jeffery catch (const exception::SdBusError &e) 279db688e9fSAndrew Jeffery { 280db688e9fSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 281db688e9fSAndrew Jeffery } 282db688e9fSAndrew Jeffery 283db688e9fSAndrew Jeffery return IPMI_CC_OK; 284db688e9fSAndrew Jeffery } 285db688e9fSAndrew Jeffery 286a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_window(struct hiomap *ctx, bool ro, 287a00f59baSAndrew Jeffery ipmi_request_t request, 288a00f59baSAndrew Jeffery ipmi_response_t response, 289a00f59baSAndrew Jeffery ipmi_data_len_t data_len) 290a00f59baSAndrew Jeffery { 291a00f59baSAndrew Jeffery if (*data_len < 4) 292a00f59baSAndrew Jeffery { 293a00f59baSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 294a00f59baSAndrew Jeffery } 295a00f59baSAndrew Jeffery 296a00f59baSAndrew Jeffery uint8_t *reqdata = (uint8_t *)request; 297a00f59baSAndrew Jeffery auto windowType = ro ? "CreateReadWindow" : "CreateWriteWindow"; 298a00f59baSAndrew Jeffery 299a00f59baSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 300a00f59baSAndrew Jeffery HIOMAPD_IFACE_V2, windowType); 301a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); 302a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); 303a00f59baSAndrew Jeffery 304a00f59baSAndrew Jeffery try 305a00f59baSAndrew Jeffery { 306a00f59baSAndrew Jeffery auto reply = ctx->bus->call(m); 307a00f59baSAndrew Jeffery 308a00f59baSAndrew Jeffery uint16_t lpcAddress, size, offset; 309a00f59baSAndrew Jeffery reply.read(lpcAddress, size, offset); 310a00f59baSAndrew Jeffery 311a00f59baSAndrew Jeffery uint8_t *respdata = (uint8_t *)response; 312a00f59baSAndrew Jeffery 313a00f59baSAndrew Jeffery /* FIXME: Assumes v2! */ 314a00f59baSAndrew Jeffery put(&respdata[0], htole16(lpcAddress)); 315a00f59baSAndrew Jeffery put(&respdata[2], htole16(size)); 316a00f59baSAndrew Jeffery put(&respdata[4], htole16(offset)); 317a00f59baSAndrew Jeffery 318a00f59baSAndrew Jeffery *data_len = 6; 319a00f59baSAndrew Jeffery } 320a00f59baSAndrew Jeffery catch (const exception::SdBusError &e) 321a00f59baSAndrew Jeffery { 322a00f59baSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 323a00f59baSAndrew Jeffery } 324a00f59baSAndrew Jeffery 325a00f59baSAndrew Jeffery return IPMI_CC_OK; 326a00f59baSAndrew Jeffery } 327a00f59baSAndrew Jeffery 328a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_read_window(ipmi_request_t request, 329a00f59baSAndrew Jeffery ipmi_response_t response, 330a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 331a00f59baSAndrew Jeffery ipmi_context_t context) 332a00f59baSAndrew Jeffery { 333a00f59baSAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 334a00f59baSAndrew Jeffery 335a00f59baSAndrew Jeffery return hiomap_create_window(ctx, true, request, response, data_len); 336a00f59baSAndrew Jeffery } 337a00f59baSAndrew Jeffery 338a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_write_window(ipmi_request_t request, 339a00f59baSAndrew Jeffery ipmi_response_t response, 340a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 341a00f59baSAndrew Jeffery ipmi_context_t context) 342a00f59baSAndrew Jeffery { 343a00f59baSAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 344a00f59baSAndrew Jeffery 345a00f59baSAndrew Jeffery return hiomap_create_window(ctx, false, request, response, data_len); 346a00f59baSAndrew Jeffery } 347a00f59baSAndrew Jeffery 348b52822cdSAndrew Jeffery static ipmi_ret_t hiomap_close_window(ipmi_request_t request, 349b52822cdSAndrew Jeffery ipmi_response_t response, 350b52822cdSAndrew Jeffery ipmi_data_len_t data_len, 351b52822cdSAndrew Jeffery ipmi_context_t context) 352b52822cdSAndrew Jeffery { 353b52822cdSAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 354b52822cdSAndrew Jeffery 355b52822cdSAndrew Jeffery if (*data_len < 1) 356b52822cdSAndrew Jeffery { 357b52822cdSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 358b52822cdSAndrew Jeffery } 359b52822cdSAndrew Jeffery 360b52822cdSAndrew Jeffery uint8_t *reqdata = (uint8_t *)request; 361b52822cdSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 362b52822cdSAndrew Jeffery HIOMAPD_IFACE_V2, "CloseWindow"); 363b52822cdSAndrew Jeffery m.append(reqdata[0]); 364b52822cdSAndrew Jeffery 365b52822cdSAndrew Jeffery try 366b52822cdSAndrew Jeffery { 367b52822cdSAndrew Jeffery auto reply = ctx->bus->call(m); 368b52822cdSAndrew Jeffery 369b52822cdSAndrew Jeffery *data_len = 0; 370b52822cdSAndrew Jeffery } 371b52822cdSAndrew Jeffery catch (const exception::SdBusError &e) 372b52822cdSAndrew Jeffery { 373b52822cdSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 374b52822cdSAndrew Jeffery } 375b52822cdSAndrew Jeffery 376b52822cdSAndrew Jeffery return IPMI_CC_OK; 377b52822cdSAndrew Jeffery } 378b52822cdSAndrew Jeffery 3799847f1c2SAndrew Jeffery static ipmi_ret_t hiomap_mark_dirty(ipmi_request_t request, 3809847f1c2SAndrew Jeffery ipmi_response_t response, 3819847f1c2SAndrew Jeffery ipmi_data_len_t data_len, 3829847f1c2SAndrew Jeffery ipmi_context_t context) 3839847f1c2SAndrew Jeffery { 3849847f1c2SAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 3859847f1c2SAndrew Jeffery 3869847f1c2SAndrew Jeffery if (*data_len < 4) 3879847f1c2SAndrew Jeffery { 3889847f1c2SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 3899847f1c2SAndrew Jeffery } 3909847f1c2SAndrew Jeffery 3919847f1c2SAndrew Jeffery uint8_t *reqdata = (uint8_t *)request; 3929847f1c2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 3939847f1c2SAndrew Jeffery HIOMAPD_IFACE_V2, "MarkDirty"); 3949847f1c2SAndrew Jeffery /* FIXME: Assumes v2 */ 3959847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 3969847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 3979847f1c2SAndrew Jeffery 3989847f1c2SAndrew Jeffery try 3999847f1c2SAndrew Jeffery { 4009847f1c2SAndrew Jeffery auto reply = ctx->bus->call(m); 4019847f1c2SAndrew Jeffery 4029847f1c2SAndrew Jeffery *data_len = 0; 4039847f1c2SAndrew Jeffery } 4049847f1c2SAndrew Jeffery catch (const exception::SdBusError &e) 4059847f1c2SAndrew Jeffery { 4069847f1c2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4079847f1c2SAndrew Jeffery } 4089847f1c2SAndrew Jeffery 4099847f1c2SAndrew Jeffery return IPMI_CC_OK; 4109847f1c2SAndrew Jeffery } 4119847f1c2SAndrew Jeffery 4127b225fb2SAndrew Jeffery static ipmi_ret_t hiomap_flush(ipmi_request_t request, ipmi_response_t response, 4137b225fb2SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 4147b225fb2SAndrew Jeffery { 4157b225fb2SAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 4167b225fb2SAndrew Jeffery 4177b225fb2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 4187b225fb2SAndrew Jeffery HIOMAPD_IFACE_V2, "Flush"); 4197b225fb2SAndrew Jeffery 4207b225fb2SAndrew Jeffery try 4217b225fb2SAndrew Jeffery { 4227b225fb2SAndrew Jeffery /* FIXME: No argument call assumes v2 */ 4237b225fb2SAndrew Jeffery auto reply = ctx->bus->call(m); 4247b225fb2SAndrew Jeffery 4257b225fb2SAndrew Jeffery *data_len = 0; 4267b225fb2SAndrew Jeffery } 4277b225fb2SAndrew Jeffery catch (const exception::SdBusError &e) 4287b225fb2SAndrew Jeffery { 4297b225fb2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4307b225fb2SAndrew Jeffery } 4317b225fb2SAndrew Jeffery 4327b225fb2SAndrew Jeffery return IPMI_CC_OK; 4337b225fb2SAndrew Jeffery } 4347b225fb2SAndrew Jeffery 435*99f277a1SAndrew Jeffery static ipmi_ret_t hiomap_ack(ipmi_request_t request, ipmi_response_t response, 436*99f277a1SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 437*99f277a1SAndrew Jeffery { 438*99f277a1SAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 439*99f277a1SAndrew Jeffery 440*99f277a1SAndrew Jeffery if (*data_len < 1) 441*99f277a1SAndrew Jeffery { 442*99f277a1SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 443*99f277a1SAndrew Jeffery } 444*99f277a1SAndrew Jeffery 445*99f277a1SAndrew Jeffery uint8_t *reqdata = (uint8_t *)request; 446*99f277a1SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 447*99f277a1SAndrew Jeffery HIOMAPD_IFACE_V2, "Ack"); 448*99f277a1SAndrew Jeffery auto acked = reqdata[0]; 449*99f277a1SAndrew Jeffery m.append(acked); 450*99f277a1SAndrew Jeffery 451*99f277a1SAndrew Jeffery try 452*99f277a1SAndrew Jeffery { 453*99f277a1SAndrew Jeffery auto reply = ctx->bus->call(m); 454*99f277a1SAndrew Jeffery 455*99f277a1SAndrew Jeffery /* Update our cache: Necessary because the signals do not carry a value 456*99f277a1SAndrew Jeffery */ 457*99f277a1SAndrew Jeffery ctx->bmc_events &= ~acked; 458*99f277a1SAndrew Jeffery 459*99f277a1SAndrew Jeffery *data_len = 0; 460*99f277a1SAndrew Jeffery } 461*99f277a1SAndrew Jeffery catch (const exception::SdBusError &e) 462*99f277a1SAndrew Jeffery { 463*99f277a1SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 464*99f277a1SAndrew Jeffery } 465*99f277a1SAndrew Jeffery 466*99f277a1SAndrew Jeffery return IPMI_CC_OK; 467*99f277a1SAndrew Jeffery } 468*99f277a1SAndrew Jeffery 4692c07f6f0SAndrew Jeffery static const hiomap_command hiomap_commands[] = { 4702c07f6f0SAndrew Jeffery [0] = NULL, /* 0 is an invalid command ID */ 4710a3358e7SAndrew Jeffery [1] = hiomap_reset, 4722c07f6f0SAndrew Jeffery [2] = hiomap_get_info, 473db688e9fSAndrew Jeffery [3] = hiomap_get_flash_info, 474a00f59baSAndrew Jeffery [4] = hiomap_create_read_window, 475b52822cdSAndrew Jeffery [5] = hiomap_close_window, 476a00f59baSAndrew Jeffery [6] = hiomap_create_write_window, 4779847f1c2SAndrew Jeffery [7] = hiomap_mark_dirty, 4787b225fb2SAndrew Jeffery [8] = hiomap_flush, 479*99f277a1SAndrew Jeffery [9] = hiomap_ack, 4802c07f6f0SAndrew Jeffery }; 4812c07f6f0SAndrew Jeffery 4822c07f6f0SAndrew Jeffery /* FIXME: Define this in the "right" place, wherever that is */ 4832c07f6f0SAndrew Jeffery /* FIXME: Double evaluation */ 4842c07f6f0SAndrew Jeffery #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 4852c07f6f0SAndrew Jeffery 4862c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_dispatch(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 4872c07f6f0SAndrew Jeffery ipmi_request_t request, 4882c07f6f0SAndrew Jeffery ipmi_response_t response, 4892c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 4902c07f6f0SAndrew Jeffery ipmi_context_t context) 4912c07f6f0SAndrew Jeffery { 4920a3358e7SAndrew Jeffery struct hiomap *ctx = static_cast<struct hiomap *>(context); 4930a3358e7SAndrew Jeffery 4942c07f6f0SAndrew Jeffery if (*data_len < 2) 4952c07f6f0SAndrew Jeffery { 4962c07f6f0SAndrew Jeffery *data_len = 0; 4972c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 4982c07f6f0SAndrew Jeffery } 4992c07f6f0SAndrew Jeffery 5002c07f6f0SAndrew Jeffery uint8_t *ipmi_req = (uint8_t *)request; 5012c07f6f0SAndrew Jeffery uint8_t *ipmi_resp = (uint8_t *)response; 5022c07f6f0SAndrew Jeffery uint8_t hiomap_cmd = ipmi_req[0]; 5032c07f6f0SAndrew Jeffery 5042c07f6f0SAndrew Jeffery if (hiomap_cmd == 0 || hiomap_cmd > ARRAY_SIZE(hiomap_commands) - 1) 5052c07f6f0SAndrew Jeffery { 5062c07f6f0SAndrew Jeffery *data_len = 0; 5072c07f6f0SAndrew Jeffery return IPMI_CC_PARM_OUT_OF_RANGE; 5082c07f6f0SAndrew Jeffery } 5092c07f6f0SAndrew Jeffery uint8_t *flash_req = ipmi_req + 2; 5102c07f6f0SAndrew Jeffery size_t flash_len = *data_len - 2; 5112c07f6f0SAndrew Jeffery uint8_t *flash_resp = ipmi_resp + 2; 5122c07f6f0SAndrew Jeffery 5132c07f6f0SAndrew Jeffery ipmi_ret_t cc = 5142c07f6f0SAndrew Jeffery hiomap_commands[hiomap_cmd](flash_req, flash_resp, &flash_len, context); 5152c07f6f0SAndrew Jeffery if (cc != IPMI_CC_OK) 5162c07f6f0SAndrew Jeffery { 5172c07f6f0SAndrew Jeffery *data_len = 0; 5182c07f6f0SAndrew Jeffery return cc; 5192c07f6f0SAndrew Jeffery } 5202c07f6f0SAndrew Jeffery 5212c07f6f0SAndrew Jeffery /* Populate the response command and sequence */ 5220a3358e7SAndrew Jeffery ipmi_resp[0] = hiomap_cmd; 5230a3358e7SAndrew Jeffery ipmi_resp[1] = ipmi_req[1]; 5242c07f6f0SAndrew Jeffery 5252c07f6f0SAndrew Jeffery *data_len = flash_len + 2; 5262c07f6f0SAndrew Jeffery 5272c07f6f0SAndrew Jeffery return cc; 5282c07f6f0SAndrew Jeffery } 5292c07f6f0SAndrew Jeffery } // namespace flash 5302c07f6f0SAndrew Jeffery } // namespace openpower 5312c07f6f0SAndrew Jeffery 5322c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() 5332c07f6f0SAndrew Jeffery { 5340a3358e7SAndrew Jeffery using namespace openpower::flash; 5350a3358e7SAndrew Jeffery 5360a3358e7SAndrew Jeffery /* FIXME: Clean this up? Can we unregister? */ 5370a3358e7SAndrew Jeffery struct hiomap *ctx = new hiomap(); 5380a3358e7SAndrew Jeffery 5390a3358e7SAndrew Jeffery /* Initialise mapping from signal and property names to status bit */ 5400a3358e7SAndrew Jeffery ctx->event_lookup["DaemonReady"] = BMC_EVENT_DAEMON_READY; 5410a3358e7SAndrew Jeffery ctx->event_lookup["FlashControlLost"] = BMC_EVENT_FLASH_CTRL_LOST; 5420a3358e7SAndrew Jeffery ctx->event_lookup["WindowReset"] = BMC_EVENT_WINDOW_RESET; 5430a3358e7SAndrew Jeffery ctx->event_lookup["ProtocolReset"] = BMC_EVENT_PROTOCOL_RESET; 5440a3358e7SAndrew Jeffery 5450a3358e7SAndrew Jeffery ctx->bus = new bus::bus(ipmid_get_sd_bus_connection()); 5460a3358e7SAndrew Jeffery 5470a3358e7SAndrew Jeffery /* Initialise signal handling */ 5480a3358e7SAndrew Jeffery 5490a3358e7SAndrew Jeffery /* 5500a3358e7SAndrew Jeffery * Can't use temporaries here because that causes SEGFAULTs due to slot 5510a3358e7SAndrew Jeffery * destruction (!?), so enjoy the weird wrapping. 5520a3358e7SAndrew Jeffery */ 5530a3358e7SAndrew Jeffery ctx->properties = 5540a3358e7SAndrew Jeffery new bus::match::match(std::move(hiomap_match_properties(ctx))); 5550a3358e7SAndrew Jeffery ctx->bmc_reboot = new bus::match::match( 5560a3358e7SAndrew Jeffery std::move(hiomap_match_signal_v2(ctx, "ProtocolReset"))); 5570a3358e7SAndrew Jeffery ctx->window_reset = new bus::match::match( 5580a3358e7SAndrew Jeffery std::move(hiomap_match_signal_v2(ctx, "WindowReset"))); 5590a3358e7SAndrew Jeffery 5600a3358e7SAndrew Jeffery ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, ctx, 5612c07f6f0SAndrew Jeffery openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE); 5622c07f6f0SAndrew Jeffery } 563