blob: f623e61f414bc2820eaac87ec8a7ca7c298026e5 [file] [log] [blame]
Andrew Jeffery2c07f6f2018-08-10 16:24:32 +09301// 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>
14#include <sdbusplus/bus.hpp>
15#include <sdbusplus/exception.hpp>
16
17using namespace sdbusplus;
18
19static void register_openpower_hiomap_commands() __attribute__((constructor));
20
21namespace openpower
22{
23namespace flash
24{
25
26/* TODO: Replace get/put with packed structs and direct assignment */
27template <typename T> static inline T get(void *buf)
28{
29 T t;
30 memcpy(&t, buf, sizeof(t));
31 return t;
32}
33
34template <typename T> static inline void put(void *buf, T &&t)
35{
36 memcpy(buf, &t, sizeof(t));
37}
38
39typedef ipmi_ret_t (*hiomap_command)(ipmi_request_t req, ipmi_response_t resp,
40 ipmi_data_len_t data_len,
41 ipmi_context_t context);
42
43struct errno_cc_entry
44{
45 int err;
46 int cc;
47};
48
49static const errno_cc_entry errno_cc_map[] = {
50 {0, IPMI_CC_OK},
51 {EBUSY, IPMI_CC_BUSY},
52 {ENOTSUP, IPMI_CC_INVALID},
53 {ETIMEDOUT, 0xc3}, /* FIXME: Replace when defined in ipmid-api.h */
54 {ENOSPC, 0xc4}, /* FIXME: Replace when defined in ipmid-api.h */
55 {EINVAL, IPMI_CC_PARM_OUT_OF_RANGE},
56 {ENODEV, IPMI_CC_SENSOR_INVALID},
57 {EPERM, IPMI_CC_INSUFFICIENT_PRIVILEGE},
58 {EACCES, IPMI_CC_INSUFFICIENT_PRIVILEGE},
59 {-1, IPMI_CC_UNSPECIFIED_ERROR},
60};
61
62static int hiomap_xlate_errno(int err)
63{
64 const errno_cc_entry *entry = &errno_cc_map[0];
65
66 while (!(entry->err == err || entry->err == -1))
67 {
68 entry++;
69 }
70
71 return entry->cc;
72}
73
74static ipmi_ret_t hiomap_get_info(ipmi_request_t request,
75 ipmi_response_t response,
76 ipmi_data_len_t data_len,
77 ipmi_context_t context)
78{
79 if (*data_len < 1)
80 {
81 return IPMI_CC_REQ_DATA_LEN_INVALID;
82 }
83
84 uint8_t *reqdata = (uint8_t *)request;
85 auto b = bus::new_system();
86 auto m = b.new_method_call(
87 "xyz.openbmc_project.Hiomapd", "/xyz/openbmc_project/Hiomapd",
88 "xyz.openbmc_project.Hiomapd.Protocol", "GetInfo");
89 m.append(reqdata[0]);
90
91 try
92 {
93 auto reply = b.call(m);
94
95 uint8_t version;
96 uint8_t blockSizeShift;
97 uint16_t timeout;
98 reply.read(version, blockSizeShift, timeout);
99
100 uint8_t *respdata = (uint8_t *)response;
101
102 /* FIXME: Assumes v2! */
103 put(&respdata[0], version);
104 put(&respdata[1], blockSizeShift);
105 put(&respdata[2], htole16(timeout));
106
107 *data_len = 4;
108 }
109 catch (const exception::SdBusError &e)
110 {
111 return hiomap_xlate_errno(e.get_errno());
112 }
113
114 return IPMI_CC_OK;
115}
116
117static const hiomap_command hiomap_commands[] = {
118 [0] = NULL, /* 0 is an invalid command ID */
119 [1] = NULL, /* RESET */
120 [2] = hiomap_get_info,
121};
122
123/* FIXME: Define this in the "right" place, wherever that is */
124/* FIXME: Double evaluation */
125#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
126
127static ipmi_ret_t hiomap_dispatch(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
128 ipmi_request_t request,
129 ipmi_response_t response,
130 ipmi_data_len_t data_len,
131 ipmi_context_t context)
132{
133 if (*data_len < 2)
134 {
135 *data_len = 0;
136 return IPMI_CC_REQ_DATA_LEN_INVALID;
137 }
138
139 uint8_t *ipmi_req = (uint8_t *)request;
140 uint8_t *ipmi_resp = (uint8_t *)response;
141 uint8_t hiomap_cmd = ipmi_req[0];
142
143 if (hiomap_cmd == 0 || hiomap_cmd > ARRAY_SIZE(hiomap_commands) - 1)
144 {
145 *data_len = 0;
146 return IPMI_CC_PARM_OUT_OF_RANGE;
147 }
148 uint8_t *flash_req = ipmi_req + 2;
149 size_t flash_len = *data_len - 2;
150 uint8_t *flash_resp = ipmi_resp + 2;
151
152 ipmi_ret_t cc =
153 hiomap_commands[hiomap_cmd](flash_req, flash_resp, &flash_len, context);
154 if (cc != IPMI_CC_OK)
155 {
156 *data_len = 0;
157 return cc;
158 }
159
160 /* Populate the response command and sequence */
161 put(&ipmi_resp[0], ipmi_req[0]);
162 put(&ipmi_resp[1], ipmi_req[1]);
163
164 *data_len = flash_len + 2;
165
166 return cc;
167}
168} // namespace flash
169} // namespace openpower
170
171static void register_openpower_hiomap_commands()
172{
173 ipmi_register_callback(NETFUN_IBM_OEM, IPMI_CMD_HIOMAP, NULL,
174 openpower::flash::hiomap_dispatch, SYSTEM_INTERFACE);
175}