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 
286*a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_window(struct hiomap *ctx, bool ro,
287*a00f59baSAndrew Jeffery                                        ipmi_request_t request,
288*a00f59baSAndrew Jeffery                                        ipmi_response_t response,
289*a00f59baSAndrew Jeffery                                        ipmi_data_len_t data_len)
290*a00f59baSAndrew Jeffery {
291*a00f59baSAndrew Jeffery     if (*data_len < 4)
292*a00f59baSAndrew Jeffery     {
293*a00f59baSAndrew Jeffery         return IPMI_CC_REQ_DATA_LEN_INVALID;
294*a00f59baSAndrew Jeffery     }
295*a00f59baSAndrew Jeffery 
296*a00f59baSAndrew Jeffery     uint8_t *reqdata = (uint8_t *)request;
297*a00f59baSAndrew Jeffery     auto windowType = ro ? "CreateReadWindow" : "CreateWriteWindow";
298*a00f59baSAndrew Jeffery 
299*a00f59baSAndrew Jeffery     auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT,
300*a00f59baSAndrew Jeffery                                        HIOMAPD_IFACE_V2, windowType);
301*a00f59baSAndrew Jeffery     m.append(le16toh(get<uint16_t>(&reqdata[0])));
302*a00f59baSAndrew Jeffery     m.append(le16toh(get<uint16_t>(&reqdata[2])));
303*a00f59baSAndrew Jeffery 
304*a00f59baSAndrew Jeffery     try
305*a00f59baSAndrew Jeffery     {
306*a00f59baSAndrew Jeffery         auto reply = ctx->bus->call(m);
307*a00f59baSAndrew Jeffery 
308*a00f59baSAndrew Jeffery         uint16_t lpcAddress, size, offset;
309*a00f59baSAndrew Jeffery         reply.read(lpcAddress, size, offset);
310*a00f59baSAndrew Jeffery 
311*a00f59baSAndrew Jeffery         uint8_t *respdata = (uint8_t *)response;
312*a00f59baSAndrew Jeffery 
313*a00f59baSAndrew Jeffery         /* FIXME: Assumes v2! */
314*a00f59baSAndrew Jeffery         put(&respdata[0], htole16(lpcAddress));
315*a00f59baSAndrew Jeffery         put(&respdata[2], htole16(size));
316*a00f59baSAndrew Jeffery         put(&respdata[4], htole16(offset));
317*a00f59baSAndrew Jeffery 
318*a00f59baSAndrew Jeffery         *data_len = 6;
319*a00f59baSAndrew Jeffery     }
320*a00f59baSAndrew Jeffery     catch (const exception::SdBusError &e)
321*a00f59baSAndrew Jeffery     {
322*a00f59baSAndrew Jeffery         return hiomap_xlate_errno(e.get_errno());
323*a00f59baSAndrew Jeffery     }
324*a00f59baSAndrew Jeffery 
325*a00f59baSAndrew Jeffery     return IPMI_CC_OK;
326*a00f59baSAndrew Jeffery }
327*a00f59baSAndrew Jeffery 
328*a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_read_window(ipmi_request_t request,
329*a00f59baSAndrew Jeffery                                             ipmi_response_t response,
330*a00f59baSAndrew Jeffery                                             ipmi_data_len_t data_len,
331*a00f59baSAndrew Jeffery                                             ipmi_context_t context)
332*a00f59baSAndrew Jeffery {
333*a00f59baSAndrew Jeffery     struct hiomap *ctx = static_cast<struct hiomap *>(context);
334*a00f59baSAndrew Jeffery 
335*a00f59baSAndrew Jeffery     return hiomap_create_window(ctx, true, request, response, data_len);
336*a00f59baSAndrew Jeffery }
337*a00f59baSAndrew Jeffery 
338*a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_write_window(ipmi_request_t request,
339*a00f59baSAndrew Jeffery                                              ipmi_response_t response,
340*a00f59baSAndrew Jeffery                                              ipmi_data_len_t data_len,
341*a00f59baSAndrew Jeffery                                              ipmi_context_t context)
342*a00f59baSAndrew Jeffery {
343*a00f59baSAndrew Jeffery     struct hiomap *ctx = static_cast<struct hiomap *>(context);
344*a00f59baSAndrew Jeffery 
345*a00f59baSAndrew Jeffery     return hiomap_create_window(ctx, false, request, response, data_len);
346*a00f59baSAndrew Jeffery }
347*a00f59baSAndrew Jeffery 
3482c07f6f0SAndrew Jeffery static const hiomap_command hiomap_commands[] = {
3492c07f6f0SAndrew Jeffery     [0] = NULL, /* 0 is an invalid command ID */
3500a3358e7SAndrew Jeffery     [1] = hiomap_reset,
3512c07f6f0SAndrew Jeffery     [2] = hiomap_get_info,
352db688e9fSAndrew Jeffery     [3] = hiomap_get_flash_info,
353*a00f59baSAndrew Jeffery     [4] = hiomap_create_read_window,
354*a00f59baSAndrew Jeffery     [5] = NULL, /* CLOSE_WINDOW */
355*a00f59baSAndrew Jeffery     [6] = hiomap_create_write_window,
3562c07f6f0SAndrew Jeffery };
3572c07f6f0SAndrew Jeffery 
3582c07f6f0SAndrew Jeffery /* FIXME: Define this in the "right" place, wherever that is */
3592c07f6f0SAndrew Jeffery /* FIXME: Double evaluation */
3602c07f6f0SAndrew Jeffery #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
3612c07f6f0SAndrew Jeffery 
3622c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_dispatch(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
3632c07f6f0SAndrew Jeffery                                   ipmi_request_t request,
3642c07f6f0SAndrew Jeffery                                   ipmi_response_t response,
3652c07f6f0SAndrew Jeffery                                   ipmi_data_len_t data_len,
3662c07f6f0SAndrew Jeffery                                   ipmi_context_t context)
3672c07f6f0SAndrew Jeffery {
3680a3358e7SAndrew Jeffery     struct hiomap *ctx = static_cast<struct hiomap *>(context);
3690a3358e7SAndrew Jeffery 
3702c07f6f0SAndrew Jeffery     if (*data_len < 2)
3712c07f6f0SAndrew Jeffery     {
3722c07f6f0SAndrew Jeffery         *data_len = 0;
3732c07f6f0SAndrew Jeffery         return IPMI_CC_REQ_DATA_LEN_INVALID;
3742c07f6f0SAndrew Jeffery     }
3752c07f6f0SAndrew Jeffery 
3762c07f6f0SAndrew Jeffery     uint8_t *ipmi_req = (uint8_t *)request;
3772c07f6f0SAndrew Jeffery     uint8_t *ipmi_resp = (uint8_t *)response;
3782c07f6f0SAndrew Jeffery     uint8_t hiomap_cmd = ipmi_req[0];
3792c07f6f0SAndrew Jeffery 
3802c07f6f0SAndrew Jeffery     if (hiomap_cmd == 0 || hiomap_cmd > ARRAY_SIZE(hiomap_commands) - 1)
3812c07f6f0SAndrew Jeffery     {
3822c07f6f0SAndrew Jeffery         *data_len = 0;
3832c07f6f0SAndrew Jeffery         return IPMI_CC_PARM_OUT_OF_RANGE;
3842c07f6f0SAndrew Jeffery     }
3852c07f6f0SAndrew Jeffery     uint8_t *flash_req = ipmi_req + 2;
3862c07f6f0SAndrew Jeffery     size_t flash_len = *data_len - 2;
3872c07f6f0SAndrew Jeffery     uint8_t *flash_resp = ipmi_resp + 2;
3882c07f6f0SAndrew Jeffery 
3892c07f6f0SAndrew Jeffery     ipmi_ret_t cc =
3902c07f6f0SAndrew Jeffery         hiomap_commands[hiomap_cmd](flash_req, flash_resp, &flash_len, context);
3912c07f6f0SAndrew Jeffery     if (cc != IPMI_CC_OK)
3922c07f6f0SAndrew Jeffery     {
3932c07f6f0SAndrew Jeffery         *data_len = 0;
3942c07f6f0SAndrew Jeffery         return cc;
3952c07f6f0SAndrew Jeffery     }
3962c07f6f0SAndrew Jeffery 
3972c07f6f0SAndrew Jeffery     /* Populate the response command and sequence */
3980a3358e7SAndrew Jeffery     ipmi_resp[0] = hiomap_cmd;
3990a3358e7SAndrew Jeffery     ipmi_resp[1] = ipmi_req[1];
4002c07f6f0SAndrew Jeffery 
4012c07f6f0SAndrew Jeffery     *data_len = flash_len + 2;
4022c07f6f0SAndrew Jeffery 
4032c07f6f0SAndrew Jeffery     return cc;
4042c07f6f0SAndrew Jeffery }
4052c07f6f0SAndrew Jeffery } // namespace flash
4062c07f6f0SAndrew Jeffery } // namespace openpower
4072c07f6f0SAndrew Jeffery 
4082c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands()
4092c07f6f0SAndrew Jeffery {
4100a3358e7SAndrew Jeffery     using namespace openpower::flash;
4110a3358e7SAndrew Jeffery 
4120a3358e7SAndrew Jeffery     /* FIXME: Clean this up? Can we unregister? */
4130a3358e7SAndrew Jeffery     struct hiomap *ctx = new hiomap();
4140a3358e7SAndrew Jeffery 
4150a3358e7SAndrew Jeffery     /* Initialise mapping from signal and property names to status bit */
4160a3358e7SAndrew Jeffery     ctx->event_lookup["DaemonReady"] = BMC_EVENT_DAEMON_READY;
4170a3358e7SAndrew Jeffery     ctx->event_lookup["FlashControlLost"] = BMC_EVENT_FLASH_CTRL_LOST;
4180a3358e7SAndrew Jeffery     ctx->event_lookup["WindowReset"] = BMC_EVENT_WINDOW_RESET;
4190a3358e7SAndrew Jeffery     ctx->event_lookup["ProtocolReset"] = BMC_EVENT_PROTOCOL_RESET;
4200a3358e7SAndrew Jeffery 
4210a3358e7SAndrew Jeffery     ctx->bus = new bus::bus(ipmid_get_sd_bus_connection());
4220a3358e7SAndrew Jeffery 
4230a3358e7SAndrew Jeffery     /* Initialise signal handling */
4240a3358e7SAndrew Jeffery 
4250a3358e7SAndrew Jeffery     /*
4260a3358e7SAndrew Jeffery      * Can't use temporaries here because that causes SEGFAULTs due to slot
4270a3358e7SAndrew Jeffery      * destruction (!?), so enjoy the weird wrapping.
4280a3358e7SAndrew Jeffery      */
4290a3358e7SAndrew Jeffery     ctx->properties =
4300a3358e7SAndrew Jeffery         new bus::match::match(std::move(hiomap_match_properties(ctx)));
4310a3358e7SAndrew Jeffery     ctx->bmc_reboot = new bus::match::match(
4320a3358e7SAndrew Jeffery         std::move(hiomap_match_signal_v2(ctx, "ProtocolReset")));
4330a3358e7SAndrew Jeffery     ctx->window_reset = new bus::match::match(
4340a3358e7SAndrew Jeffery         std::move(hiomap_match_signal_v2(ctx, "WindowReset")));
4350a3358e7SAndrew Jeffery 
4360a3358e7SAndrew Jeffery     ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, ctx,
4372c07f6f0SAndrew Jeffery                            openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE);
4382c07f6f0SAndrew Jeffery }
439