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