12c07f6f0SAndrew Jeffery // SPDX-License-Identifier: Apache-2.0 22c07f6f0SAndrew Jeffery // Copyright (C) 2018 IBM Corp. 32c07f6f0SAndrew Jeffery 42c07f6f0SAndrew Jeffery #include "hiomap.hpp" 52c07f6f0SAndrew Jeffery 62c07f6f0SAndrew Jeffery #include <endian.h> 7*89707266SWilly Tu #include <ipmid/api.h> 8619207dcSAndrew Jeffery #include <signal.h> 9619207dcSAndrew Jeffery #include <string.h> 10619207dcSAndrew Jeffery #include <systemd/sd-bus.h> 11619207dcSAndrew Jeffery #include <systemd/sd-event.h> 122c07f6f0SAndrew Jeffery 13619207dcSAndrew Jeffery #include <cassert> 14ee70196bSPatrick Venture #include <cstring> 152c07f6f0SAndrew Jeffery #include <fstream> 160a3358e7SAndrew Jeffery #include <functional> 170a3358e7SAndrew Jeffery #include <iostream> 18*89707266SWilly Tu #include <ipmid-host/cmd-utils.hpp> 19*89707266SWilly Tu #include <ipmid-host/cmd.hpp> 20ee3064baSVernon Mauery #include <ipmid/api.hpp> 21ee70196bSPatrick Venture #include <map> 220a3358e7SAndrew Jeffery #include <phosphor-logging/log.hpp> 232c07f6f0SAndrew Jeffery #include <sdbusplus/bus.hpp> 240a3358e7SAndrew Jeffery #include <sdbusplus/bus/match.hpp> 252c07f6f0SAndrew Jeffery #include <sdbusplus/exception.hpp> 26ee70196bSPatrick Venture #include <string> 27ee70196bSPatrick Venture #include <tuple> 28*89707266SWilly Tu #include <unordered_map> 29ee70196bSPatrick Venture #include <utility> 302c07f6f0SAndrew Jeffery 31619207dcSAndrew Jeffery /* 32619207dcSAndrew Jeffery 33619207dcSAndrew Jeffery Design and integration notes 34619207dcSAndrew Jeffery ============================ 35619207dcSAndrew Jeffery 36619207dcSAndrew Jeffery The primary motivation of the Host I/O Mapping protocol (HIOMAP) is to mediate 37619207dcSAndrew Jeffery host access to a BMC-controlled flash chip housing the host's boot firmware. 38619207dcSAndrew Jeffery 39619207dcSAndrew Jeffery openpower-host-ipmi-flash facilitates the system design of transporting the 40619207dcSAndrew Jeffery HIOMAP protocol[1] over IPMI. This is somewhat abusive of IPMI, basically 41619207dcSAndrew Jeffery treating the BT interface as a mailbox with an interrupt each way between the 42619207dcSAndrew Jeffery BMC and the host. 43619207dcSAndrew Jeffery 44619207dcSAndrew Jeffery [1] https://github.com/openbmc/mboxbridge/blob/master/Documentation/protocol.md 45619207dcSAndrew Jeffery 46619207dcSAndrew Jeffery Using IPMI in this way has a number of challenges, a lot of them on the host 47619207dcSAndrew Jeffery side where we need to bring up the LPC and BT interfaces to enable IPMI before 48619207dcSAndrew Jeffery accessing the flash, and before any interrupts are enabled. There are also 49619207dcSAndrew Jeffery challenges on the BMC side with the design of the current implementation. We 50619207dcSAndrew Jeffery will cover those here. 51619207dcSAndrew Jeffery 52619207dcSAndrew Jeffery BMC-side System Design and Integration Issues 53619207dcSAndrew Jeffery --------------------------------------------- 54619207dcSAndrew Jeffery 55619207dcSAndrew Jeffery The current design is that we have the HIOMAP daemon, mboxd (to be renamed), 56619207dcSAndrew Jeffery exposing a set of DBus interfaces. Whilst the spec defines the IPMI transport 57619207dcSAndrew Jeffery message packing, mboxd knows nothing of IPMI itself, instead relying on the 58619207dcSAndrew Jeffery DBus interface to receive messages from ipmid. ipmid in-turn knows nothing of 59619207dcSAndrew Jeffery the interfaces communicating with it, also relying on DBus to receive messages 60619207dcSAndrew Jeffery from interface-specific daemons, e.g. btbridged[2]. 61619207dcSAndrew Jeffery 62619207dcSAndrew Jeffery [2] https://github.com/openbmc/btbridge 63619207dcSAndrew Jeffery 64619207dcSAndrew Jeffery For this design to function correctly we must ensure that the daemons are 65619207dcSAndrew Jeffery started and shut down in a reasonable order, however defining that order is 66619207dcSAndrew Jeffery somewhat tricky: 67619207dcSAndrew Jeffery 68619207dcSAndrew Jeffery 1. systemd uses Wants=/Before=/After= relationships in units to define both 69619207dcSAndrew Jeffery start-up *and* shutdown order, in stack push / pop order respectively. 70619207dcSAndrew Jeffery 2. Clearly ipmid depends on btbridged to receive messages sent by signals and 71619207dcSAndrew Jeffery replied to by method calls, so it needs a Wants=/After= relationship on 72619207dcSAndrew Jeffery btbridged 73619207dcSAndrew Jeffery 3. mboxd depends on ipmid to receive messages sent by method call, and issues a 74619207dcSAndrew Jeffery PropertiesChanged signal to notify of state changes. 75619207dcSAndrew Jeffery 76619207dcSAndrew Jeffery Point 3. suggests mboxd should have a Wants=/Before= relationship with ipmid to 77619207dcSAndrew Jeffery ensure ipmid can call into mboxd as messages arrive. However, this causes some 78619207dcSAndrew Jeffery grief with shutdown of the BMC, as mboxd needs to issue a state-change 79619207dcSAndrew Jeffery notification when it is shut down to inform the host that will not repsond to 80619207dcSAndrew Jeffery future requests and that the protocol state has been reset. If mboxd has a 81619207dcSAndrew Jeffery Wants=/Before= relationship with ipmid this message will never propagate to the 82619207dcSAndrew Jeffery host, as ipmid will be shut by systemd before mboxd. 83619207dcSAndrew Jeffery 84619207dcSAndrew Jeffery The above leads to mboxd having a Wants=/After= relationship with ipmid. This 85619207dcSAndrew Jeffery ensures that if mboxd is restarted on its own the correct state changes will be 86619207dcSAndrew Jeffery propagated to the host. The case where ipmid attempts to call into mboxd's DBus 87619207dcSAndrew Jeffery interface before mboxd is ready is mitigated by the ready bit in the protocol's 88619207dcSAndrew Jeffery BMC status, which will not yet be set, preventing a conforming host from 89619207dcSAndrew Jeffery attempting to contact mboxd. 90619207dcSAndrew Jeffery 91619207dcSAndrew Jeffery While this ordering prevents mboxd from being terminated before ipmid, there is 92619207dcSAndrew Jeffery no control over the *scheduling* of processes to ensure the PropertiesChanged 93619207dcSAndrew Jeffery signal emitted by mboxd before mboxd is terminated is seen by ipmid before 94619207dcSAndrew Jeffery *ipmid* is also terminated. This leads to our first implementation wart: 95619207dcSAndrew Jeffery 96619207dcSAndrew Jeffery On the basis that mboxd has a Wants=/After= relationship with ipmid, 97619207dcSAndrew Jeffery openpower-host-ipmi-flash will emit an HIOMAP BMC status event to the host 98619207dcSAndrew Jeffery with the value BMC_EVENT_PROTOCOL_RESET upon receiving SIGTERM iff the BMC 99619207dcSAndrew Jeffery state is not already set to BMC_EVENT_PROTOCOL_RESET. 100619207dcSAndrew Jeffery 101619207dcSAndrew Jeffery If ipmid has received SIGTERM the assumption is that it is systemd that is 102619207dcSAndrew Jeffery sending it, and that the Wants=/After= relationship requires that mboxd has 103619207dcSAndrew Jeffery been terminated before ipmid receives SIGTERM. By ensuring 104619207dcSAndrew Jeffery openpower-host-ipmi-flash emits the BMC event state we close the race where the 105619207dcSAndrew Jeffery host is not informed of the termination of mboxd due to scheduling ipmid (to 106619207dcSAndrew Jeffery deliver SIGTERM) prior to scheduling dbus-daemon, where the PropertiesChanged 107619207dcSAndrew Jeffery event would be delivered from mboxd to ipmid. 108619207dcSAndrew Jeffery 109619207dcSAndrew Jeffery Observations on the IPMI Specification and Design Details of ipmid 110619207dcSAndrew Jeffery ------------------------------------------------------------------ 111619207dcSAndrew Jeffery 112619207dcSAndrew Jeffery In addition to the system-level design problems with delivering 113619207dcSAndrew Jeffery PropertiesChanged signals during shutdown, IPMI specification and ipmid design 114619207dcSAndrew Jeffery issues exist that make it tedious to ensure that events will be correctly 115619207dcSAndrew Jeffery delivered to the host. 116619207dcSAndrew Jeffery 117619207dcSAndrew Jeffery The first necessary observation is that the mechanism for delivering BMC state 118619207dcSAndrew Jeffery change events from mboxd to the host over IPMI uses the SMS ATN bit to indicate 119619207dcSAndrew Jeffery a message is ready for delivery from the BMC to the host system. Retrieving the 120619207dcSAndrew Jeffery BMC state data involves the host recognising that the SMS ATN bit is set, 121619207dcSAndrew Jeffery performing Get Message Flags transaction with the BMC followed by a subsequent 122619207dcSAndrew Jeffery Get Message transaction. Thus, delivery of the HIOMAP protocol's BMC status is 123619207dcSAndrew Jeffery not an atomic event. 124619207dcSAndrew Jeffery 125619207dcSAndrew Jeffery The second necessary observation is that the kernel delivers signals 126619207dcSAndrew Jeffery asynchronously. This couples badly with IPMI's event delivery not being atomic: 127619207dcSAndrew Jeffery ipmid can win the race against SIGTERM to receive the PropertiesChanged event 128619207dcSAndrew Jeffery from mboxd, but lose the race to complete delivery to the host. 129619207dcSAndrew Jeffery 130619207dcSAndrew Jeffery On this basis, we need to block the delivery of SIGTERM to ipmid until ipmid 131619207dcSAndrew Jeffery has completed the set of `SMS ATN`/`Get Message Flags`/`Get Message` 132619207dcSAndrew Jeffery transactions with the host 133619207dcSAndrew Jeffery 134619207dcSAndrew Jeffery One approach to this would be to configure a custom SIGTERM handler that sets 135619207dcSAndrew Jeffery some global application state to indicate that SIGTERM has been delivered. A 136619207dcSAndrew Jeffery better approach that avoids the need for global application state is to simply 137619207dcSAndrew Jeffery block the signal until we are ready to handle it, which we can do via 138619207dcSAndrew Jeffery sigprocmask(2). 139619207dcSAndrew Jeffery 140619207dcSAndrew Jeffery The existing design of ipmid makes it feasible to block and unblock 141619207dcSAndrew Jeffery asynchronous SIGTERM as we require. ipmid_send_cmd_to_host() takes a CallBack 142619207dcSAndrew Jeffery function as an argument, which is invoked by 143619207dcSAndrew Jeffery phosphor::host::command::Manager::getNextCommand(). The documentation for 144619207dcSAndrew Jeffery phosphor::host::command::Manager::getNextCommand() says: 145619207dcSAndrew Jeffery 146619207dcSAndrew Jeffery @brief Extracts the next entry in the queue and returns 147619207dcSAndrew Jeffery Command and data part of it. 148619207dcSAndrew Jeffery 149619207dcSAndrew Jeffery @detail Also calls into the registered handlers so that they can now 150619207dcSAndrew Jeffery send the CommandComplete signal since the interface contract 151619207dcSAndrew Jeffery is that we emit this signal once the message has been 152619207dcSAndrew Jeffery passed to the host (which is required when calling this) 153619207dcSAndrew Jeffery 154619207dcSAndrew Jeffery Also, if the queue has more commands, then it will alert the 155619207dcSAndrew Jeffery host 156619207dcSAndrew Jeffery 157619207dcSAndrew Jeffery However, its description is not entirely accurate. The callback function is 158619207dcSAndrew Jeffery invoked when ipmid *dequeues* the data to send to the host: Delivery of the 159619207dcSAndrew Jeffery data to the host occurs at some *after* the callback has been invoked. 160619207dcSAndrew Jeffery 161619207dcSAndrew Jeffery Invoking the callback before completion of delivery of the data to the host 162619207dcSAndrew Jeffery nullifies the approach of unblocking asynchronous SIGTERM in the callback 163619207dcSAndrew Jeffery associated with sending the HIOMAP BMC state event to the host, as the BMC 164619207dcSAndrew Jeffery kernel can asynchronously terminate the process between the callback being 165619207dcSAndrew Jeffery invoked and the host receiving the BMC state event data. 166619207dcSAndrew Jeffery 167619207dcSAndrew Jeffery Overcoming this issue hinges on a significant implementation detail of ipmid: 168619207dcSAndrew Jeffery 169619207dcSAndrew Jeffery ipmid uses an sd_event loop in the main function to pump DBus events. 170619207dcSAndrew Jeffery 171619207dcSAndrew Jeffery This leads to a third necessary observation: 172619207dcSAndrew Jeffery 173619207dcSAndrew Jeffery sd_event can be used to process UNIX signals as well as other events by way 174619207dcSAndrew Jeffery of Linux's signalfd(2) interface. 175619207dcSAndrew Jeffery 176619207dcSAndrew Jeffery The fact that sd_event is used to pump DBus events means that ipmid can remain 177619207dcSAndrew Jeffery a single-threaded process. By remaining single-threaded we know that events 178619207dcSAndrew Jeffery processing is sequencial and no two events can be processed simultaneously. A 179619207dcSAndrew Jeffery corollary of this is that DBus events and UNIX signals are serialised with 180619207dcSAndrew Jeffery respect to eachother. 181619207dcSAndrew Jeffery 182619207dcSAndrew Jeffery The fourth necessary observation is that we do not need to pump sd_event in 183619207dcSAndrew Jeffery order to complete DBus method calls; sd_bus will handle the pumping independent 184619207dcSAndrew Jeffery of the main loop in order to complete the method invocation. 185619207dcSAndrew Jeffery 186619207dcSAndrew Jeffery Implementing Reliable HIOMAP BMC Status Event Delivery 187619207dcSAndrew Jeffery ------------------------------------------------------ 188619207dcSAndrew Jeffery 189619207dcSAndrew Jeffery We achieve reliable delivery of HIOMAP BMC status events in the following way: 190619207dcSAndrew Jeffery 191619207dcSAndrew Jeffery 1. During plugin initialisation, mask SIGTERM using sigprocmask(2) 192619207dcSAndrew Jeffery 2. Subsequent to masking SIGTERM, register 193619207dcSAndrew Jeffery openpower::flash::hiomap_protocol_reset() as the SIGTERM handler using 194619207dcSAndrew Jeffery sd_event_add_signal() to hook a signalfd(2) into sd_event 195619207dcSAndrew Jeffery 3. openpower::flash::hiomap_protocol_reset() implements the logic to send the 196619207dcSAndrew Jeffery BMC_EVENT_PROTOCOL_RESET state to the host if necessary, otherwise terminate 197619207dcSAndrew Jeffery the sd_event loop. 198619207dcSAndrew Jeffery 4. If it is necessary to send BMC_EVENT_PROTOCOL_RESET to the host in 3, assign 199619207dcSAndrew Jeffery a callback handler that terminates the sd_event loop, which is only 200619207dcSAndrew Jeffery processed after the current iteration is complete. 201619207dcSAndrew Jeffery 202619207dcSAndrew Jeffery This process and its use of signalfd integration in the sd_event loop 203619207dcSAndrew Jeffery eliminates the following three races: 204619207dcSAndrew Jeffery 205619207dcSAndrew Jeffery 1. The scheduler race between mboxd, dbus-daemon and ipmid, by having 206619207dcSAndrew Jeffery openpower-host-ipmi-flash conditionally deliver the protocol reset event if 207619207dcSAndrew Jeffery no such message has been received from mboxd 208619207dcSAndrew Jeffery 2. The race between delivering the BMC status event to the host and ipmid 209619207dcSAndrew Jeffery receiving asynchronous SIGTERM after receiving the PropertiesChanged event 210619207dcSAndrew Jeffery from mboxd 211619207dcSAndrew Jeffery 3. The race to deliver the BMC status data to the host after unblocking 212619207dcSAndrew Jeffery asynchronous SIGTERM in the host command callback and before receiving 213619207dcSAndrew Jeffery asynchronous SIGTERM. 214619207dcSAndrew Jeffery 215619207dcSAndrew Jeffery Ultimately, ipmid could benefit from a redesign that fires the callback *after* 216619207dcSAndrew Jeffery delivering the associated data to the host, but brief inspection determined 217619207dcSAndrew Jeffery that this involved a non-trivial amount of effort. 218619207dcSAndrew Jeffery 219619207dcSAndrew Jeffery */ 220619207dcSAndrew Jeffery 2212c07f6f0SAndrew Jeffery using namespace sdbusplus; 2220a3358e7SAndrew Jeffery using namespace phosphor::host::command; 2232c07f6f0SAndrew Jeffery 2242c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() __attribute__((constructor)); 2252c07f6f0SAndrew Jeffery 2262c07f6f0SAndrew Jeffery namespace openpower 2272c07f6f0SAndrew Jeffery { 2282c07f6f0SAndrew Jeffery namespace flash 2292c07f6f0SAndrew Jeffery { 2300a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_DAEMON_READY = 1 << 7; 2310a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_FLASH_CTRL_LOST = 1 << 6; 2320a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_WINDOW_RESET = 1 << 1; 2330a3358e7SAndrew Jeffery constexpr auto BMC_EVENT_PROTOCOL_RESET = 1 << 0; 2340a3358e7SAndrew Jeffery 2350a3358e7SAndrew Jeffery constexpr auto IPMI_CMD_HIOMAP_EVENT = 0x0f; 2360a3358e7SAndrew Jeffery 2370a3358e7SAndrew Jeffery constexpr auto HIOMAPD_SERVICE = "xyz.openbmc_project.Hiomapd"; 2380a3358e7SAndrew Jeffery constexpr auto HIOMAPD_OBJECT = "/xyz/openbmc_project/Hiomapd"; 2390a3358e7SAndrew Jeffery constexpr auto HIOMAPD_IFACE = "xyz.openbmc_project.Hiomapd.Protocol"; 2400a3358e7SAndrew Jeffery constexpr auto HIOMAPD_IFACE_V2 = "xyz.openbmc_project.Hiomapd.Protocol.V2"; 2410a3358e7SAndrew Jeffery 2420a3358e7SAndrew Jeffery constexpr auto DBUS_IFACE_PROPERTIES = "org.freedesktop.DBus.Properties"; 2430a3358e7SAndrew Jeffery 244619207dcSAndrew Jeffery /* XXX: ipmid is currently single-threaded, pumping dbus events in sequence 245619207dcSAndrew Jeffery * via the main event loop. Thus the code is not forced to be re-entrant. We 246619207dcSAndrew Jeffery * also know that the callback and DBus event handling will not be running 247619207dcSAndrew Jeffery * concurrently. 248619207dcSAndrew Jeffery * 249619207dcSAndrew Jeffery * ipmid_send_cmd_to_host() takes a callback that doesn't define a context 250619207dcSAndrew Jeffery * pointer, so instead use a global. active_event_updates gates manipulation of 251619207dcSAndrew Jeffery * process state, so its definition as a global at least aligns with its use. 252619207dcSAndrew Jeffery */ 253619207dcSAndrew Jeffery static int active_event_updates; 254619207dcSAndrew Jeffery 2550a3358e7SAndrew Jeffery struct hiomap 2560a3358e7SAndrew Jeffery { 2570a3358e7SAndrew Jeffery bus::bus* bus; 2580a3358e7SAndrew Jeffery 2590a3358e7SAndrew Jeffery /* Signals */ 2600a3358e7SAndrew Jeffery bus::match::match* properties; 2610a3358e7SAndrew Jeffery 2620a3358e7SAndrew Jeffery /* Protocol state */ 2630a3358e7SAndrew Jeffery std::map<std::string, int> event_lookup; 2640a3358e7SAndrew Jeffery uint8_t bmc_events; 26504d75136SAndrew Jeffery uint8_t seq; 2660a3358e7SAndrew Jeffery }; 2672c07f6f0SAndrew Jeffery 268ee3064baSVernon Mauery SignalResponse sigtermResponse = SignalResponse::continueExecution; 269ee3064baSVernon Mauery 2702c07f6f0SAndrew Jeffery /* TODO: Replace get/put with packed structs and direct assignment */ 2715b355068SPatrick Venture template <typename T> 2725b355068SPatrick Venture static inline T get(void* buf) 2732c07f6f0SAndrew Jeffery { 2742c07f6f0SAndrew Jeffery T t; 275ee70196bSPatrick Venture std::memcpy(&t, buf, sizeof(t)); 2762c07f6f0SAndrew Jeffery return t; 2772c07f6f0SAndrew Jeffery } 2782c07f6f0SAndrew Jeffery 2795b355068SPatrick Venture template <typename T> 2805b355068SPatrick Venture static inline void put(void* buf, T&& t) 2812c07f6f0SAndrew Jeffery { 282ee70196bSPatrick Venture std::memcpy(buf, &t, sizeof(t)); 2832c07f6f0SAndrew Jeffery } 2842c07f6f0SAndrew Jeffery 285*89707266SWilly Tu using hiomap_command = 286*89707266SWilly Tu std::function<ipmi_ret_t(ipmi_request_t req, ipmi_response_t resp, 287*89707266SWilly Tu ipmi_data_len_t data_len, ipmi_context_t context)>; 2882c07f6f0SAndrew Jeffery struct errno_cc_entry 2892c07f6f0SAndrew Jeffery { 2902c07f6f0SAndrew Jeffery int err; 2912c07f6f0SAndrew Jeffery int cc; 2922c07f6f0SAndrew Jeffery }; 2932c07f6f0SAndrew Jeffery 2942c07f6f0SAndrew Jeffery static const errno_cc_entry errno_cc_map[] = { 2952c07f6f0SAndrew Jeffery {0, IPMI_CC_OK}, 2962c07f6f0SAndrew Jeffery {EBUSY, IPMI_CC_BUSY}, 2972c07f6f0SAndrew Jeffery {ENOTSUP, IPMI_CC_INVALID}, 2982c07f6f0SAndrew Jeffery {ETIMEDOUT, 0xc3}, /* FIXME: Replace when defined in ipmid-api.h */ 2992c07f6f0SAndrew Jeffery {ENOSPC, 0xc4}, /* FIXME: Replace when defined in ipmid-api.h */ 3002c07f6f0SAndrew Jeffery {EINVAL, IPMI_CC_PARM_OUT_OF_RANGE}, 3012c07f6f0SAndrew Jeffery {ENODEV, IPMI_CC_SENSOR_INVALID}, 3022c07f6f0SAndrew Jeffery {EPERM, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 3032c07f6f0SAndrew Jeffery {EACCES, IPMI_CC_INSUFFICIENT_PRIVILEGE}, 3042c07f6f0SAndrew Jeffery {-1, IPMI_CC_UNSPECIFIED_ERROR}, 3052c07f6f0SAndrew Jeffery }; 3062c07f6f0SAndrew Jeffery 3072c07f6f0SAndrew Jeffery static int hiomap_xlate_errno(int err) 3082c07f6f0SAndrew Jeffery { 3092c07f6f0SAndrew Jeffery const errno_cc_entry* entry = &errno_cc_map[0]; 3102c07f6f0SAndrew Jeffery 3112c07f6f0SAndrew Jeffery while (!(entry->err == err || entry->err == -1)) 3122c07f6f0SAndrew Jeffery { 3132c07f6f0SAndrew Jeffery entry++; 3142c07f6f0SAndrew Jeffery } 3152c07f6f0SAndrew Jeffery 3162c07f6f0SAndrew Jeffery return entry->cc; 3172c07f6f0SAndrew Jeffery } 3182c07f6f0SAndrew Jeffery 3190a3358e7SAndrew Jeffery static void ipmi_hiomap_event_response(IpmiCmdData cmd, bool status) 3200a3358e7SAndrew Jeffery { 3210a3358e7SAndrew Jeffery using namespace phosphor::logging; 3220a3358e7SAndrew Jeffery 3230a3358e7SAndrew Jeffery if (!status) 3240a3358e7SAndrew Jeffery { 3250a3358e7SAndrew Jeffery log<level::ERR>("Failed to deliver host command", 3260a3358e7SAndrew Jeffery entry("SEL_COMMAND=%x:%x", cmd.first, cmd.second)); 3270a3358e7SAndrew Jeffery } 328619207dcSAndrew Jeffery 329619207dcSAndrew Jeffery assert(active_event_updates); 330619207dcSAndrew Jeffery active_event_updates--; 331619207dcSAndrew Jeffery if (!active_event_updates) 332619207dcSAndrew Jeffery { 333ee3064baSVernon Mauery sigtermResponse = SignalResponse::continueExecution; 334619207dcSAndrew Jeffery log<level::DEBUG>("Unblocked SIGTERM"); 335619207dcSAndrew Jeffery } 336619207dcSAndrew Jeffery } 3370a3358e7SAndrew Jeffery 3380a3358e7SAndrew Jeffery static int hiomap_handle_property_update(struct hiomap* ctx, 3390a3358e7SAndrew Jeffery sdbusplus::message::message& msg) 3400a3358e7SAndrew Jeffery { 341619207dcSAndrew Jeffery using namespace phosphor::logging; 342619207dcSAndrew Jeffery 34380d5bcafSPatrick Williams std::map<std::string, std::variant<bool>> msgData; 344619207dcSAndrew Jeffery 345ee3064baSVernon Mauery sigtermResponse = SignalResponse::breakExecution; 346619207dcSAndrew Jeffery if (!active_event_updates) 347619207dcSAndrew Jeffery { 348ee3064baSVernon Mauery sigtermResponse = SignalResponse::breakExecution; 349619207dcSAndrew Jeffery log<level::DEBUG>("Blocked SIGTERM"); 350619207dcSAndrew Jeffery } 351619207dcSAndrew Jeffery active_event_updates++; 3520a3358e7SAndrew Jeffery 3530a3358e7SAndrew Jeffery std::string iface; 3540a3358e7SAndrew Jeffery msg.read(iface, msgData); 3550a3358e7SAndrew Jeffery 3560a3358e7SAndrew Jeffery for (auto const& x : msgData) 3570a3358e7SAndrew Jeffery { 3580a3358e7SAndrew Jeffery if (!ctx->event_lookup.count(x.first)) 3590a3358e7SAndrew Jeffery { 3600a3358e7SAndrew Jeffery /* Unsupported event? */ 3610a3358e7SAndrew Jeffery continue; 3620a3358e7SAndrew Jeffery } 3630a3358e7SAndrew Jeffery 3640a3358e7SAndrew Jeffery uint8_t mask = ctx->event_lookup[x.first]; 3653d420921SPatrick Williams auto value = std::get<bool>(x.second); 3660a3358e7SAndrew Jeffery 3670a3358e7SAndrew Jeffery if (value) 3680a3358e7SAndrew Jeffery { 3690a3358e7SAndrew Jeffery ctx->bmc_events |= mask; 3700a3358e7SAndrew Jeffery } 3710a3358e7SAndrew Jeffery else 3720a3358e7SAndrew Jeffery { 3730a3358e7SAndrew Jeffery ctx->bmc_events &= ~mask; 3740a3358e7SAndrew Jeffery } 3750a3358e7SAndrew Jeffery } 3760a3358e7SAndrew Jeffery 3770a3358e7SAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); 3780a3358e7SAndrew Jeffery 3790a3358e7SAndrew Jeffery ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); 3800a3358e7SAndrew Jeffery 3810a3358e7SAndrew Jeffery return 0; 3820a3358e7SAndrew Jeffery } 3830a3358e7SAndrew Jeffery 384*89707266SWilly Tu static int hiomap_protocol_reset_response([[maybe_unused]] IpmiCmdData cmd, 385*89707266SWilly Tu [[maybe_unused]] bool status) 386619207dcSAndrew Jeffery { 387ee3064baSVernon Mauery // If this is running in signal context, ipmid will shutdown 388ee3064baSVernon Mauery // the event queue as the last signal handler 389d4b7f5e4SAdriana Kobylak sigtermResponse = SignalResponse::continueExecution; 390ee3064baSVernon Mauery return 0; 391619207dcSAndrew Jeffery } 392619207dcSAndrew Jeffery 393ee3064baSVernon Mauery static int hiomap_protocol_reset(struct hiomap* ctx) 394619207dcSAndrew Jeffery { 395619207dcSAndrew Jeffery if (ctx->bmc_events == BMC_EVENT_PROTOCOL_RESET) 396619207dcSAndrew Jeffery { 397ee3064baSVernon Mauery // If this is running in signal context, ipmid will shutdown 398ee3064baSVernon Mauery // the event queue as the last signal handler 399d4b7f5e4SAdriana Kobylak sigtermResponse = SignalResponse::continueExecution; 400ee3064baSVernon Mauery return 0; 401619207dcSAndrew Jeffery } 402619207dcSAndrew Jeffery 403619207dcSAndrew Jeffery /* 404619207dcSAndrew Jeffery * Send an attention indicating the hiomapd has died 405619207dcSAndrew Jeffery * (BMC_EVENT_DAEMON_READY cleared) and that the protocol has been reset 406619207dcSAndrew Jeffery * (BMC_EVENT_PROTOCOL_RESET set) to indicate to the host that it needs to 407619207dcSAndrew Jeffery * wait for the BMC to come back and renegotiate the protocol. 408619207dcSAndrew Jeffery * 409619207dcSAndrew Jeffery * We know this to be the case in systems that integrate 410619207dcSAndrew Jeffery * openpower-host-ipmi-flash, as hiomapd's unit depends on 411619207dcSAndrew Jeffery * phosphor-ipmi-host, and thus hiomapd has been terminated before ipmid 412619207dcSAndrew Jeffery * receives SIGTERM. 413619207dcSAndrew Jeffery */ 414619207dcSAndrew Jeffery auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, BMC_EVENT_PROTOCOL_RESET); 415619207dcSAndrew Jeffery 416619207dcSAndrew Jeffery auto cmdHandler = std::make_tuple(cmd, hiomap_protocol_reset_response); 417619207dcSAndrew Jeffery ipmid_send_cmd_to_host(cmdHandler); 418619207dcSAndrew Jeffery 419619207dcSAndrew Jeffery return 0; 420619207dcSAndrew Jeffery } 421619207dcSAndrew Jeffery 4220a3358e7SAndrew Jeffery static bus::match::match hiomap_match_properties(struct hiomap* ctx) 4230a3358e7SAndrew Jeffery { 4240a3358e7SAndrew Jeffery auto properties = 4250a3358e7SAndrew Jeffery bus::match::rules::propertiesChanged(HIOMAPD_OBJECT, HIOMAPD_IFACE_V2); 4260a3358e7SAndrew Jeffery 4270a3358e7SAndrew Jeffery bus::match::match match( 4280a3358e7SAndrew Jeffery *ctx->bus, properties, 4290a3358e7SAndrew Jeffery std::bind(hiomap_handle_property_update, ctx, std::placeholders::_1)); 4300a3358e7SAndrew Jeffery 4310a3358e7SAndrew Jeffery return match; 4320a3358e7SAndrew Jeffery } 4330a3358e7SAndrew Jeffery 434*89707266SWilly Tu static ipmi_ret_t hiomap_reset([[maybe_unused]] ipmi_request_t request, 435*89707266SWilly Tu [[maybe_unused]] ipmi_response_t response, 4360a3358e7SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 4370a3358e7SAndrew Jeffery { 4380a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 4390a3358e7SAndrew Jeffery 4400a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 4410a3358e7SAndrew Jeffery HIOMAPD_IFACE, "Reset"); 4420a3358e7SAndrew Jeffery try 4430a3358e7SAndrew Jeffery { 4440a3358e7SAndrew Jeffery ctx->bus->call(m); 4450a3358e7SAndrew Jeffery 4460a3358e7SAndrew Jeffery *data_len = 0; 4470a3358e7SAndrew Jeffery } 44895510386SPatrick Williams catch (const exception::exception& e) 4490a3358e7SAndrew Jeffery { 4500a3358e7SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4510a3358e7SAndrew Jeffery } 4520a3358e7SAndrew Jeffery 4530a3358e7SAndrew Jeffery return IPMI_CC_OK; 4540a3358e7SAndrew Jeffery } 4550a3358e7SAndrew Jeffery 4562c07f6f0SAndrew Jeffery static ipmi_ret_t hiomap_get_info(ipmi_request_t request, 4572c07f6f0SAndrew Jeffery ipmi_response_t response, 4582c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 4592c07f6f0SAndrew Jeffery ipmi_context_t context) 4602c07f6f0SAndrew Jeffery { 4610a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 4620a3358e7SAndrew Jeffery 4632c07f6f0SAndrew Jeffery if (*data_len < 1) 4642c07f6f0SAndrew Jeffery { 4652c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 4662c07f6f0SAndrew Jeffery } 4672c07f6f0SAndrew Jeffery 4682c07f6f0SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 4690a3358e7SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 4700a3358e7SAndrew Jeffery HIOMAPD_IFACE, "GetInfo"); 4712c07f6f0SAndrew Jeffery m.append(reqdata[0]); 4722c07f6f0SAndrew Jeffery 4732c07f6f0SAndrew Jeffery try 4742c07f6f0SAndrew Jeffery { 4750a3358e7SAndrew Jeffery auto reply = ctx->bus->call(m); 4762c07f6f0SAndrew Jeffery 4772c07f6f0SAndrew Jeffery uint8_t version; 4782c07f6f0SAndrew Jeffery uint8_t blockSizeShift; 4792c07f6f0SAndrew Jeffery uint16_t timeout; 4802c07f6f0SAndrew Jeffery reply.read(version, blockSizeShift, timeout); 4812c07f6f0SAndrew Jeffery 4822c07f6f0SAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 4832c07f6f0SAndrew Jeffery 4842c07f6f0SAndrew Jeffery /* FIXME: Assumes v2! */ 4852c07f6f0SAndrew Jeffery put(&respdata[0], version); 4862c07f6f0SAndrew Jeffery put(&respdata[1], blockSizeShift); 4872c07f6f0SAndrew Jeffery put(&respdata[2], htole16(timeout)); 4882c07f6f0SAndrew Jeffery 4892c07f6f0SAndrew Jeffery *data_len = 4; 4902c07f6f0SAndrew Jeffery } 49195510386SPatrick Williams catch (const exception::exception& e) 4922c07f6f0SAndrew Jeffery { 4932c07f6f0SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 4942c07f6f0SAndrew Jeffery } 4952c07f6f0SAndrew Jeffery 4962c07f6f0SAndrew Jeffery return IPMI_CC_OK; 4972c07f6f0SAndrew Jeffery } 4982c07f6f0SAndrew Jeffery 499*89707266SWilly Tu static ipmi_ret_t hiomap_get_flash_info([[maybe_unused]] ipmi_request_t request, 500db688e9fSAndrew Jeffery ipmi_response_t response, 501db688e9fSAndrew Jeffery ipmi_data_len_t data_len, 502db688e9fSAndrew Jeffery ipmi_context_t context) 503db688e9fSAndrew Jeffery { 504db688e9fSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 505db688e9fSAndrew Jeffery 506db688e9fSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 507db688e9fSAndrew Jeffery HIOMAPD_IFACE_V2, "GetFlashInfo"); 508db688e9fSAndrew Jeffery try 509db688e9fSAndrew Jeffery { 510db688e9fSAndrew Jeffery auto reply = ctx->bus->call(m); 511db688e9fSAndrew Jeffery 512db688e9fSAndrew Jeffery uint16_t flashSize, eraseSize; 513db688e9fSAndrew Jeffery reply.read(flashSize, eraseSize); 514db688e9fSAndrew Jeffery 515db688e9fSAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 516db688e9fSAndrew Jeffery put(&respdata[0], htole16(flashSize)); 517db688e9fSAndrew Jeffery put(&respdata[2], htole16(eraseSize)); 518db688e9fSAndrew Jeffery 519db688e9fSAndrew Jeffery *data_len = 4; 520db688e9fSAndrew Jeffery } 52195510386SPatrick Williams catch (const exception::exception& e) 522db688e9fSAndrew Jeffery { 523db688e9fSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 524db688e9fSAndrew Jeffery } 525db688e9fSAndrew Jeffery 526db688e9fSAndrew Jeffery return IPMI_CC_OK; 527db688e9fSAndrew Jeffery } 528db688e9fSAndrew Jeffery 529a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_window(struct hiomap* ctx, bool ro, 530a00f59baSAndrew Jeffery ipmi_request_t request, 531a00f59baSAndrew Jeffery ipmi_response_t response, 532a00f59baSAndrew Jeffery ipmi_data_len_t data_len) 533a00f59baSAndrew Jeffery { 534a00f59baSAndrew Jeffery if (*data_len < 4) 535a00f59baSAndrew Jeffery { 536a00f59baSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 537a00f59baSAndrew Jeffery } 538a00f59baSAndrew Jeffery 539a00f59baSAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 540a00f59baSAndrew Jeffery auto windowType = ro ? "CreateReadWindow" : "CreateWriteWindow"; 541a00f59baSAndrew Jeffery 542a00f59baSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 543a00f59baSAndrew Jeffery HIOMAPD_IFACE_V2, windowType); 544a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); 545a00f59baSAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); 546a00f59baSAndrew Jeffery 547a00f59baSAndrew Jeffery try 548a00f59baSAndrew Jeffery { 549a00f59baSAndrew Jeffery auto reply = ctx->bus->call(m); 550a00f59baSAndrew Jeffery 551a00f59baSAndrew Jeffery uint16_t lpcAddress, size, offset; 552a00f59baSAndrew Jeffery reply.read(lpcAddress, size, offset); 553a00f59baSAndrew Jeffery 554a00f59baSAndrew Jeffery uint8_t* respdata = (uint8_t*)response; 555a00f59baSAndrew Jeffery 556a00f59baSAndrew Jeffery /* FIXME: Assumes v2! */ 557a00f59baSAndrew Jeffery put(&respdata[0], htole16(lpcAddress)); 558a00f59baSAndrew Jeffery put(&respdata[2], htole16(size)); 559a00f59baSAndrew Jeffery put(&respdata[4], htole16(offset)); 560a00f59baSAndrew Jeffery 561a00f59baSAndrew Jeffery *data_len = 6; 562a00f59baSAndrew Jeffery } 56395510386SPatrick Williams catch (const exception::exception& e) 564a00f59baSAndrew Jeffery { 565a00f59baSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 566a00f59baSAndrew Jeffery } 567a00f59baSAndrew Jeffery 568a00f59baSAndrew Jeffery return IPMI_CC_OK; 569a00f59baSAndrew Jeffery } 570a00f59baSAndrew Jeffery 571a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_read_window(ipmi_request_t request, 572a00f59baSAndrew Jeffery ipmi_response_t response, 573a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 574a00f59baSAndrew Jeffery ipmi_context_t context) 575a00f59baSAndrew Jeffery { 576a00f59baSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 577a00f59baSAndrew Jeffery 578a00f59baSAndrew Jeffery return hiomap_create_window(ctx, true, request, response, data_len); 579a00f59baSAndrew Jeffery } 580a00f59baSAndrew Jeffery 581a00f59baSAndrew Jeffery static ipmi_ret_t hiomap_create_write_window(ipmi_request_t request, 582a00f59baSAndrew Jeffery ipmi_response_t response, 583a00f59baSAndrew Jeffery ipmi_data_len_t data_len, 584a00f59baSAndrew Jeffery ipmi_context_t context) 585a00f59baSAndrew Jeffery { 586a00f59baSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 587a00f59baSAndrew Jeffery 588a00f59baSAndrew Jeffery return hiomap_create_window(ctx, false, request, response, data_len); 589a00f59baSAndrew Jeffery } 590a00f59baSAndrew Jeffery 591b52822cdSAndrew Jeffery static ipmi_ret_t hiomap_close_window(ipmi_request_t request, 592*89707266SWilly Tu [[maybe_unused]] ipmi_response_t response, 593b52822cdSAndrew Jeffery ipmi_data_len_t data_len, 594b52822cdSAndrew Jeffery ipmi_context_t context) 595b52822cdSAndrew Jeffery { 596b52822cdSAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 597b52822cdSAndrew Jeffery 598b52822cdSAndrew Jeffery if (*data_len < 1) 599b52822cdSAndrew Jeffery { 600b52822cdSAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 601b52822cdSAndrew Jeffery } 602b52822cdSAndrew Jeffery 603b52822cdSAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 604b52822cdSAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 605b52822cdSAndrew Jeffery HIOMAPD_IFACE_V2, "CloseWindow"); 606b52822cdSAndrew Jeffery m.append(reqdata[0]); 607b52822cdSAndrew Jeffery 608b52822cdSAndrew Jeffery try 609b52822cdSAndrew Jeffery { 610b52822cdSAndrew Jeffery auto reply = ctx->bus->call(m); 611b52822cdSAndrew Jeffery 612b52822cdSAndrew Jeffery *data_len = 0; 613b52822cdSAndrew Jeffery } 61495510386SPatrick Williams catch (const exception::exception& e) 615b52822cdSAndrew Jeffery { 616b52822cdSAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 617b52822cdSAndrew Jeffery } 618b52822cdSAndrew Jeffery 619b52822cdSAndrew Jeffery return IPMI_CC_OK; 620b52822cdSAndrew Jeffery } 621b52822cdSAndrew Jeffery 6229847f1c2SAndrew Jeffery static ipmi_ret_t hiomap_mark_dirty(ipmi_request_t request, 623*89707266SWilly Tu [[maybe_unused]] ipmi_response_t response, 6249847f1c2SAndrew Jeffery ipmi_data_len_t data_len, 6259847f1c2SAndrew Jeffery ipmi_context_t context) 6269847f1c2SAndrew Jeffery { 6279847f1c2SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 6289847f1c2SAndrew Jeffery 6299847f1c2SAndrew Jeffery if (*data_len < 4) 6309847f1c2SAndrew Jeffery { 6319847f1c2SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 6329847f1c2SAndrew Jeffery } 6339847f1c2SAndrew Jeffery 6349847f1c2SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 6359847f1c2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 6369847f1c2SAndrew Jeffery HIOMAPD_IFACE_V2, "MarkDirty"); 6379847f1c2SAndrew Jeffery /* FIXME: Assumes v2 */ 6389847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 6399847f1c2SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 6409847f1c2SAndrew Jeffery 6419847f1c2SAndrew Jeffery try 6429847f1c2SAndrew Jeffery { 6439847f1c2SAndrew Jeffery auto reply = ctx->bus->call(m); 6449847f1c2SAndrew Jeffery 6459847f1c2SAndrew Jeffery *data_len = 0; 6469847f1c2SAndrew Jeffery } 64795510386SPatrick Williams catch (const exception::exception& e) 6489847f1c2SAndrew Jeffery { 6499847f1c2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 6509847f1c2SAndrew Jeffery } 6519847f1c2SAndrew Jeffery 6529847f1c2SAndrew Jeffery return IPMI_CC_OK; 6539847f1c2SAndrew Jeffery } 6549847f1c2SAndrew Jeffery 655*89707266SWilly Tu static ipmi_ret_t hiomap_flush([[maybe_unused]] ipmi_request_t request, 656*89707266SWilly Tu [[maybe_unused]] ipmi_response_t response, 6577b225fb2SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 6587b225fb2SAndrew Jeffery { 6597b225fb2SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 6607b225fb2SAndrew Jeffery 6617b225fb2SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 6627b225fb2SAndrew Jeffery HIOMAPD_IFACE_V2, "Flush"); 6637b225fb2SAndrew Jeffery 6647b225fb2SAndrew Jeffery try 6657b225fb2SAndrew Jeffery { 6667b225fb2SAndrew Jeffery /* FIXME: No argument call assumes v2 */ 6677b225fb2SAndrew Jeffery auto reply = ctx->bus->call(m); 6687b225fb2SAndrew Jeffery 6697b225fb2SAndrew Jeffery *data_len = 0; 6707b225fb2SAndrew Jeffery } 67195510386SPatrick Williams catch (const exception::exception& e) 6727b225fb2SAndrew Jeffery { 6737b225fb2SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 6747b225fb2SAndrew Jeffery } 6757b225fb2SAndrew Jeffery 6767b225fb2SAndrew Jeffery return IPMI_CC_OK; 6777b225fb2SAndrew Jeffery } 6787b225fb2SAndrew Jeffery 679*89707266SWilly Tu static ipmi_ret_t hiomap_ack(ipmi_request_t request, 680*89707266SWilly Tu [[maybe_unused]] ipmi_response_t response, 68199f277a1SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 68299f277a1SAndrew Jeffery { 68399f277a1SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 68499f277a1SAndrew Jeffery 68599f277a1SAndrew Jeffery if (*data_len < 1) 68699f277a1SAndrew Jeffery { 68799f277a1SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 68899f277a1SAndrew Jeffery } 68999f277a1SAndrew Jeffery 69099f277a1SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 69199f277a1SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 69299f277a1SAndrew Jeffery HIOMAPD_IFACE_V2, "Ack"); 69399f277a1SAndrew Jeffery auto acked = reqdata[0]; 69499f277a1SAndrew Jeffery m.append(acked); 69599f277a1SAndrew Jeffery 69699f277a1SAndrew Jeffery try 69799f277a1SAndrew Jeffery { 69899f277a1SAndrew Jeffery auto reply = ctx->bus->call(m); 69999f277a1SAndrew Jeffery 70099f277a1SAndrew Jeffery *data_len = 0; 70199f277a1SAndrew Jeffery } 70295510386SPatrick Williams catch (const exception::exception& e) 70399f277a1SAndrew Jeffery { 70499f277a1SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 70599f277a1SAndrew Jeffery } 70699f277a1SAndrew Jeffery 70799f277a1SAndrew Jeffery return IPMI_CC_OK; 70899f277a1SAndrew Jeffery } 70999f277a1SAndrew Jeffery 710*89707266SWilly Tu static ipmi_ret_t hiomap_erase(ipmi_request_t request, 711*89707266SWilly Tu [[maybe_unused]] ipmi_response_t response, 712a1e35b85SAndrew Jeffery ipmi_data_len_t data_len, ipmi_context_t context) 713a1e35b85SAndrew Jeffery { 714a1e35b85SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 715a1e35b85SAndrew Jeffery 716a1e35b85SAndrew Jeffery if (*data_len < 4) 717a1e35b85SAndrew Jeffery { 718a1e35b85SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 719a1e35b85SAndrew Jeffery } 720a1e35b85SAndrew Jeffery 721a1e35b85SAndrew Jeffery uint8_t* reqdata = (uint8_t*)request; 722a1e35b85SAndrew Jeffery auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, 723a1e35b85SAndrew Jeffery HIOMAPD_IFACE_V2, "Erase"); 724a1e35b85SAndrew Jeffery /* FIXME: Assumes v2 */ 725a1e35b85SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ 726a1e35b85SAndrew Jeffery m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ 727a1e35b85SAndrew Jeffery 728a1e35b85SAndrew Jeffery try 729a1e35b85SAndrew Jeffery { 730a1e35b85SAndrew Jeffery auto reply = ctx->bus->call(m); 731a1e35b85SAndrew Jeffery 732a1e35b85SAndrew Jeffery *data_len = 0; 733a1e35b85SAndrew Jeffery } 73495510386SPatrick Williams catch (const exception::exception& e) 735a1e35b85SAndrew Jeffery { 736a1e35b85SAndrew Jeffery return hiomap_xlate_errno(e.get_errno()); 737a1e35b85SAndrew Jeffery } 738a1e35b85SAndrew Jeffery 739a1e35b85SAndrew Jeffery return IPMI_CC_OK; 740a1e35b85SAndrew Jeffery } 741a1e35b85SAndrew Jeffery 74204d75136SAndrew Jeffery #define HIOMAP_C_RESET 1 74304d75136SAndrew Jeffery #define HIOMAP_C_GET_INFO 2 74404d75136SAndrew Jeffery #define HIOMAP_C_GET_FLASH_INFO 3 74504d75136SAndrew Jeffery #define HIOMAP_C_CREATE_READ_WINDOW 4 74604d75136SAndrew Jeffery #define HIOMAP_C_CLOSE_WINDOW 5 74704d75136SAndrew Jeffery #define HIOMAP_C_CREATE_WRITE_WINDOW 6 74804d75136SAndrew Jeffery #define HIOMAP_C_MARK_DIRTY 7 74904d75136SAndrew Jeffery #define HIOMAP_C_FLUSH 8 75004d75136SAndrew Jeffery #define HIOMAP_C_ACK 9 75104d75136SAndrew Jeffery #define HIOMAP_C_ERASE 10 75204d75136SAndrew Jeffery 753*89707266SWilly Tu static const std::unordered_map<uint8_t, hiomap_command> hiomap_commands = { 754*89707266SWilly Tu {0, nullptr}, /* Invalid command ID */ 755*89707266SWilly Tu {HIOMAP_C_RESET, hiomap_reset}, 756*89707266SWilly Tu {HIOMAP_C_GET_INFO, hiomap_get_info}, 757*89707266SWilly Tu {HIOMAP_C_GET_FLASH_INFO, hiomap_get_flash_info}, 758*89707266SWilly Tu {HIOMAP_C_CREATE_READ_WINDOW, hiomap_create_read_window}, 759*89707266SWilly Tu {HIOMAP_C_CLOSE_WINDOW, hiomap_close_window}, 760*89707266SWilly Tu {HIOMAP_C_CREATE_WRITE_WINDOW, hiomap_create_write_window}, 761*89707266SWilly Tu {HIOMAP_C_MARK_DIRTY, hiomap_mark_dirty}, 762*89707266SWilly Tu {HIOMAP_C_FLUSH, hiomap_flush}, 763*89707266SWilly Tu {HIOMAP_C_ACK, hiomap_ack}, 764*89707266SWilly Tu {HIOMAP_C_ERASE, hiomap_erase}, 7652c07f6f0SAndrew Jeffery }; 7662c07f6f0SAndrew Jeffery 7672c07f6f0SAndrew Jeffery /* FIXME: Define this in the "right" place, wherever that is */ 7682c07f6f0SAndrew Jeffery /* FIXME: Double evaluation */ 7692c07f6f0SAndrew Jeffery #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 7702c07f6f0SAndrew Jeffery 771*89707266SWilly Tu static ipmi_ret_t hiomap_dispatch([[maybe_unused]] ipmi_netfn_t netfn, 772*89707266SWilly Tu [[maybe_unused]] ipmi_cmd_t cmd, 7732c07f6f0SAndrew Jeffery ipmi_request_t request, 7742c07f6f0SAndrew Jeffery ipmi_response_t response, 7752c07f6f0SAndrew Jeffery ipmi_data_len_t data_len, 7762c07f6f0SAndrew Jeffery ipmi_context_t context) 7772c07f6f0SAndrew Jeffery { 7780a3358e7SAndrew Jeffery struct hiomap* ctx = static_cast<struct hiomap*>(context); 7790a3358e7SAndrew Jeffery 7802c07f6f0SAndrew Jeffery if (*data_len < 2) 7812c07f6f0SAndrew Jeffery { 7822c07f6f0SAndrew Jeffery *data_len = 0; 7832c07f6f0SAndrew Jeffery return IPMI_CC_REQ_DATA_LEN_INVALID; 7842c07f6f0SAndrew Jeffery } 7852c07f6f0SAndrew Jeffery 7862c07f6f0SAndrew Jeffery uint8_t* ipmi_req = (uint8_t*)request; 7872c07f6f0SAndrew Jeffery uint8_t* ipmi_resp = (uint8_t*)response; 7882c07f6f0SAndrew Jeffery uint8_t hiomap_cmd = ipmi_req[0]; 7892c07f6f0SAndrew Jeffery 790*89707266SWilly Tu if (hiomap_cmd == 0 || hiomap_cmd > hiomap_commands.size() - 1) 7912c07f6f0SAndrew Jeffery { 7922c07f6f0SAndrew Jeffery *data_len = 0; 7932c07f6f0SAndrew Jeffery return IPMI_CC_PARM_OUT_OF_RANGE; 7942c07f6f0SAndrew Jeffery } 79504d75136SAndrew Jeffery 79604d75136SAndrew Jeffery bool is_unversioned = 79704d75136SAndrew Jeffery (hiomap_cmd == HIOMAP_C_RESET || hiomap_cmd == HIOMAP_C_GET_INFO || 79804d75136SAndrew Jeffery hiomap_cmd == HIOMAP_C_ACK); 79904d75136SAndrew Jeffery if (!is_unversioned && ctx->seq == ipmi_req[1]) 80004d75136SAndrew Jeffery { 80104d75136SAndrew Jeffery *data_len = 0; 80204d75136SAndrew Jeffery return IPMI_CC_INVALID_FIELD_REQUEST; 80304d75136SAndrew Jeffery } 80404d75136SAndrew Jeffery 80504d75136SAndrew Jeffery ctx->seq = ipmi_req[1]; 80604d75136SAndrew Jeffery 8072c07f6f0SAndrew Jeffery uint8_t* flash_req = ipmi_req + 2; 8082c07f6f0SAndrew Jeffery size_t flash_len = *data_len - 2; 8092c07f6f0SAndrew Jeffery uint8_t* flash_resp = ipmi_resp + 2; 8102c07f6f0SAndrew Jeffery 811*89707266SWilly Tu auto command = hiomap_commands.find(hiomap_cmd); 812*89707266SWilly Tu if (command == hiomap_commands.end()) 813*89707266SWilly Tu { 814*89707266SWilly Tu *data_len = 0; 815*89707266SWilly Tu return IPMI_CC_INVALID; 816*89707266SWilly Tu } 817*89707266SWilly Tu ipmi_ret_t cc = command->second(flash_req, flash_resp, &flash_len, context); 8182c07f6f0SAndrew Jeffery if (cc != IPMI_CC_OK) 8192c07f6f0SAndrew Jeffery { 8202c07f6f0SAndrew Jeffery *data_len = 0; 8212c07f6f0SAndrew Jeffery return cc; 8222c07f6f0SAndrew Jeffery } 8232c07f6f0SAndrew Jeffery 8242c07f6f0SAndrew Jeffery /* Populate the response command and sequence */ 8250a3358e7SAndrew Jeffery ipmi_resp[0] = hiomap_cmd; 82604d75136SAndrew Jeffery ipmi_resp[1] = ctx->seq; 8272c07f6f0SAndrew Jeffery 8282c07f6f0SAndrew Jeffery *data_len = flash_len + 2; 8292c07f6f0SAndrew Jeffery 8302c07f6f0SAndrew Jeffery return cc; 8312c07f6f0SAndrew Jeffery } 8322c07f6f0SAndrew Jeffery } // namespace flash 8332c07f6f0SAndrew Jeffery } // namespace openpower 8342c07f6f0SAndrew Jeffery 8352c07f6f0SAndrew Jeffery static void register_openpower_hiomap_commands() 8362c07f6f0SAndrew Jeffery { 837619207dcSAndrew Jeffery using namespace phosphor::logging; 8380a3358e7SAndrew Jeffery using namespace openpower::flash; 8390a3358e7SAndrew Jeffery 8400a3358e7SAndrew Jeffery struct hiomap* ctx = new hiomap(); 8410a3358e7SAndrew Jeffery 8420a3358e7SAndrew Jeffery /* Initialise mapping from signal and property names to status bit */ 8430a3358e7SAndrew Jeffery ctx->event_lookup["DaemonReady"] = BMC_EVENT_DAEMON_READY; 8440a3358e7SAndrew Jeffery ctx->event_lookup["FlashControlLost"] = BMC_EVENT_FLASH_CTRL_LOST; 8450a3358e7SAndrew Jeffery ctx->event_lookup["WindowReset"] = BMC_EVENT_WINDOW_RESET; 8460a3358e7SAndrew Jeffery ctx->event_lookup["ProtocolReset"] = BMC_EVENT_PROTOCOL_RESET; 8470a3358e7SAndrew Jeffery 8480a3358e7SAndrew Jeffery ctx->bus = new bus::bus(ipmid_get_sd_bus_connection()); 8490a3358e7SAndrew Jeffery 8500a3358e7SAndrew Jeffery /* Initialise signal handling */ 8510a3358e7SAndrew Jeffery 8520a3358e7SAndrew Jeffery /* 8530a3358e7SAndrew Jeffery * Can't use temporaries here because that causes SEGFAULTs due to slot 8540a3358e7SAndrew Jeffery * destruction (!?), so enjoy the weird wrapping. 8550a3358e7SAndrew Jeffery */ 8560a3358e7SAndrew Jeffery ctx->properties = 8570a3358e7SAndrew Jeffery new bus::match::match(std::move(hiomap_match_properties(ctx))); 858619207dcSAndrew Jeffery 859ee3064baSVernon Mauery std::function<SignalResponse(int)> shutdownHandler = 860*89707266SWilly Tu [ctx]([[maybe_unused]] int signalNumber) { 861ee3064baSVernon Mauery hiomap_protocol_reset(ctx); 862ee3064baSVernon Mauery return sigtermResponse; 863ee3064baSVernon Mauery }; 864ee3064baSVernon Mauery registerSignalHandler(ipmi::prioMax, SIGTERM, shutdownHandler); 8650a3358e7SAndrew Jeffery 8660a3358e7SAndrew Jeffery ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, ctx, 8672c07f6f0SAndrew Jeffery openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE); 8682c07f6f0SAndrew Jeffery } 869