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