| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 | 
|  | 2 | // Copyright (C) 2018 IBM Corp. | 
|  | 3 |  | 
|  | 4 | #include "config.h" | 
|  | 5 |  | 
|  | 6 | #include "hiomap.hpp" | 
|  | 7 |  | 
|  | 8 | #include <endian.h> | 
|  | 9 | #include <host-ipmid/ipmid-api.h> | 
|  | 10 | #include <string.h> | 
|  | 11 | #include <systemd/sd-bus.h> | 
|  | 12 |  | 
|  | 13 | #include <fstream> | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 14 | #include <functional> | 
|  | 15 | #include <host-ipmid/ipmid-host-cmd-utils.hpp> | 
|  | 16 | #include <host-ipmid/ipmid-host-cmd.hpp> | 
|  | 17 | #include <iostream> | 
|  | 18 | #include <phosphor-logging/log.hpp> | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 19 | #include <sdbusplus/bus.hpp> | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 20 | #include <sdbusplus/bus/match.hpp> | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 21 | #include <sdbusplus/exception.hpp> | 
|  | 22 |  | 
|  | 23 | using namespace sdbusplus; | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 24 | using namespace phosphor::host::command; | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 25 |  | 
|  | 26 | static void register_openpower_hiomap_commands() __attribute__((constructor)); | 
|  | 27 |  | 
|  | 28 | namespace openpower | 
|  | 29 | { | 
|  | 30 | namespace flash | 
|  | 31 | { | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 32 | constexpr auto BMC_EVENT_DAEMON_READY = 1 << 7; | 
|  | 33 | constexpr auto BMC_EVENT_FLASH_CTRL_LOST = 1 << 6; | 
|  | 34 | constexpr auto BMC_EVENT_WINDOW_RESET = 1 << 1; | 
|  | 35 | constexpr auto BMC_EVENT_PROTOCOL_RESET = 1 << 0; | 
|  | 36 |  | 
|  | 37 | constexpr auto IPMI_CMD_HIOMAP_EVENT = 0x0f; | 
|  | 38 |  | 
|  | 39 | constexpr auto HIOMAPD_SERVICE = "xyz.openbmc_project.Hiomapd"; | 
|  | 40 | constexpr auto HIOMAPD_OBJECT = "/xyz/openbmc_project/Hiomapd"; | 
|  | 41 | constexpr auto HIOMAPD_IFACE = "xyz.openbmc_project.Hiomapd.Protocol"; | 
|  | 42 | constexpr auto HIOMAPD_IFACE_V2 = "xyz.openbmc_project.Hiomapd.Protocol.V2"; | 
|  | 43 |  | 
|  | 44 | constexpr auto DBUS_IFACE_PROPERTIES = "org.freedesktop.DBus.Properties"; | 
|  | 45 |  | 
|  | 46 | struct hiomap | 
|  | 47 | { | 
|  | 48 | bus::bus *bus; | 
|  | 49 |  | 
|  | 50 | /* Signals */ | 
|  | 51 | bus::match::match *properties; | 
|  | 52 | bus::match::match *window_reset; | 
|  | 53 | bus::match::match *bmc_reboot; | 
|  | 54 |  | 
|  | 55 | /* Protocol state */ | 
|  | 56 | std::map<std::string, int> event_lookup; | 
|  | 57 | uint8_t bmc_events; | 
| Andrew Jeffery | 04d7513 | 2018-09-26 00:58:52 +0930 | [diff] [blame^] | 58 | uint8_t seq; | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 59 | }; | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 60 |  | 
|  | 61 | /* TODO: Replace get/put with packed structs and direct assignment */ | 
|  | 62 | template <typename T> static inline T get(void *buf) | 
|  | 63 | { | 
|  | 64 | T t; | 
|  | 65 | memcpy(&t, buf, sizeof(t)); | 
|  | 66 | return t; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | template <typename T> static inline void put(void *buf, T &&t) | 
|  | 70 | { | 
|  | 71 | memcpy(buf, &t, sizeof(t)); | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | typedef ipmi_ret_t (*hiomap_command)(ipmi_request_t req, ipmi_response_t resp, | 
|  | 75 | ipmi_data_len_t data_len, | 
|  | 76 | ipmi_context_t context); | 
|  | 77 |  | 
|  | 78 | struct errno_cc_entry | 
|  | 79 | { | 
|  | 80 | int err; | 
|  | 81 | int cc; | 
|  | 82 | }; | 
|  | 83 |  | 
|  | 84 | static const errno_cc_entry errno_cc_map[] = { | 
|  | 85 | {0, IPMI_CC_OK}, | 
|  | 86 | {EBUSY, IPMI_CC_BUSY}, | 
|  | 87 | {ENOTSUP, IPMI_CC_INVALID}, | 
|  | 88 | {ETIMEDOUT, 0xc3}, /* FIXME: Replace when defined in ipmid-api.h */ | 
|  | 89 | {ENOSPC, 0xc4},    /* FIXME: Replace when defined in ipmid-api.h */ | 
|  | 90 | {EINVAL, IPMI_CC_PARM_OUT_OF_RANGE}, | 
|  | 91 | {ENODEV, IPMI_CC_SENSOR_INVALID}, | 
|  | 92 | {EPERM, IPMI_CC_INSUFFICIENT_PRIVILEGE}, | 
|  | 93 | {EACCES, IPMI_CC_INSUFFICIENT_PRIVILEGE}, | 
|  | 94 | {-1, IPMI_CC_UNSPECIFIED_ERROR}, | 
|  | 95 | }; | 
|  | 96 |  | 
|  | 97 | static int hiomap_xlate_errno(int err) | 
|  | 98 | { | 
|  | 99 | const errno_cc_entry *entry = &errno_cc_map[0]; | 
|  | 100 |  | 
|  | 101 | while (!(entry->err == err || entry->err == -1)) | 
|  | 102 | { | 
|  | 103 | entry++; | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | return entry->cc; | 
|  | 107 | } | 
|  | 108 |  | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 109 | static void ipmi_hiomap_event_response(IpmiCmdData cmd, bool status) | 
|  | 110 | { | 
|  | 111 | using namespace phosphor::logging; | 
|  | 112 |  | 
|  | 113 | if (!status) | 
|  | 114 | { | 
|  | 115 | log<level::ERR>("Failed to deliver host command", | 
|  | 116 | entry("SEL_COMMAND=%x:%x", cmd.first, cmd.second)); | 
|  | 117 | } | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | static int hiomap_handle_property_update(struct hiomap *ctx, | 
|  | 121 | sdbusplus::message::message &msg) | 
|  | 122 | { | 
|  | 123 | std::map<std::string, sdbusplus::message::variant<bool>> msgData; | 
|  | 124 |  | 
|  | 125 | std::string iface; | 
|  | 126 | msg.read(iface, msgData); | 
|  | 127 |  | 
|  | 128 | for (auto const &x : msgData) | 
|  | 129 | { | 
|  | 130 | if (!ctx->event_lookup.count(x.first)) | 
|  | 131 | { | 
|  | 132 | /* Unsupported event? */ | 
|  | 133 | continue; | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | uint8_t mask = ctx->event_lookup[x.first]; | 
|  | 137 | auto value = sdbusplus::message::variant_ns::get<bool>(x.second); | 
|  | 138 |  | 
|  | 139 | if (value) | 
|  | 140 | { | 
|  | 141 | ctx->bmc_events |= mask; | 
|  | 142 | } | 
|  | 143 | else | 
|  | 144 | { | 
|  | 145 | ctx->bmc_events &= ~mask; | 
|  | 146 | } | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); | 
|  | 150 |  | 
|  | 151 | ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); | 
|  | 152 |  | 
|  | 153 | return 0; | 
|  | 154 | } | 
|  | 155 |  | 
|  | 156 | static bus::match::match hiomap_match_properties(struct hiomap *ctx) | 
|  | 157 | { | 
|  | 158 | auto properties = | 
|  | 159 | bus::match::rules::propertiesChanged(HIOMAPD_OBJECT, HIOMAPD_IFACE_V2); | 
|  | 160 |  | 
|  | 161 | bus::match::match match( | 
|  | 162 | *ctx->bus, properties, | 
|  | 163 | std::bind(hiomap_handle_property_update, ctx, std::placeholders::_1)); | 
|  | 164 |  | 
|  | 165 | return match; | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | static int hiomap_handle_signal_v2(struct hiomap *ctx, const char *name) | 
|  | 169 | { | 
|  | 170 | ctx->bmc_events |= ctx->event_lookup[name]; | 
|  | 171 |  | 
|  | 172 | auto cmd = std::make_pair(IPMI_CMD_HIOMAP_EVENT, ctx->bmc_events); | 
|  | 173 |  | 
|  | 174 | ipmid_send_cmd_to_host(std::make_tuple(cmd, ipmi_hiomap_event_response)); | 
|  | 175 |  | 
|  | 176 | return 0; | 
|  | 177 | } | 
|  | 178 |  | 
|  | 179 | static bus::match::match hiomap_match_signal_v2(struct hiomap *ctx, | 
|  | 180 | const char *name) | 
|  | 181 | { | 
|  | 182 | using namespace bus::match; | 
|  | 183 |  | 
|  | 184 | auto signals = rules::type::signal() + rules::path(HIOMAPD_OBJECT) + | 
|  | 185 | rules::interface(HIOMAPD_IFACE_V2) + rules::member(name); | 
|  | 186 |  | 
|  | 187 | bus::match::match match(*ctx->bus, signals, | 
|  | 188 | std::bind(hiomap_handle_signal_v2, ctx, name)); | 
|  | 189 |  | 
|  | 190 | return match; | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | static ipmi_ret_t hiomap_reset(ipmi_request_t request, ipmi_response_t response, | 
|  | 194 | ipmi_data_len_t data_len, ipmi_context_t context) | 
|  | 195 | { | 
|  | 196 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 197 |  | 
|  | 198 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 199 | HIOMAPD_IFACE, "Reset"); | 
|  | 200 | try | 
|  | 201 | { | 
|  | 202 | ctx->bus->call(m); | 
|  | 203 |  | 
|  | 204 | *data_len = 0; | 
|  | 205 | } | 
|  | 206 | catch (const exception::SdBusError &e) | 
|  | 207 | { | 
|  | 208 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | return IPMI_CC_OK; | 
|  | 212 | } | 
|  | 213 |  | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 214 | static ipmi_ret_t hiomap_get_info(ipmi_request_t request, | 
|  | 215 | ipmi_response_t response, | 
|  | 216 | ipmi_data_len_t data_len, | 
|  | 217 | ipmi_context_t context) | 
|  | 218 | { | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 219 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 220 |  | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 221 | if (*data_len < 1) | 
|  | 222 | { | 
|  | 223 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 224 | } | 
|  | 225 |  | 
|  | 226 | uint8_t *reqdata = (uint8_t *)request; | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 227 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 228 | HIOMAPD_IFACE, "GetInfo"); | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 229 | m.append(reqdata[0]); | 
|  | 230 |  | 
|  | 231 | try | 
|  | 232 | { | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 233 | auto reply = ctx->bus->call(m); | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 234 |  | 
|  | 235 | uint8_t version; | 
|  | 236 | uint8_t blockSizeShift; | 
|  | 237 | uint16_t timeout; | 
|  | 238 | reply.read(version, blockSizeShift, timeout); | 
|  | 239 |  | 
|  | 240 | uint8_t *respdata = (uint8_t *)response; | 
|  | 241 |  | 
|  | 242 | /* FIXME: Assumes v2! */ | 
|  | 243 | put(&respdata[0], version); | 
|  | 244 | put(&respdata[1], blockSizeShift); | 
|  | 245 | put(&respdata[2], htole16(timeout)); | 
|  | 246 |  | 
|  | 247 | *data_len = 4; | 
|  | 248 | } | 
|  | 249 | catch (const exception::SdBusError &e) | 
|  | 250 | { | 
|  | 251 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 252 | } | 
|  | 253 |  | 
|  | 254 | return IPMI_CC_OK; | 
|  | 255 | } | 
|  | 256 |  | 
| Andrew Jeffery | db688e9 | 2018-08-23 21:21:30 +0930 | [diff] [blame] | 257 | static ipmi_ret_t hiomap_get_flash_info(ipmi_request_t request, | 
|  | 258 | ipmi_response_t response, | 
|  | 259 | ipmi_data_len_t data_len, | 
|  | 260 | ipmi_context_t context) | 
|  | 261 | { | 
|  | 262 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 263 |  | 
|  | 264 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 265 | HIOMAPD_IFACE_V2, "GetFlashInfo"); | 
|  | 266 | try | 
|  | 267 | { | 
|  | 268 | auto reply = ctx->bus->call(m); | 
|  | 269 |  | 
|  | 270 | uint16_t flashSize, eraseSize; | 
|  | 271 | reply.read(flashSize, eraseSize); | 
|  | 272 |  | 
|  | 273 | uint8_t *respdata = (uint8_t *)response; | 
|  | 274 | put(&respdata[0], htole16(flashSize)); | 
|  | 275 | put(&respdata[2], htole16(eraseSize)); | 
|  | 276 |  | 
|  | 277 | *data_len = 4; | 
|  | 278 | } | 
|  | 279 | catch (const exception::SdBusError &e) | 
|  | 280 | { | 
|  | 281 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | return IPMI_CC_OK; | 
|  | 285 | } | 
|  | 286 |  | 
| Andrew Jeffery | a00f59b | 2018-08-23 22:25:49 +0930 | [diff] [blame] | 287 | static ipmi_ret_t hiomap_create_window(struct hiomap *ctx, bool ro, | 
|  | 288 | ipmi_request_t request, | 
|  | 289 | ipmi_response_t response, | 
|  | 290 | ipmi_data_len_t data_len) | 
|  | 291 | { | 
|  | 292 | if (*data_len < 4) | 
|  | 293 | { | 
|  | 294 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 295 | } | 
|  | 296 |  | 
|  | 297 | uint8_t *reqdata = (uint8_t *)request; | 
|  | 298 | auto windowType = ro ? "CreateReadWindow" : "CreateWriteWindow"; | 
|  | 299 |  | 
|  | 300 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 301 | HIOMAPD_IFACE_V2, windowType); | 
|  | 302 | m.append(le16toh(get<uint16_t>(&reqdata[0]))); | 
|  | 303 | m.append(le16toh(get<uint16_t>(&reqdata[2]))); | 
|  | 304 |  | 
|  | 305 | try | 
|  | 306 | { | 
|  | 307 | auto reply = ctx->bus->call(m); | 
|  | 308 |  | 
|  | 309 | uint16_t lpcAddress, size, offset; | 
|  | 310 | reply.read(lpcAddress, size, offset); | 
|  | 311 |  | 
|  | 312 | uint8_t *respdata = (uint8_t *)response; | 
|  | 313 |  | 
|  | 314 | /* FIXME: Assumes v2! */ | 
|  | 315 | put(&respdata[0], htole16(lpcAddress)); | 
|  | 316 | put(&respdata[2], htole16(size)); | 
|  | 317 | put(&respdata[4], htole16(offset)); | 
|  | 318 |  | 
|  | 319 | *data_len = 6; | 
|  | 320 | } | 
|  | 321 | catch (const exception::SdBusError &e) | 
|  | 322 | { | 
|  | 323 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | return IPMI_CC_OK; | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | static ipmi_ret_t hiomap_create_read_window(ipmi_request_t request, | 
|  | 330 | ipmi_response_t response, | 
|  | 331 | ipmi_data_len_t data_len, | 
|  | 332 | ipmi_context_t context) | 
|  | 333 | { | 
|  | 334 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 335 |  | 
|  | 336 | return hiomap_create_window(ctx, true, request, response, data_len); | 
|  | 337 | } | 
|  | 338 |  | 
|  | 339 | static ipmi_ret_t hiomap_create_write_window(ipmi_request_t request, | 
|  | 340 | ipmi_response_t response, | 
|  | 341 | ipmi_data_len_t data_len, | 
|  | 342 | ipmi_context_t context) | 
|  | 343 | { | 
|  | 344 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 345 |  | 
|  | 346 | return hiomap_create_window(ctx, false, request, response, data_len); | 
|  | 347 | } | 
|  | 348 |  | 
| Andrew Jeffery | b52822c | 2018-08-23 23:01:39 +0930 | [diff] [blame] | 349 | static ipmi_ret_t hiomap_close_window(ipmi_request_t request, | 
|  | 350 | ipmi_response_t response, | 
|  | 351 | ipmi_data_len_t data_len, | 
|  | 352 | ipmi_context_t context) | 
|  | 353 | { | 
|  | 354 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 355 |  | 
|  | 356 | if (*data_len < 1) | 
|  | 357 | { | 
|  | 358 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 359 | } | 
|  | 360 |  | 
|  | 361 | uint8_t *reqdata = (uint8_t *)request; | 
|  | 362 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 363 | HIOMAPD_IFACE_V2, "CloseWindow"); | 
|  | 364 | m.append(reqdata[0]); | 
|  | 365 |  | 
|  | 366 | try | 
|  | 367 | { | 
|  | 368 | auto reply = ctx->bus->call(m); | 
|  | 369 |  | 
|  | 370 | *data_len = 0; | 
|  | 371 | } | 
|  | 372 | catch (const exception::SdBusError &e) | 
|  | 373 | { | 
|  | 374 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 375 | } | 
|  | 376 |  | 
|  | 377 | return IPMI_CC_OK; | 
|  | 378 | } | 
|  | 379 |  | 
| Andrew Jeffery | 9847f1c | 2018-08-24 09:13:40 +0930 | [diff] [blame] | 380 | static ipmi_ret_t hiomap_mark_dirty(ipmi_request_t request, | 
|  | 381 | ipmi_response_t response, | 
|  | 382 | ipmi_data_len_t data_len, | 
|  | 383 | ipmi_context_t context) | 
|  | 384 | { | 
|  | 385 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 386 |  | 
|  | 387 | if (*data_len < 4) | 
|  | 388 | { | 
|  | 389 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 390 | } | 
|  | 391 |  | 
|  | 392 | uint8_t *reqdata = (uint8_t *)request; | 
|  | 393 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 394 | HIOMAPD_IFACE_V2, "MarkDirty"); | 
|  | 395 | /* FIXME: Assumes v2 */ | 
|  | 396 | m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ | 
|  | 397 | m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ | 
|  | 398 |  | 
|  | 399 | try | 
|  | 400 | { | 
|  | 401 | auto reply = ctx->bus->call(m); | 
|  | 402 |  | 
|  | 403 | *data_len = 0; | 
|  | 404 | } | 
|  | 405 | catch (const exception::SdBusError &e) | 
|  | 406 | { | 
|  | 407 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 408 | } | 
|  | 409 |  | 
|  | 410 | return IPMI_CC_OK; | 
|  | 411 | } | 
|  | 412 |  | 
| Andrew Jeffery | 7b225fb | 2018-08-24 09:19:21 +0930 | [diff] [blame] | 413 | static ipmi_ret_t hiomap_flush(ipmi_request_t request, ipmi_response_t response, | 
|  | 414 | ipmi_data_len_t data_len, ipmi_context_t context) | 
|  | 415 | { | 
|  | 416 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 417 |  | 
|  | 418 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 419 | HIOMAPD_IFACE_V2, "Flush"); | 
|  | 420 |  | 
|  | 421 | try | 
|  | 422 | { | 
|  | 423 | /* FIXME: No argument call assumes v2 */ | 
|  | 424 | auto reply = ctx->bus->call(m); | 
|  | 425 |  | 
|  | 426 | *data_len = 0; | 
|  | 427 | } | 
|  | 428 | catch (const exception::SdBusError &e) | 
|  | 429 | { | 
|  | 430 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | return IPMI_CC_OK; | 
|  | 434 | } | 
|  | 435 |  | 
| Andrew Jeffery | 99f277a | 2018-08-24 09:24:04 +0930 | [diff] [blame] | 436 | static ipmi_ret_t hiomap_ack(ipmi_request_t request, ipmi_response_t response, | 
|  | 437 | ipmi_data_len_t data_len, ipmi_context_t context) | 
|  | 438 | { | 
|  | 439 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 440 |  | 
|  | 441 | if (*data_len < 1) | 
|  | 442 | { | 
|  | 443 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 444 | } | 
|  | 445 |  | 
|  | 446 | uint8_t *reqdata = (uint8_t *)request; | 
|  | 447 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 448 | HIOMAPD_IFACE_V2, "Ack"); | 
|  | 449 | auto acked = reqdata[0]; | 
|  | 450 | m.append(acked); | 
|  | 451 |  | 
|  | 452 | try | 
|  | 453 | { | 
|  | 454 | auto reply = ctx->bus->call(m); | 
|  | 455 |  | 
|  | 456 | /* Update our cache: Necessary because the signals do not carry a value | 
|  | 457 | */ | 
|  | 458 | ctx->bmc_events &= ~acked; | 
|  | 459 |  | 
|  | 460 | *data_len = 0; | 
|  | 461 | } | 
|  | 462 | catch (const exception::SdBusError &e) | 
|  | 463 | { | 
|  | 464 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | return IPMI_CC_OK; | 
|  | 468 | } | 
|  | 469 |  | 
| Andrew Jeffery | a1e35b8 | 2018-08-24 09:39:10 +0930 | [diff] [blame] | 470 | static ipmi_ret_t hiomap_erase(ipmi_request_t request, ipmi_response_t response, | 
|  | 471 | ipmi_data_len_t data_len, ipmi_context_t context) | 
|  | 472 | { | 
|  | 473 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 474 |  | 
|  | 475 | if (*data_len < 4) | 
|  | 476 | { | 
|  | 477 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 478 | } | 
|  | 479 |  | 
|  | 480 | uint8_t *reqdata = (uint8_t *)request; | 
|  | 481 | auto m = ctx->bus->new_method_call(HIOMAPD_SERVICE, HIOMAPD_OBJECT, | 
|  | 482 | HIOMAPD_IFACE_V2, "Erase"); | 
|  | 483 | /* FIXME: Assumes v2 */ | 
|  | 484 | m.append(le16toh(get<uint16_t>(&reqdata[0]))); /* offset */ | 
|  | 485 | m.append(le16toh(get<uint16_t>(&reqdata[2]))); /* size */ | 
|  | 486 |  | 
|  | 487 | try | 
|  | 488 | { | 
|  | 489 | auto reply = ctx->bus->call(m); | 
|  | 490 |  | 
|  | 491 | *data_len = 0; | 
|  | 492 | } | 
|  | 493 | catch (const exception::SdBusError &e) | 
|  | 494 | { | 
|  | 495 | return hiomap_xlate_errno(e.get_errno()); | 
|  | 496 | } | 
|  | 497 |  | 
|  | 498 | return IPMI_CC_OK; | 
|  | 499 | } | 
|  | 500 |  | 
| Andrew Jeffery | 04d7513 | 2018-09-26 00:58:52 +0930 | [diff] [blame^] | 501 | #define HIOMAP_C_RESET 1 | 
|  | 502 | #define HIOMAP_C_GET_INFO 2 | 
|  | 503 | #define HIOMAP_C_GET_FLASH_INFO 3 | 
|  | 504 | #define HIOMAP_C_CREATE_READ_WINDOW 4 | 
|  | 505 | #define HIOMAP_C_CLOSE_WINDOW 5 | 
|  | 506 | #define HIOMAP_C_CREATE_WRITE_WINDOW 6 | 
|  | 507 | #define HIOMAP_C_MARK_DIRTY 7 | 
|  | 508 | #define HIOMAP_C_FLUSH 8 | 
|  | 509 | #define HIOMAP_C_ACK 9 | 
|  | 510 | #define HIOMAP_C_ERASE 10 | 
|  | 511 |  | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 512 | static const hiomap_command hiomap_commands[] = { | 
| Andrew Jeffery | 04d7513 | 2018-09-26 00:58:52 +0930 | [diff] [blame^] | 513 | [0] = NULL, /* Invalid command ID */ | 
|  | 514 | [HIOMAP_C_RESET] = hiomap_reset, | 
|  | 515 | [HIOMAP_C_GET_INFO] = hiomap_get_info, | 
|  | 516 | [HIOMAP_C_GET_FLASH_INFO] = hiomap_get_flash_info, | 
|  | 517 | [HIOMAP_C_CREATE_READ_WINDOW] = hiomap_create_read_window, | 
|  | 518 | [HIOMAP_C_CLOSE_WINDOW] = hiomap_close_window, | 
|  | 519 | [HIOMAP_C_CREATE_WRITE_WINDOW] = hiomap_create_write_window, | 
|  | 520 | [HIOMAP_C_MARK_DIRTY] = hiomap_mark_dirty, | 
|  | 521 | [HIOMAP_C_FLUSH] = hiomap_flush, | 
|  | 522 | [HIOMAP_C_ACK] = hiomap_ack, | 
|  | 523 | [HIOMAP_C_ERASE] = hiomap_erase, | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 524 | }; | 
|  | 525 |  | 
|  | 526 | /* FIXME: Define this in the "right" place, wherever that is */ | 
|  | 527 | /* FIXME: Double evaluation */ | 
|  | 528 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | 
|  | 529 |  | 
|  | 530 | static ipmi_ret_t hiomap_dispatch(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
|  | 531 | ipmi_request_t request, | 
|  | 532 | ipmi_response_t response, | 
|  | 533 | ipmi_data_len_t data_len, | 
|  | 534 | ipmi_context_t context) | 
|  | 535 | { | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 536 | struct hiomap *ctx = static_cast<struct hiomap *>(context); | 
|  | 537 |  | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 538 | if (*data_len < 2) | 
|  | 539 | { | 
|  | 540 | *data_len = 0; | 
|  | 541 | return IPMI_CC_REQ_DATA_LEN_INVALID; | 
|  | 542 | } | 
|  | 543 |  | 
|  | 544 | uint8_t *ipmi_req = (uint8_t *)request; | 
|  | 545 | uint8_t *ipmi_resp = (uint8_t *)response; | 
|  | 546 | uint8_t hiomap_cmd = ipmi_req[0]; | 
|  | 547 |  | 
|  | 548 | if (hiomap_cmd == 0 || hiomap_cmd > ARRAY_SIZE(hiomap_commands) - 1) | 
|  | 549 | { | 
|  | 550 | *data_len = 0; | 
|  | 551 | return IPMI_CC_PARM_OUT_OF_RANGE; | 
|  | 552 | } | 
| Andrew Jeffery | 04d7513 | 2018-09-26 00:58:52 +0930 | [diff] [blame^] | 553 |  | 
|  | 554 | bool is_unversioned = | 
|  | 555 | (hiomap_cmd == HIOMAP_C_RESET || hiomap_cmd == HIOMAP_C_GET_INFO || | 
|  | 556 | hiomap_cmd == HIOMAP_C_ACK); | 
|  | 557 | if (!is_unversioned && ctx->seq == ipmi_req[1]) | 
|  | 558 | { | 
|  | 559 | *data_len = 0; | 
|  | 560 | return IPMI_CC_INVALID_FIELD_REQUEST; | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 | ctx->seq = ipmi_req[1]; | 
|  | 564 |  | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 565 | uint8_t *flash_req = ipmi_req + 2; | 
|  | 566 | size_t flash_len = *data_len - 2; | 
|  | 567 | uint8_t *flash_resp = ipmi_resp + 2; | 
|  | 568 |  | 
|  | 569 | ipmi_ret_t cc = | 
|  | 570 | hiomap_commands[hiomap_cmd](flash_req, flash_resp, &flash_len, context); | 
|  | 571 | if (cc != IPMI_CC_OK) | 
|  | 572 | { | 
|  | 573 | *data_len = 0; | 
|  | 574 | return cc; | 
|  | 575 | } | 
|  | 576 |  | 
|  | 577 | /* Populate the response command and sequence */ | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 578 | ipmi_resp[0] = hiomap_cmd; | 
| Andrew Jeffery | 04d7513 | 2018-09-26 00:58:52 +0930 | [diff] [blame^] | 579 | ipmi_resp[1] = ctx->seq; | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 580 |  | 
|  | 581 | *data_len = flash_len + 2; | 
|  | 582 |  | 
|  | 583 | return cc; | 
|  | 584 | } | 
|  | 585 | } // namespace flash | 
|  | 586 | } // namespace openpower | 
|  | 587 |  | 
|  | 588 | static void register_openpower_hiomap_commands() | 
|  | 589 | { | 
| Andrew Jeffery | 0a3358e | 2018-08-21 10:42:09 +0930 | [diff] [blame] | 590 | using namespace openpower::flash; | 
|  | 591 |  | 
|  | 592 | /* FIXME: Clean this up? Can we unregister? */ | 
|  | 593 | struct hiomap *ctx = new hiomap(); | 
|  | 594 |  | 
|  | 595 | /* Initialise mapping from signal and property names to status bit */ | 
|  | 596 | ctx->event_lookup["DaemonReady"] = BMC_EVENT_DAEMON_READY; | 
|  | 597 | ctx->event_lookup["FlashControlLost"] = BMC_EVENT_FLASH_CTRL_LOST; | 
|  | 598 | ctx->event_lookup["WindowReset"] = BMC_EVENT_WINDOW_RESET; | 
|  | 599 | ctx->event_lookup["ProtocolReset"] = BMC_EVENT_PROTOCOL_RESET; | 
|  | 600 |  | 
|  | 601 | ctx->bus = new bus::bus(ipmid_get_sd_bus_connection()); | 
|  | 602 |  | 
|  | 603 | /* Initialise signal handling */ | 
|  | 604 |  | 
|  | 605 | /* | 
|  | 606 | * Can't use temporaries here because that causes SEGFAULTs due to slot | 
|  | 607 | * destruction (!?), so enjoy the weird wrapping. | 
|  | 608 | */ | 
|  | 609 | ctx->properties = | 
|  | 610 | new bus::match::match(std::move(hiomap_match_properties(ctx))); | 
|  | 611 | ctx->bmc_reboot = new bus::match::match( | 
|  | 612 | std::move(hiomap_match_signal_v2(ctx, "ProtocolReset"))); | 
|  | 613 | ctx->window_reset = new bus::match::match( | 
|  | 614 | std::move(hiomap_match_signal_v2(ctx, "WindowReset"))); | 
|  | 615 |  | 
|  | 616 | ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, ctx, | 
| Andrew Jeffery | 2c07f6f | 2018-08-10 16:24:32 +0930 | [diff] [blame] | 617 | openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE); | 
|  | 618 | } |