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; 5804d75136SAndrew Jeffery uint8_t seq; 590a3358e7SAndrew Jeffery }; 602c07f6f0SAndrew Jeffery 612c07f6f0SAndrew Jeffery /* TODO: Replace get/put with packed structs and direct assignment */ 62*5b355068SPatrick Venture template <typename T> 63*5b355068SPatrick Venture static inline T get(void* buf) 642c07f6f0SAndrew Jeffery { 652c07f6f0SAndrew Jeffery T t; 662c07f6f0SAndrew Jeffery memcpy(&t, buf, sizeof(t)); 672c07f6f0SAndrew Jeffery return t; 682c07f6f0SAndrew Jeffery } 692c07f6f0SAndrew Jeffery 70*5b355068SPatrick Venture template <typename T> 71*5b355068SPatrick Venture static inline void put(void* buf, T&& t) 722c07f6f0SAndrew Jeffery { 732c07f6f0SAndrew Jeffery memcpy(buf, &t, sizeof(t)); 742c07f6f0SAndrew Jeffery } 752c07f6f0SAndrew Jeffery 762c07f6f0SAndrew Jeffery typedef ipmi_ret_t (*hiomap_command)(ipmi_request_t req, ipmi_response_t resp, 772c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 782c07f6f0SAndrew Jeffery ipmi_context_t context); 792c07f6f0SAndrew Jeffery 802c07f6f0SAndrew Jeffery struct errno_cc_entry 812c07f6f0SAndrew Jeffery { 822c07f6f0SAndrew Jeffery int err; 832c07f6f0SAndrew Jeffery int cc; 842c07f6f0SAndrew Jeffery }; 852c07f6f0SAndrew Jeffery 862c07f6f0SAndrew Jeffery static const errno_cc_entry errno_cc_map[] = { 872c07f6f0SAndrew Jeffery {0, IPMI_CC_OK}, 882c07f6f0SAndrew Jeffery {EBUSY, IPMI_CC_BUSY}, 892c07f6f0SAndrew Jeffery {ENOTSUP, IPMI_CC_INVALID}, 902c07f6f0SAndrew Jeffery {ETIMEDOUT, 0xc3}, /* FIXME: Replace when defined in ipmid-api.h */ 912c07f6f0SAndrew Jeffery {ENOSPC, 0xc4}, /* FIXME: Replace when defined in ipmid-api.h */ 922c07f6f0SAndrew Jeffery {EINVAL, IPMI_CC_PARM_OUT_OF_RANGE}, 932c07f6f0SAndrew Jeffery {ENODEV, IPMI_CC_SENSOR_INVALID}, 942c07f6f0SAndrew Jeffery {EPERM, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 952c07f6f0SAndrew Jeffery {EACCES, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 962c07f6f0SAndrew Jeffery {-1, IPMI_CC_UNSPECIFIED_ERROR}, 972c07f6f0SAndrew Jeffery }; 982c07f6f0SAndrew Jeffery 992c07f6f0SAndrew Jeffery static int hiomap_xlate_errno(int err) 1002c07f6f0SAndrew Jeffery { 1012c07f6f0SAndrew Jeffery const errno_cc_entry* entry = &errno_cc_map[0]; 1022c07f6f0SAndrew Jeffery 1032c07f6f0SAndrew Jeffery while (!(entry->err == err || entry->err == -1)) 1042c07f6f0SAndrew Jeffery { 1052c07f6f0SAndrew Jeffery entry++; 1062c07f6f0SAndrew Jeffery } 1072c07f6f0SAndrew Jeffery 1082c07f6f0SAndrew Jeffery return entry->cc; 1092c07f6f0SAndrew Jeffery } 1102c07f6f0SAndrew Jeffery 1110a3358e7SAndrew Jeffery static void ipmi_hiomap_event_response(IpmiCmdData cmd, bool status) 1120a3358e7SAndrew Jeffery { 1130a3358e7SAndrew Jeffery using namespace phosphor::logging; 1140a3358e7SAndrew Jeffery 1150a3358e7SAndrew Jeffery if (!status) 1160a3358e7SAndrew Jeffery { 1170a3358e7SAndrew Jeffery log<level::ERR>("Failed to deliver host command", 1180a3358e7SAndrew Jeffery entry("SEL_COMMAND=%x:%x", cmd.first, cmd.second)); 1190a3358e7SAndrew Jeffery } 1200a3358e7SAndrew Jeffery } 1210a3358e7SAndrew Jeffery 1220a3358e7SAndrew Jeffery static int hiomap_handle_property_update(struct hiomap* ctx, 1230a3358e7SAndrew Jeffery sdbusplus::message::message& msg) 1240a3358e7SAndrew Jeffery { 1250a3358e7SAndrew Jeffery std::map<std::string, sdbusplus::message::variant<bool>> msgData; 1260a3358e7SAndrew Jeffery 1270a3358e7SAndrew Jeffery std::string iface; 1280a3358e7SAndrew Jeffery msg.read(iface, msgData); 1290a3358e7SAndrew Jeffery 1300a3358e7SAndrew Jeffery for (auto const& x : msgData) 1310a3358e7SAndrew Jeffery { 1320a3358e7SAndrew Jeffery if (!ctx->event_lookup.count(x.first)) 1330a3358e7SAndrew Jeffery { 1340a3358e7SAndrew Jeffery /* Unsupported event? */ 1350a3358e7SAndrew Jeffery continue; 1360a3358e7SAndrew Jeffery } 1370a3358e7SAndrew Jeffery 1380a3358e7SAndrew Jeffery uint8_t mask = ctx->event_lookup[x.first]; 1390a3358e7SAndrew Jeffery auto value = sdbusplus::message::variant_ns::get<bool>(x.second); 1400a3358e7SAndrew Jeffery 1410a3358e7SAndrew Jeffery if (value) 1420a3358e7SAndrew Jeffery { 1430a3358e7SAndrew Jeffery ctx->bmc_events |= mask; 1440a3358e7SAndrew Jeffery } 1450a3358e7SAndrew Jeffery else 1460a3358e7SAndrew Jeffery { 1470a3358e7SAndrew Jeffery ctx->bmc_events &= ~mask; 1480a3358e7SAndrew Jeffery } 1490a3358e7SAndrew Jeffery } 1500a3358e7SAndrew Jeffery 1510a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 1520a3358e7SAndrew Jeffery 1530a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 1540a3358e7SAndrew Jeffery 1550a3358e7SAndrew Jeffery return 0; 1560a3358e7SAndrew Jeffery } 1570a3358e7SAndrew Jeffery 1580a3358e7SAndrew Jeffery static bus::match::match hiomap_match_properties(struct hiomap* ctx) 1590a3358e7SAndrew Jeffery { 1600a3358e7SAndrew Jeffery auto properties = 1610a3358e7SAndrew Jeffery bus::match::rules::propertiesChanged(HIOMAPD_OBJECT, HIOMAPD_IFACE_V2); 1620a3358e7SAndrew Jeffery 1630a3358e7SAndrew Jeffery bus::match::match match( 1640a3358e7SAndrew Jeffery *ctx->bus, properties, 1650a3358e7SAndrew Jeffery std::bind(hiomap_handle_property_update, ctx, std::placeholders::_1)); 1660a3358e7SAndrew Jeffery 1670a3358e7SAndrew Jeffery return match; 1680a3358e7SAndrew Jeffery } 1690a3358e7SAndrew Jeffery 1700a3358e7SAndrew Jeffery static int hiomap_handle_signal_v2(struct hiomap* ctx, const char* name) 1710a3358e7SAndrew Jeffery { 1720a3358e7SAndrew Jeffery ctx->bmc_events |= ctx->event_lookup[name]; 1730a3358e7SAndrew Jeffery 1740a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 1750a3358e7SAndrew Jeffery 1760a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 1770a3358e7SAndrew Jeffery 1780a3358e7SAndrew Jeffery return 0; 1790a3358e7SAndrew Jeffery } 1800a3358e7SAndrew Jeffery 1810a3358e7SAndrew Jeffery static bus::match::match hiomap_match_signal_v2(struct hiomap* ctx, 1820a3358e7SAndrew Jeffery const char* name) 1830a3358e7SAndrew Jeffery { 1840a3358e7SAndrew Jeffery using namespace bus::match; 1850a3358e7SAndrew Jeffery 1860a3358e7SAndrew Jeffery auto signals = rules::type::signal() + rules::path(HIOMAPD_OBJECT) + 1870a3358e7SAndrew Jeffery rules::interface(HIOMAPD_IFACE_V2) + rules::member(name); 1880a3358e7SAndrew Jeffery 1890a3358e7SAndrew Jeffery bus::match::match match(*ctx->bus, signals, 1900a3358e7SAndrew Jeffery std::bind(hiomap_handle_signal_v2, ctx, name)); 1910a3358e7SAndrew Jeffery 1920a3358e7SAndrew Jeffery return match; 1930a3358e7SAndrew Jeffery } 1940a3358e7SAndrew Jeffery 1950a3358e7SAndrew Jeffery static ipmi_ret_t hiomap_reset(ipmi_request_t request, ipmi_response_t response, 1960a3358e7SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 1970a3358e7SAndrew Jeffery { 1980a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 1990a3358e7SAndrew Jeffery 2000a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 2010a3358e7SAndrew Jeffery HIOMAPD_IFACE, "Reset"); 2020a3358e7SAndrew Jeffery try 2030a3358e7SAndrew Jeffery { 2040a3358e7SAndrew Jeffery ctx->bus->call(m); 2050a3358e7SAndrew Jeffery 2060a3358e7SAndrew Jeffery *data_len = 0; 2070a3358e7SAndrew Jeffery } 2080a3358e7SAndrew Jeffery catch (const exception::SdBusError& e) 2090a3358e7SAndrew Jeffery { 2100a3358e7SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 2110a3358e7SAndrew Jeffery } 2120a3358e7SAndrew Jeffery 2130a3358e7SAndrew Jeffery return IPMI_CC_OK; 2140a3358e7SAndrew Jeffery } 2150a3358e7SAndrew Jeffery 2162c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_get_info(ipmi_request_t request, 2172c07f6f0SAndrew Jeffery ipmi_response_t response, 2182c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 2192c07f6f0SAndrew Jeffery ipmi_context_t context) 2202c07f6f0SAndrew Jeffery { 2210a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 2220a3358e7SAndrew Jeffery 2232c07f6f0SAndrew Jeffery if (*data_len < 1) 2242c07f6f0SAndrew Jeffery { 2252c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 2262c07f6f0SAndrew Jeffery } 2272c07f6f0SAndrew Jeffery 2282c07f6f0SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 2290a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 2300a3358e7SAndrew Jeffery HIOMAPD_IFACE, "GetInfo"); 2312c07f6f0SAndrew Jeffery m.append(reqdata[0]); 2322c07f6f0SAndrew Jeffery 2332c07f6f0SAndrew Jeffery try 2342c07f6f0SAndrew Jeffery { 2350a3358e7SAndrew Jeffery auto reply = ctx->bus->call(m); 2362c07f6f0SAndrew Jeffery 2372c07f6f0SAndrew Jeffery uint8_t version; 2382c07f6f0SAndrew Jeffery uint8_t blockSizeShift; 2392c07f6f0SAndrew Jeffery uint16_t timeout; 2402c07f6f0SAndrew Jeffery reply.read(version, blockSizeShift, timeout); 2412c07f6f0SAndrew Jeffery 2422c07f6f0SAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 2432c07f6f0SAndrew Jeffery 2442c07f6f0SAndrew Jeffery /* FIXME: Assumes v2! */ 2452c07f6f0SAndrew Jeffery put(&respdata[0], version); 2462c07f6f0SAndrew Jeffery put(&respdata[1], blockSizeShift); 2472c07f6f0SAndrew Jeffery put(&respdata[2], htole16(timeout)); 2482c07f6f0SAndrew Jeffery 2492c07f6f0SAndrew Jeffery *data_len = 4; 2502c07f6f0SAndrew Jeffery } 2512c07f6f0SAndrew Jeffery catch (const exception::SdBusError& e) 2522c07f6f0SAndrew Jeffery { 2532c07f6f0SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 2542c07f6f0SAndrew Jeffery } 2552c07f6f0SAndrew Jeffery 2562c07f6f0SAndrew Jeffery return IPMI_CC_OK; 2572c07f6f0SAndrew Jeffery } 2582c07f6f0SAndrew Jeffery 259db688e9fSAndrew Jeffery static ipmi_ret_t hiomap_get_flash_info(ipmi_request_t request, 260db688e9fSAndrew Jeffery ipmi_response_t response, 261db688e9fSAndrew Jeffery ipmi_data_len_t data_len, 262db688e9fSAndrew Jeffery ipmi_context_t context) 263db688e9fSAndrew Jeffery { 264db688e9fSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 265db688e9fSAndrew Jeffery 266db688e9fSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 267db688e9fSAndrew Jeffery HIOMAPD_IFACE_V2, "GetFlashInfo"); 268db688e9fSAndrew Jeffery try 269db688e9fSAndrew Jeffery { 270db688e9fSAndrew Jeffery auto reply = ctx->bus->call(m); 271db688e9fSAndrew Jeffery 272db688e9fSAndrew Jeffery uint16_t flashSize, eraseSize; 273db688e9fSAndrew Jeffery reply.read(flashSize, eraseSize); 274db688e9fSAndrew Jeffery 275db688e9fSAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 276db688e9fSAndrew Jeffery put(&respdata[0], htole16(flashSize)); 277db688e9fSAndrew Jeffery put(&respdata[2], htole16(eraseSize)); 278db688e9fSAndrew Jeffery 279db688e9fSAndrew Jeffery *data_len = 4; 280db688e9fSAndrew Jeffery } 281db688e9fSAndrew Jeffery catch (const exception::SdBusError& e) 282db688e9fSAndrew Jeffery { 283db688e9fSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 284db688e9fSAndrew Jeffery } 285db688e9fSAndrew Jeffery 286db688e9fSAndrew Jeffery return IPMI_CC_OK; 287db688e9fSAndrew Jeffery } 288db688e9fSAndrew Jeffery 289a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_window(struct hiomap* ctx, bool ro, 290a00f59baSAndrew Jeffery ipmi_request_t request, 291a00f59baSAndrew Jeffery ipmi_response_t response, 292a00f59baSAndrew Jeffery ipmi_data_len_t data_len) 293a00f59baSAndrew Jeffery { 294a00f59baSAndrew Jeffery if (*data_len < 4) 295a00f59baSAndrew Jeffery { 296a00f59baSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 297a00f59baSAndrew Jeffery } 298a00f59baSAndrew Jeffery 299a00f59baSAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 300a00f59baSAndrew Jeffery auto windowType = ro ? "CreateReadWindow" : "CreateWriteWindow"; 301a00f59baSAndrew Jeffery 302a00f59baSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 303a00f59baSAndrew Jeffery HIOMAPD_IFACE_V2, windowType); 304a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); 305a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); 306a00f59baSAndrew Jeffery 307a00f59baSAndrew Jeffery try 308a00f59baSAndrew Jeffery { 309a00f59baSAndrew Jeffery auto reply = ctx->bus->call(m); 310a00f59baSAndrew Jeffery 311a00f59baSAndrew Jeffery uint16_t lpcAddress, size, offset; 312a00f59baSAndrew Jeffery reply.read(lpcAddress, size, offset); 313a00f59baSAndrew Jeffery 314a00f59baSAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 315a00f59baSAndrew Jeffery 316a00f59baSAndrew Jeffery /* FIXME: Assumes v2! */ 317a00f59baSAndrew Jeffery put(&respdata[0], htole16(lpcAddress)); 318a00f59baSAndrew Jeffery put(&respdata[2], htole16(size)); 319a00f59baSAndrew Jeffery put(&respdata[4], htole16(offset)); 320a00f59baSAndrew Jeffery 321a00f59baSAndrew Jeffery *data_len = 6; 322a00f59baSAndrew Jeffery } 323a00f59baSAndrew Jeffery catch (const exception::SdBusError& e) 324a00f59baSAndrew Jeffery { 325a00f59baSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 326a00f59baSAndrew Jeffery } 327a00f59baSAndrew Jeffery 328a00f59baSAndrew Jeffery return IPMI_CC_OK; 329a00f59baSAndrew Jeffery } 330a00f59baSAndrew Jeffery 331a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_read_window(ipmi_request_t request, 332a00f59baSAndrew Jeffery ipmi_response_t response, 333a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 334a00f59baSAndrew Jeffery ipmi_context_t context) 335a00f59baSAndrew Jeffery { 336a00f59baSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 337a00f59baSAndrew Jeffery 338a00f59baSAndrew Jeffery return hiomap_create_window(ctx, true, request, response, data_len); 339a00f59baSAndrew Jeffery } 340a00f59baSAndrew Jeffery 341a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_write_window(ipmi_request_t request, 342a00f59baSAndrew Jeffery ipmi_response_t response, 343a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 344a00f59baSAndrew Jeffery ipmi_context_t context) 345a00f59baSAndrew Jeffery { 346a00f59baSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 347a00f59baSAndrew Jeffery 348a00f59baSAndrew Jeffery return hiomap_create_window(ctx, false, request, response, data_len); 349a00f59baSAndrew Jeffery } 350a00f59baSAndrew Jeffery 351b52822cdSAndrew Jeffery static ipmi_ret_t hiomap_close_window(ipmi_request_t request, 352b52822cdSAndrew Jeffery ipmi_response_t response, 353b52822cdSAndrew Jeffery ipmi_data_len_t data_len, 354b52822cdSAndrew Jeffery ipmi_context_t context) 355b52822cdSAndrew Jeffery { 356b52822cdSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 357b52822cdSAndrew Jeffery 358b52822cdSAndrew Jeffery if (*data_len < 1) 359b52822cdSAndrew Jeffery { 360b52822cdSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 361b52822cdSAndrew Jeffery } 362b52822cdSAndrew Jeffery 363b52822cdSAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 364b52822cdSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 365b52822cdSAndrew Jeffery HIOMAPD_IFACE_V2, "CloseWindow"); 366b52822cdSAndrew Jeffery m.append(reqdata[0]); 367b52822cdSAndrew Jeffery 368b52822cdSAndrew Jeffery try 369b52822cdSAndrew Jeffery { 370b52822cdSAndrew Jeffery auto reply = ctx->bus->call(m); 371b52822cdSAndrew Jeffery 372b52822cdSAndrew Jeffery *data_len = 0; 373b52822cdSAndrew Jeffery } 374b52822cdSAndrew Jeffery catch (const exception::SdBusError& e) 375b52822cdSAndrew Jeffery { 376b52822cdSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 377b52822cdSAndrew Jeffery } 378b52822cdSAndrew Jeffery 379b52822cdSAndrew Jeffery return IPMI_CC_OK; 380b52822cdSAndrew Jeffery } 381b52822cdSAndrew Jeffery 3829847f1c2SAndrew Jeffery static ipmi_ret_t hiomap_mark_dirty(ipmi_request_t request, 3839847f1c2SAndrew Jeffery ipmi_response_t response, 3849847f1c2SAndrew Jeffery ipmi_data_len_t data_len, 3859847f1c2SAndrew Jeffery ipmi_context_t context) 3869847f1c2SAndrew Jeffery { 3879847f1c2SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 3889847f1c2SAndrew Jeffery 3899847f1c2SAndrew Jeffery if (*data_len < 4) 3909847f1c2SAndrew Jeffery { 3919847f1c2SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 3929847f1c2SAndrew Jeffery } 3939847f1c2SAndrew Jeffery 3949847f1c2SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 3959847f1c2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 3969847f1c2SAndrew Jeffery HIOMAPD_IFACE_V2, "MarkDirty"); 3979847f1c2SAndrew Jeffery /* FIXME: Assumes v2 */ 3989847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 3999847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 4009847f1c2SAndrew Jeffery 4019847f1c2SAndrew Jeffery try 4029847f1c2SAndrew Jeffery { 4039847f1c2SAndrew Jeffery auto reply = ctx->bus->call(m); 4049847f1c2SAndrew Jeffery 4059847f1c2SAndrew Jeffery *data_len = 0; 4069847f1c2SAndrew Jeffery } 4079847f1c2SAndrew Jeffery catch (const exception::SdBusError& e) 4089847f1c2SAndrew Jeffery { 4099847f1c2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4109847f1c2SAndrew Jeffery } 4119847f1c2SAndrew Jeffery 4129847f1c2SAndrew Jeffery return IPMI_CC_OK; 4139847f1c2SAndrew Jeffery } 4149847f1c2SAndrew Jeffery 4157b225fb2SAndrew Jeffery static ipmi_ret_t hiomap_flush(ipmi_request_t request, ipmi_response_t response, 4167b225fb2SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 4177b225fb2SAndrew Jeffery { 4187b225fb2SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 4197b225fb2SAndrew Jeffery 4207b225fb2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 4217b225fb2SAndrew Jeffery HIOMAPD_IFACE_V2, "Flush"); 4227b225fb2SAndrew Jeffery 4237b225fb2SAndrew Jeffery try 4247b225fb2SAndrew Jeffery { 4257b225fb2SAndrew Jeffery /* FIXME: No argument call assumes v2 */ 4267b225fb2SAndrew Jeffery auto reply = ctx->bus->call(m); 4277b225fb2SAndrew Jeffery 4287b225fb2SAndrew Jeffery *data_len = 0; 4297b225fb2SAndrew Jeffery } 4307b225fb2SAndrew Jeffery catch (const exception::SdBusError& e) 4317b225fb2SAndrew Jeffery { 4327b225fb2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4337b225fb2SAndrew Jeffery } 4347b225fb2SAndrew Jeffery 4357b225fb2SAndrew Jeffery return IPMI_CC_OK; 4367b225fb2SAndrew Jeffery } 4377b225fb2SAndrew Jeffery 43899f277a1SAndrew Jeffery static ipmi_ret_t hiomap_ack(ipmi_request_t request, ipmi_response_t response, 43999f277a1SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 44099f277a1SAndrew Jeffery { 44199f277a1SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 44299f277a1SAndrew Jeffery 44399f277a1SAndrew Jeffery if (*data_len < 1) 44499f277a1SAndrew Jeffery { 44599f277a1SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 44699f277a1SAndrew Jeffery } 44799f277a1SAndrew Jeffery 44899f277a1SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 44999f277a1SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 45099f277a1SAndrew Jeffery HIOMAPD_IFACE_V2, "Ack"); 45199f277a1SAndrew Jeffery auto acked = reqdata[0]; 45299f277a1SAndrew Jeffery m.append(acked); 45399f277a1SAndrew Jeffery 45499f277a1SAndrew Jeffery try 45599f277a1SAndrew Jeffery { 45699f277a1SAndrew Jeffery auto reply = ctx->bus->call(m); 45799f277a1SAndrew Jeffery 45899f277a1SAndrew Jeffery /* Update our cache: Necessary because the signals do not carry a value 45999f277a1SAndrew Jeffery */ 46099f277a1SAndrew Jeffery ctx->bmc_events &= ~acked; 46199f277a1SAndrew Jeffery 46299f277a1SAndrew Jeffery *data_len = 0; 46399f277a1SAndrew Jeffery } 46499f277a1SAndrew Jeffery catch (const exception::SdBusError& e) 46599f277a1SAndrew Jeffery { 46699f277a1SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 46799f277a1SAndrew Jeffery } 46899f277a1SAndrew Jeffery 46999f277a1SAndrew Jeffery return IPMI_CC_OK; 47099f277a1SAndrew Jeffery } 47199f277a1SAndrew Jeffery 472a1e35b85SAndrew Jeffery static ipmi_ret_t hiomap_erase(ipmi_request_t request, ipmi_response_t response, 473a1e35b85SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 474a1e35b85SAndrew Jeffery { 475a1e35b85SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 476a1e35b85SAndrew Jeffery 477a1e35b85SAndrew Jeffery if (*data_len < 4) 478a1e35b85SAndrew Jeffery { 479a1e35b85SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 480a1e35b85SAndrew Jeffery } 481a1e35b85SAndrew Jeffery 482a1e35b85SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 483a1e35b85SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 484a1e35b85SAndrew Jeffery HIOMAPD_IFACE_V2, "Erase"); 485a1e35b85SAndrew Jeffery /* FIXME: Assumes v2 */ 486a1e35b85SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 487a1e35b85SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 488a1e35b85SAndrew Jeffery 489a1e35b85SAndrew Jeffery try 490a1e35b85SAndrew Jeffery { 491a1e35b85SAndrew Jeffery auto reply = ctx->bus->call(m); 492a1e35b85SAndrew Jeffery 493a1e35b85SAndrew Jeffery *data_len = 0; 494a1e35b85SAndrew Jeffery } 495a1e35b85SAndrew Jeffery catch (const exception::SdBusError& e) 496a1e35b85SAndrew Jeffery { 497a1e35b85SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 498a1e35b85SAndrew Jeffery } 499a1e35b85SAndrew Jeffery 500a1e35b85SAndrew Jeffery return IPMI_CC_OK; 501a1e35b85SAndrew Jeffery } 502a1e35b85SAndrew Jeffery 50304d75136SAndrew Jeffery #define HIOMAP_C_RESET 1 50404d75136SAndrew Jeffery #define HIOMAP_C_GET_INFO 2 50504d75136SAndrew Jeffery #define HIOMAP_C_GET_FLASH_INFO 3 50604d75136SAndrew Jeffery #define HIOMAP_C_CREATE_READ_WINDOW 4 50704d75136SAndrew Jeffery #define HIOMAP_C_CLOSE_WINDOW 5 50804d75136SAndrew Jeffery #define HIOMAP_C_CREATE_WRITE_WINDOW 6 50904d75136SAndrew Jeffery #define HIOMAP_C_MARK_DIRTY 7 51004d75136SAndrew Jeffery #define HIOMAP_C_FLUSH 8 51104d75136SAndrew Jeffery #define HIOMAP_C_ACK 9 51204d75136SAndrew Jeffery #define HIOMAP_C_ERASE 10 51304d75136SAndrew Jeffery 5142c07f6f0SAndrew Jeffery static const hiomap_command hiomap_commands[] = { 51504d75136SAndrew Jeffery [0] = NULL, /* Invalid command ID */ 51604d75136SAndrew Jeffery [HIOMAP_C_RESET] = hiomap_reset, 51704d75136SAndrew Jeffery [HIOMAP_C_GET_INFO] = hiomap_get_info, 51804d75136SAndrew Jeffery [HIOMAP_C_GET_FLASH_INFO] = hiomap_get_flash_info, 51904d75136SAndrew Jeffery [HIOMAP_C_CREATE_READ_WINDOW] = hiomap_create_read_window, 52004d75136SAndrew Jeffery [HIOMAP_C_CLOSE_WINDOW] = hiomap_close_window, 52104d75136SAndrew Jeffery [HIOMAP_C_CREATE_WRITE_WINDOW] = hiomap_create_write_window, 52204d75136SAndrew Jeffery [HIOMAP_C_MARK_DIRTY] = hiomap_mark_dirty, 52304d75136SAndrew Jeffery [HIOMAP_C_FLUSH] = hiomap_flush, 52404d75136SAndrew Jeffery [HIOMAP_C_ACK] = hiomap_ack, 52504d75136SAndrew Jeffery [HIOMAP_C_ERASE] = hiomap_erase, 5262c07f6f0SAndrew Jeffery }; 5272c07f6f0SAndrew Jeffery 5282c07f6f0SAndrew Jeffery /* FIXME: Define this in the "right" place, wherever that is */ 5292c07f6f0SAndrew Jeffery /* FIXME: Double evaluation */ 5302c07f6f0SAndrew Jeffery #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 5312c07f6f0SAndrew Jeffery 5322c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_dispatch(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 5332c07f6f0SAndrew Jeffery ipmi_request_t request, 5342c07f6f0SAndrew Jeffery ipmi_response_t response, 5352c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 5362c07f6f0SAndrew Jeffery ipmi_context_t context) 5372c07f6f0SAndrew Jeffery { 5380a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 5390a3358e7SAndrew Jeffery 5402c07f6f0SAndrew Jeffery if (*data_len < 2) 5412c07f6f0SAndrew Jeffery { 5422c07f6f0SAndrew Jeffery *data_len = 0; 5432c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 5442c07f6f0SAndrew Jeffery } 5452c07f6f0SAndrew Jeffery 5462c07f6f0SAndrew Jeffery uint8_t* ipmi_req = (uint8_t*)request; 5472c07f6f0SAndrew Jeffery uint8_t* ipmi_resp = (uint8_t*)response; 5482c07f6f0SAndrew Jeffery uint8_t hiomap_cmd = ipmi_req[0]; 5492c07f6f0SAndrew Jeffery 5502c07f6f0SAndrew Jeffery if (hiomap_cmd == 0 || hiomap_cmd > ARRAY_SIZE(hiomap_commands) - 1) 5512c07f6f0SAndrew Jeffery { 5522c07f6f0SAndrew Jeffery *data_len = 0; 5532c07f6f0SAndrew Jeffery return IPMI_CC_PARM_OUT_OF_RANGE; 5542c07f6f0SAndrew Jeffery } 55504d75136SAndrew Jeffery 55604d75136SAndrew Jeffery bool is_unversioned = 55704d75136SAndrew Jeffery (hiomap_cmd == HIOMAP_C_RESET || hiomap_cmd == HIOMAP_C_GET_INFO || 55804d75136SAndrew Jeffery hiomap_cmd == HIOMAP_C_ACK); 55904d75136SAndrew Jeffery if (!is_unversioned && ctx->seq == ipmi_req[1]) 56004d75136SAndrew Jeffery { 56104d75136SAndrew Jeffery *data_len = 0; 56204d75136SAndrew Jeffery return IPMI_CC_INVALID_FIELD_REQUEST; 56304d75136SAndrew Jeffery } 56404d75136SAndrew Jeffery 56504d75136SAndrew Jeffery ctx->seq = ipmi_req[1]; 56604d75136SAndrew Jeffery 5672c07f6f0SAndrew Jeffery uint8_t* flash_req = ipmi_req + 2; 5682c07f6f0SAndrew Jeffery size_t flash_len = *data_len - 2; 5692c07f6f0SAndrew Jeffery uint8_t* flash_resp = ipmi_resp + 2; 5702c07f6f0SAndrew Jeffery 5712c07f6f0SAndrew Jeffery ipmi_ret_t cc = 5722c07f6f0SAndrew Jeffery hiomap_commands[hiomap_cmd](flash_req, flash_resp, &flash_len, context); 5732c07f6f0SAndrew Jeffery if (cc != IPMI_CC_OK) 5742c07f6f0SAndrew Jeffery { 5752c07f6f0SAndrew Jeffery *data_len = 0; 5762c07f6f0SAndrew Jeffery return cc; 5772c07f6f0SAndrew Jeffery } 5782c07f6f0SAndrew Jeffery 5792c07f6f0SAndrew Jeffery /* Populate the response command and sequence */ 5800a3358e7SAndrew Jeffery ipmi_resp[0] = hiomap_cmd; 58104d75136SAndrew Jeffery ipmi_resp[1] = ctx->seq; 5822c07f6f0SAndrew Jeffery 5832c07f6f0SAndrew Jeffery *data_len = flash_len + 2; 5842c07f6f0SAndrew Jeffery 5852c07f6f0SAndrew Jeffery return cc; 5862c07f6f0SAndrew Jeffery } 5872c07f6f0SAndrew Jeffery } // namespace flash 5882c07f6f0SAndrew Jeffery } // namespace openpower 5892c07f6f0SAndrew Jeffery 5902c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() 5912c07f6f0SAndrew Jeffery { 5920a3358e7SAndrew Jeffery using namespace openpower::flash; 5930a3358e7SAndrew Jeffery 5940a3358e7SAndrew Jeffery /* FIXME: Clean this up? Can we unregister? */ 5950a3358e7SAndrew Jeffery struct hiomap* ctx = new hiomap(); 5960a3358e7SAndrew Jeffery 5970a3358e7SAndrew Jeffery /* Initialise mapping from signal and property names to status bit */ 5980a3358e7SAndrew Jeffery ctx->event_lookup["DaemonReady"] = BMC_EVENT_DAEMON_READY; 5990a3358e7SAndrew Jeffery ctx->event_lookup["FlashControlLost"] = BMC_EVENT_FLASH_CTRL_LOST; 6000a3358e7SAndrew Jeffery ctx->event_lookup["WindowReset"] = BMC_EVENT_WINDOW_RESET; 6010a3358e7SAndrew Jeffery ctx->event_lookup["ProtocolReset"] = BMC_EVENT_PROTOCOL_RESET; 6020a3358e7SAndrew Jeffery 6030a3358e7SAndrew Jeffery ctx->bus = new bus::bus(ipmid_get_sd_bus_connection()); 6040a3358e7SAndrew Jeffery 6050a3358e7SAndrew Jeffery /* Initialise signal handling */ 6060a3358e7SAndrew Jeffery 6070a3358e7SAndrew Jeffery /* 6080a3358e7SAndrew Jeffery * Can't use temporaries here because that causes SEGFAULTs due to slot 6090a3358e7SAndrew Jeffery * destruction (!?), so enjoy the weird wrapping. 6100a3358e7SAndrew Jeffery */ 6110a3358e7SAndrew Jeffery ctx->properties = 6120a3358e7SAndrew Jeffery new bus::match::match(std::move(hiomap_match_properties(ctx))); 6130a3358e7SAndrew Jeffery ctx->bmc_reboot = new bus::match::match( 6140a3358e7SAndrew Jeffery std::move(hiomap_match_signal_v2(ctx, "ProtocolReset"))); 6150a3358e7SAndrew Jeffery ctx->window_reset = new bus::match::match( 6160a3358e7SAndrew Jeffery std::move(hiomap_match_signal_v2(ctx, "WindowReset"))); 6170a3358e7SAndrew Jeffery 6180a3358e7SAndrew Jeffery ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, ctx, 6192c07f6f0SAndrew Jeffery openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE); 6202c07f6f0SAndrew Jeffery } 621