xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 8bfffbccad2b7a9836caee359bd5055ab6989ac5)
1*8bfffbccSCorey Minyard /*
2*8bfffbccSCorey Minyard  * IPMI BMC emulation
3*8bfffbccSCorey Minyard  *
4*8bfffbccSCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
5*8bfffbccSCorey Minyard  *
6*8bfffbccSCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*8bfffbccSCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
8*8bfffbccSCorey Minyard  * in the Software without restriction, including without limitation the rights
9*8bfffbccSCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*8bfffbccSCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
11*8bfffbccSCorey Minyard  * furnished to do so, subject to the following conditions:
12*8bfffbccSCorey Minyard  *
13*8bfffbccSCorey Minyard  * The above copyright notice and this permission notice shall be included in
14*8bfffbccSCorey Minyard  * all copies or substantial portions of the Software.
15*8bfffbccSCorey Minyard  *
16*8bfffbccSCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*8bfffbccSCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*8bfffbccSCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*8bfffbccSCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*8bfffbccSCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*8bfffbccSCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22*8bfffbccSCorey Minyard  * THE SOFTWARE.
23*8bfffbccSCorey Minyard  */
24*8bfffbccSCorey Minyard 
25*8bfffbccSCorey Minyard #include <stdio.h>
26*8bfffbccSCorey Minyard #include <string.h>
27*8bfffbccSCorey Minyard #include <stdint.h>
28*8bfffbccSCorey Minyard #include "qemu/timer.h"
29*8bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
30*8bfffbccSCorey Minyard #include "qemu/error-report.h"
31*8bfffbccSCorey Minyard 
32*8bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
33*8bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS_MAXCMD         0x03
34*8bfffbccSCorey Minyard 
35*8bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
36*8bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
37*8bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
38*8bfffbccSCorey Minyard 
39*8bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
40*8bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT_MAXCMD    0x2e
41*8bfffbccSCorey Minyard 
42*8bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
43*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
44*8bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
45*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
46*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
47*8bfffbccSCorey Minyard 
48*8bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
49*8bfffbccSCorey Minyard #define IPMI_NETFN_APP_MAXCMD             0x36
50*8bfffbccSCorey Minyard 
51*8bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
52*8bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
53*8bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
54*8bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
55*8bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
56*8bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
57*8bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
58*8bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
59*8bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
60*8bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
61*8bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
62*8bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
63*8bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
64*8bfffbccSCorey Minyard 
65*8bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
66*8bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE_MAXCMD         0x4a
67*8bfffbccSCorey Minyard 
68*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
69*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
70*8bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
71*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
72*8bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
73*8bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
74*8bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
75*8bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
76*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
77*8bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
78*8bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
79*8bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
80*8bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
81*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
82*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
83*8bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
84*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
85*8bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
86*8bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
87*8bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
88*8bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
89*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
90*8bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
91*8bfffbccSCorey Minyard 
92*8bfffbccSCorey Minyard 
93*8bfffbccSCorey Minyard /* Same as a timespec struct. */
94*8bfffbccSCorey Minyard struct ipmi_time {
95*8bfffbccSCorey Minyard     long tv_sec;
96*8bfffbccSCorey Minyard     long tv_nsec;
97*8bfffbccSCorey Minyard };
98*8bfffbccSCorey Minyard 
99*8bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
100*8bfffbccSCorey Minyard 
101*8bfffbccSCorey Minyard typedef struct IPMISel {
102*8bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
103*8bfffbccSCorey Minyard     unsigned int next_free;
104*8bfffbccSCorey Minyard     long time_offset;
105*8bfffbccSCorey Minyard     uint16_t reservation;
106*8bfffbccSCorey Minyard     uint8_t last_addition[4];
107*8bfffbccSCorey Minyard     uint8_t last_clear[4];
108*8bfffbccSCorey Minyard     uint8_t overflow;
109*8bfffbccSCorey Minyard } IPMISel;
110*8bfffbccSCorey Minyard 
111*8bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
112*8bfffbccSCorey Minyard 
113*8bfffbccSCorey Minyard typedef struct IPMISdr {
114*8bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
115*8bfffbccSCorey Minyard     unsigned int next_free;
116*8bfffbccSCorey Minyard     uint16_t next_rec_id;
117*8bfffbccSCorey Minyard     uint16_t reservation;
118*8bfffbccSCorey Minyard     uint8_t last_addition[4];
119*8bfffbccSCorey Minyard     uint8_t last_clear[4];
120*8bfffbccSCorey Minyard     uint8_t overflow;
121*8bfffbccSCorey Minyard } IPMISdr;
122*8bfffbccSCorey Minyard 
123*8bfffbccSCorey Minyard typedef struct IPMISensor {
124*8bfffbccSCorey Minyard     uint8_t status;
125*8bfffbccSCorey Minyard     uint8_t reading;
126*8bfffbccSCorey Minyard     uint16_t states_suppt;
127*8bfffbccSCorey Minyard     uint16_t assert_suppt;
128*8bfffbccSCorey Minyard     uint16_t deassert_suppt;
129*8bfffbccSCorey Minyard     uint16_t states;
130*8bfffbccSCorey Minyard     uint16_t assert_states;
131*8bfffbccSCorey Minyard     uint16_t deassert_states;
132*8bfffbccSCorey Minyard     uint16_t assert_enable;
133*8bfffbccSCorey Minyard     uint16_t deassert_enable;
134*8bfffbccSCorey Minyard     uint8_t  sensor_type;
135*8bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
136*8bfffbccSCorey Minyard } IPMISensor;
137*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
138*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
139*8bfffbccSCorey Minyard                                              !!(v))
140*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
141*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
142*8bfffbccSCorey Minyard                                              ((!!(v)) << 6))
143*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
144*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
145*8bfffbccSCorey Minyard                                              ((!!(v)) << 7))
146*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
147*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
148*8bfffbccSCorey Minyard                                              (v & 0xc0))
149*8bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
150*8bfffbccSCorey Minyard 
151*8bfffbccSCorey Minyard #define MAX_SENSORS 20
152*8bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
153*8bfffbccSCorey Minyard 
154*8bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
155*8bfffbccSCorey Minyard 
156*8bfffbccSCorey Minyard #define MAX_NETFNS 64
157*8bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s,
158*8bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
159*8bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
160*8bfffbccSCorey Minyard                                unsigned int max_rsp_len);
161*8bfffbccSCorey Minyard typedef struct IPMINetfn {
162*8bfffbccSCorey Minyard     unsigned int cmd_nums;
163*8bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
164*8bfffbccSCorey Minyard } IPMINetfn;
165*8bfffbccSCorey Minyard 
166*8bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
167*8bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
168*8bfffbccSCorey Minyard     uint8_t len;
169*8bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
170*8bfffbccSCorey Minyard } IPMIRcvBufEntry;
171*8bfffbccSCorey Minyard 
172*8bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
173*8bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
174*8bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
175*8bfffbccSCorey Minyard struct IPMIBmcSim {
176*8bfffbccSCorey Minyard     IPMIBmc parent;
177*8bfffbccSCorey Minyard 
178*8bfffbccSCorey Minyard     QEMUTimer *timer;
179*8bfffbccSCorey Minyard 
180*8bfffbccSCorey Minyard     uint8_t bmc_global_enables;
181*8bfffbccSCorey Minyard     uint8_t msg_flags;
182*8bfffbccSCorey Minyard 
183*8bfffbccSCorey Minyard     bool     watchdog_initialized;
184*8bfffbccSCorey Minyard     uint8_t  watchdog_use;
185*8bfffbccSCorey Minyard     uint8_t  watchdog_action;
186*8bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
187*8bfffbccSCorey Minyard     bool     watchdog_expired;
188*8bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
189*8bfffbccSCorey Minyard 
190*8bfffbccSCorey Minyard     bool     watchdog_running;
191*8bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
192*8bfffbccSCorey Minyard     int64_t  watchdog_expiry;
193*8bfffbccSCorey Minyard 
194*8bfffbccSCorey Minyard     uint8_t device_id;
195*8bfffbccSCorey Minyard     uint8_t ipmi_version;
196*8bfffbccSCorey Minyard     uint8_t device_rev;
197*8bfffbccSCorey Minyard     uint8_t fwrev1;
198*8bfffbccSCorey Minyard     uint8_t fwrev2;
199*8bfffbccSCorey Minyard     uint8_t mfg_id[3];
200*8bfffbccSCorey Minyard     uint8_t product_id[2];
201*8bfffbccSCorey Minyard 
202*8bfffbccSCorey Minyard     IPMISel sel;
203*8bfffbccSCorey Minyard     IPMISdr sdr;
204*8bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
205*8bfffbccSCorey Minyard 
206*8bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
207*8bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
208*8bfffbccSCorey Minyard 
209*8bfffbccSCorey Minyard     QemuMutex lock;
210*8bfffbccSCorey Minyard     /* We allow one event in the buffer */
211*8bfffbccSCorey Minyard     uint8_t evtbuf[16];
212*8bfffbccSCorey Minyard 
213*8bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
214*8bfffbccSCorey Minyard };
215*8bfffbccSCorey Minyard 
216*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
217*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
218*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
219*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
220*8bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
221*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
222*8bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
223*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
224*8bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
225*8bfffbccSCorey Minyard 
226*8bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
227*8bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
228*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
229*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
230*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
231*8bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
232*8bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
233*8bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
234*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
235*8bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
236*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
237*8bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
238*8bfffbccSCorey Minyard 
239*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
240*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
241*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
242*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
243*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
244*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
245*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
246*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
247*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
248*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
249*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
250*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
251*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
252*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
253*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
254*8bfffbccSCorey Minyard 
255*8bfffbccSCorey Minyard 
256*8bfffbccSCorey Minyard /* Add a byte to the response. */
257*8bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \
258*8bfffbccSCorey Minyard     do {                                                   \
259*8bfffbccSCorey Minyard         if (*rsp_len >= max_rsp_len) {                     \
260*8bfffbccSCorey Minyard             rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;       \
261*8bfffbccSCorey Minyard             goto out;                                      \
262*8bfffbccSCorey Minyard         }                                                  \
263*8bfffbccSCorey Minyard         rsp[(*rsp_len)++] = (b);                           \
264*8bfffbccSCorey Minyard     } while (0)
265*8bfffbccSCorey Minyard 
266*8bfffbccSCorey Minyard /* Verify that the received command is a certain length. */
267*8bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \
268*8bfffbccSCorey Minyard     if (cmd_len < l) {                                     \
269*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;      \
270*8bfffbccSCorey Minyard         goto out; \
271*8bfffbccSCorey Minyard     }
272*8bfffbccSCorey Minyard 
273*8bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */
274*8bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \
275*8bfffbccSCorey Minyard     do {                                                   \
276*8bfffbccSCorey Minyard         if ((cmd[off] | (cmd[off + 1] << 8)) != r) {       \
277*8bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_RESERVATION;          \
278*8bfffbccSCorey Minyard             goto out;                                      \
279*8bfffbccSCorey Minyard         }                                                  \
280*8bfffbccSCorey Minyard     } while (0)
281*8bfffbccSCorey Minyard 
282*8bfffbccSCorey Minyard 
283*8bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
284*8bfffbccSCorey Minyard 
285*8bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
286*8bfffbccSCorey Minyard {
287*8bfffbccSCorey Minyard     int64_t stime;
288*8bfffbccSCorey Minyard 
289*8bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
290*8bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
291*8bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
292*8bfffbccSCorey Minyard }
293*8bfffbccSCorey Minyard 
294*8bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
295*8bfffbccSCorey Minyard {
296*8bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
297*8bfffbccSCorey Minyard }
298*8bfffbccSCorey Minyard 
299*8bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
300*8bfffbccSCorey Minyard {
301*8bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
302*8bfffbccSCorey Minyard 
303*8bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
304*8bfffbccSCorey Minyard }
305*8bfffbccSCorey Minyard 
306*8bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
307*8bfffbccSCorey Minyard {
308*8bfffbccSCorey Minyard     unsigned int val;
309*8bfffbccSCorey Minyard     struct ipmi_time now;
310*8bfffbccSCorey Minyard 
311*8bfffbccSCorey Minyard     ipmi_gettime(&now);
312*8bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
313*8bfffbccSCorey Minyard     ts[0] = val & 0xff;
314*8bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
315*8bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
316*8bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
317*8bfffbccSCorey Minyard }
318*8bfffbccSCorey Minyard 
319*8bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
320*8bfffbccSCorey Minyard {
321*8bfffbccSCorey Minyard     sdr->reservation++;
322*8bfffbccSCorey Minyard     if (sdr->reservation == 0) {
323*8bfffbccSCorey Minyard         sdr->reservation = 1;
324*8bfffbccSCorey Minyard     }
325*8bfffbccSCorey Minyard }
326*8bfffbccSCorey Minyard 
327*8bfffbccSCorey Minyard static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry,
328*8bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
329*8bfffbccSCorey Minyard {
330*8bfffbccSCorey Minyard     if ((len < 5) || (len > 255)) {
331*8bfffbccSCorey Minyard         return 1;
332*8bfffbccSCorey Minyard     }
333*8bfffbccSCorey Minyard 
334*8bfffbccSCorey Minyard     if (entry[4] != len - 5) {
335*8bfffbccSCorey Minyard         return 1;
336*8bfffbccSCorey Minyard     }
337*8bfffbccSCorey Minyard 
338*8bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
339*8bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
340*8bfffbccSCorey Minyard         return 1;
341*8bfffbccSCorey Minyard     }
342*8bfffbccSCorey Minyard 
343*8bfffbccSCorey Minyard     memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len);
344*8bfffbccSCorey Minyard     ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff;
345*8bfffbccSCorey Minyard     ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
346*8bfffbccSCorey Minyard     ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */
347*8bfffbccSCorey Minyard 
348*8bfffbccSCorey Minyard     if (recid) {
349*8bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
350*8bfffbccSCorey Minyard     }
351*8bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
352*8bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
353*8bfffbccSCorey Minyard     ibs->sdr.next_free += len;
354*8bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
355*8bfffbccSCorey Minyard     return 0;
356*8bfffbccSCorey Minyard }
357*8bfffbccSCorey Minyard 
358*8bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
359*8bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
360*8bfffbccSCorey Minyard {
361*8bfffbccSCorey Minyard     unsigned int pos = *retpos;
362*8bfffbccSCorey Minyard 
363*8bfffbccSCorey Minyard     while (pos < sdr->next_free) {
364*8bfffbccSCorey Minyard         uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8);
365*8bfffbccSCorey Minyard         unsigned int nextpos = pos + sdr->sdr[pos + 4];
366*8bfffbccSCorey Minyard 
367*8bfffbccSCorey Minyard         if (trec == recid) {
368*8bfffbccSCorey Minyard             if (nextrec) {
369*8bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
370*8bfffbccSCorey Minyard                     *nextrec = 0xffff;
371*8bfffbccSCorey Minyard                 } else {
372*8bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
373*8bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
374*8bfffbccSCorey Minyard                 }
375*8bfffbccSCorey Minyard             }
376*8bfffbccSCorey Minyard             *retpos = pos;
377*8bfffbccSCorey Minyard             return 0;
378*8bfffbccSCorey Minyard         }
379*8bfffbccSCorey Minyard         pos = nextpos;
380*8bfffbccSCorey Minyard     }
381*8bfffbccSCorey Minyard     return 1;
382*8bfffbccSCorey Minyard }
383*8bfffbccSCorey Minyard 
384*8bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
385*8bfffbccSCorey Minyard {
386*8bfffbccSCorey Minyard     sel->reservation++;
387*8bfffbccSCorey Minyard     if (sel->reservation == 0) {
388*8bfffbccSCorey Minyard         sel->reservation = 1;
389*8bfffbccSCorey Minyard     }
390*8bfffbccSCorey Minyard }
391*8bfffbccSCorey Minyard 
392*8bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
393*8bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
394*8bfffbccSCorey Minyard {
395*8bfffbccSCorey Minyard     event[0] = 0xff;
396*8bfffbccSCorey Minyard     event[1] = 0xff;
397*8bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
398*8bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
399*8bfffbccSCorey Minyard         ibs->sel.overflow = 1;
400*8bfffbccSCorey Minyard         return 1;
401*8bfffbccSCorey Minyard     }
402*8bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
403*8bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
404*8bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
405*8bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
406*8bfffbccSCorey Minyard     ibs->sel.next_free++;
407*8bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
408*8bfffbccSCorey Minyard     return 0;
409*8bfffbccSCorey Minyard }
410*8bfffbccSCorey Minyard 
411*8bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
412*8bfffbccSCorey Minyard {
413*8bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
414*8bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
415*8bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
416*8bfffbccSCorey Minyard }
417*8bfffbccSCorey Minyard 
418*8bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
419*8bfffbccSCorey Minyard {
420*8bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
421*8bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
422*8bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
423*8bfffbccSCorey Minyard }
424*8bfffbccSCorey Minyard 
425*8bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
426*8bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
427*8bfffbccSCorey Minyard {
428*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
429*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
430*8bfffbccSCorey Minyard     uint8_t evt[16];
431*8bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
432*8bfffbccSCorey Minyard 
433*8bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
434*8bfffbccSCorey Minyard         return;
435*8bfffbccSCorey Minyard     }
436*8bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
437*8bfffbccSCorey Minyard         return;
438*8bfffbccSCorey Minyard     }
439*8bfffbccSCorey Minyard 
440*8bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
441*8bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
442*8bfffbccSCorey Minyard     evt[8] = 0;
443*8bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
444*8bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
445*8bfffbccSCorey Minyard     evt[11] = sens_num;
446*8bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
447*8bfffbccSCorey Minyard     evt[13] = evd1;
448*8bfffbccSCorey Minyard     evt[14] = evd2;
449*8bfffbccSCorey Minyard     evt[15] = evd3;
450*8bfffbccSCorey Minyard 
451*8bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
452*8bfffbccSCorey Minyard         sel_add_event(ibs, evt);
453*8bfffbccSCorey Minyard     }
454*8bfffbccSCorey Minyard 
455*8bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
456*8bfffbccSCorey Minyard         goto out;
457*8bfffbccSCorey Minyard     }
458*8bfffbccSCorey Minyard 
459*8bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
460*8bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
461*8bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
462*8bfffbccSCorey Minyard  out:
463*8bfffbccSCorey Minyard     return;
464*8bfffbccSCorey Minyard }
465*8bfffbccSCorey Minyard 
466*8bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
467*8bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
468*8bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
469*8bfffbccSCorey Minyard {
470*8bfffbccSCorey Minyard     IPMISensor *sens;
471*8bfffbccSCorey Minyard     uint16_t mask;
472*8bfffbccSCorey Minyard 
473*8bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
474*8bfffbccSCorey Minyard         return;
475*8bfffbccSCorey Minyard     }
476*8bfffbccSCorey Minyard     if (bit >= 16) {
477*8bfffbccSCorey Minyard         return;
478*8bfffbccSCorey Minyard     }
479*8bfffbccSCorey Minyard 
480*8bfffbccSCorey Minyard     mask = (1 << bit);
481*8bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
482*8bfffbccSCorey Minyard     if (val) {
483*8bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
484*8bfffbccSCorey Minyard         if (sens->assert_states & mask) {
485*8bfffbccSCorey Minyard             return; /* Already asserted */
486*8bfffbccSCorey Minyard         }
487*8bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
488*8bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
489*8bfffbccSCorey Minyard             /* Send an event on assert */
490*8bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
491*8bfffbccSCorey Minyard         }
492*8bfffbccSCorey Minyard     } else {
493*8bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
494*8bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
495*8bfffbccSCorey Minyard             return; /* Already deasserted */
496*8bfffbccSCorey Minyard         }
497*8bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
498*8bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
499*8bfffbccSCorey Minyard             /* Send an event on deassert */
500*8bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
501*8bfffbccSCorey Minyard         }
502*8bfffbccSCorey Minyard     }
503*8bfffbccSCorey Minyard }
504*8bfffbccSCorey Minyard 
505*8bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
506*8bfffbccSCorey Minyard {
507*8bfffbccSCorey Minyard     unsigned int i, pos;
508*8bfffbccSCorey Minyard     IPMISensor *sens;
509*8bfffbccSCorey Minyard 
510*8bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
511*8bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
512*8bfffbccSCorey Minyard     }
513*8bfffbccSCorey Minyard 
514*8bfffbccSCorey Minyard     pos = 0;
515*8bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
516*8bfffbccSCorey Minyard         uint8_t *sdr = s->sdr.sdr + pos;
517*8bfffbccSCorey Minyard         unsigned int len = sdr[4];
518*8bfffbccSCorey Minyard 
519*8bfffbccSCorey Minyard         if (len < 20) {
520*8bfffbccSCorey Minyard             continue;
521*8bfffbccSCorey Minyard         }
522*8bfffbccSCorey Minyard         if ((sdr[3] < 1) || (sdr[3] > 2)) {
523*8bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
524*8bfffbccSCorey Minyard         }
525*8bfffbccSCorey Minyard 
526*8bfffbccSCorey Minyard         if (sdr[7] > MAX_SENSORS) {
527*8bfffbccSCorey Minyard             continue;
528*8bfffbccSCorey Minyard         }
529*8bfffbccSCorey Minyard         sens = s->sensors + sdr[7];
530*8bfffbccSCorey Minyard 
531*8bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
532*8bfffbccSCorey Minyard         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1);
533*8bfffbccSCorey Minyard         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1);
534*8bfffbccSCorey Minyard         sens->assert_suppt = sdr[14] | (sdr[15] << 8);
535*8bfffbccSCorey Minyard         sens->deassert_suppt = sdr[16] | (sdr[17] << 8);
536*8bfffbccSCorey Minyard         sens->states_suppt = sdr[18] | (sdr[19] << 8);
537*8bfffbccSCorey Minyard         sens->sensor_type = sdr[12];
538*8bfffbccSCorey Minyard         sens->evt_reading_type_code = sdr[13] & 0x7f;
539*8bfffbccSCorey Minyard 
540*8bfffbccSCorey Minyard         /* Enable all the events that are supported. */
541*8bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
542*8bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
543*8bfffbccSCorey Minyard     }
544*8bfffbccSCorey Minyard }
545*8bfffbccSCorey Minyard 
546*8bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
547*8bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
548*8bfffbccSCorey Minyard {
549*8bfffbccSCorey Minyard     if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) {
550*8bfffbccSCorey Minyard         return -1;
551*8bfffbccSCorey Minyard     }
552*8bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
553*8bfffbccSCorey Minyard     return 0;
554*8bfffbccSCorey Minyard }
555*8bfffbccSCorey Minyard 
556*8bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
557*8bfffbccSCorey Minyard {
558*8bfffbccSCorey Minyard     int64_t next;
559*8bfffbccSCorey Minyard     if (ibs->watchdog_running) {
560*8bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
561*8bfffbccSCorey Minyard     } else {
562*8bfffbccSCorey Minyard         /* Wait a minute */
563*8bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
564*8bfffbccSCorey Minyard     }
565*8bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
566*8bfffbccSCorey Minyard }
567*8bfffbccSCorey Minyard 
568*8bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
569*8bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
570*8bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
571*8bfffbccSCorey Minyard                                     uint8_t msg_id)
572*8bfffbccSCorey Minyard {
573*8bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
574*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
575*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
576*8bfffbccSCorey Minyard     unsigned int netfn;
577*8bfffbccSCorey Minyard     uint8_t rsp[MAX_IPMI_MSG_SIZE];
578*8bfffbccSCorey Minyard     unsigned int rsp_len_holder = 0;
579*8bfffbccSCorey Minyard     unsigned int *rsp_len = &rsp_len_holder;
580*8bfffbccSCorey Minyard     unsigned int max_rsp_len = sizeof(rsp);
581*8bfffbccSCorey Minyard 
582*8bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
583*8bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
584*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
585*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[1]);
586*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0); /* Assume success */
587*8bfffbccSCorey Minyard 
588*8bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
589*8bfffbccSCorey Minyard     if (cmd_len < 2) {
590*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
591*8bfffbccSCorey Minyard         goto out;
592*8bfffbccSCorey Minyard     }
593*8bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
594*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
595*8bfffbccSCorey Minyard         goto out;
596*8bfffbccSCorey Minyard     }
597*8bfffbccSCorey Minyard 
598*8bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
599*8bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
600*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
601*8bfffbccSCorey Minyard         goto out;
602*8bfffbccSCorey Minyard     }
603*8bfffbccSCorey Minyard 
604*8bfffbccSCorey Minyard     netfn = cmd[0] >> 2;
605*8bfffbccSCorey Minyard 
606*8bfffbccSCorey Minyard     /* Odd netfns are not valid, make sure the command is registered */
607*8bfffbccSCorey Minyard     if ((netfn & 1) || !ibs->netfns[netfn / 2] ||
608*8bfffbccSCorey Minyard                         (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) ||
609*8bfffbccSCorey Minyard                         (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) {
610*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_CMD;
611*8bfffbccSCorey Minyard         goto out;
612*8bfffbccSCorey Minyard     }
613*8bfffbccSCorey Minyard 
614*8bfffbccSCorey Minyard     ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len,
615*8bfffbccSCorey Minyard                                                 max_rsp_len);
616*8bfffbccSCorey Minyard 
617*8bfffbccSCorey Minyard  out:
618*8bfffbccSCorey Minyard     k->handle_rsp(s, msg_id, rsp, *rsp_len);
619*8bfffbccSCorey Minyard 
620*8bfffbccSCorey Minyard     next_timeout(ibs);
621*8bfffbccSCorey Minyard }
622*8bfffbccSCorey Minyard 
623*8bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
624*8bfffbccSCorey Minyard {
625*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
626*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
627*8bfffbccSCorey Minyard 
628*8bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
629*8bfffbccSCorey Minyard         goto out;
630*8bfffbccSCorey Minyard     }
631*8bfffbccSCorey Minyard 
632*8bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
633*8bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
634*8bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
635*8bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
636*8bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
637*8bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
638*8bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
639*8bfffbccSCorey Minyard             break;
640*8bfffbccSCorey Minyard 
641*8bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
642*8bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
643*8bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
644*8bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
645*8bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
646*8bfffbccSCorey Minyard             break;
647*8bfffbccSCorey Minyard 
648*8bfffbccSCorey Minyard         default:
649*8bfffbccSCorey Minyard             goto do_full_expiry;
650*8bfffbccSCorey Minyard         }
651*8bfffbccSCorey Minyard 
652*8bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
653*8bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
654*8bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
655*8bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
656*8bfffbccSCorey Minyard         goto out;
657*8bfffbccSCorey Minyard     }
658*8bfffbccSCorey Minyard 
659*8bfffbccSCorey Minyard  do_full_expiry:
660*8bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
661*8bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
662*8bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
663*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
664*8bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
665*8bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
666*8bfffbccSCorey Minyard         break;
667*8bfffbccSCorey Minyard 
668*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
669*8bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
670*8bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
671*8bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
672*8bfffbccSCorey Minyard         break;
673*8bfffbccSCorey Minyard 
674*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
675*8bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
676*8bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
677*8bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
678*8bfffbccSCorey Minyard         break;
679*8bfffbccSCorey Minyard 
680*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
681*8bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
682*8bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
683*8bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
684*8bfffbccSCorey Minyard         break;
685*8bfffbccSCorey Minyard     }
686*8bfffbccSCorey Minyard 
687*8bfffbccSCorey Minyard  out:
688*8bfffbccSCorey Minyard     next_timeout(ibs);
689*8bfffbccSCorey Minyard }
690*8bfffbccSCorey Minyard 
691*8bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
692*8bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
693*8bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
694*8bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
695*8bfffbccSCorey Minyard {
696*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
697*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
698*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
699*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
700*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
701*8bfffbccSCorey Minyard  out:
702*8bfffbccSCorey Minyard     return;
703*8bfffbccSCorey Minyard }
704*8bfffbccSCorey Minyard 
705*8bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
706*8bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
707*8bfffbccSCorey Minyard                            uint8_t *rsp, unsigned int *rsp_len,
708*8bfffbccSCorey Minyard                            unsigned int max_rsp_len)
709*8bfffbccSCorey Minyard {
710*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */
711*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
712*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
713*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
714*8bfffbccSCorey Minyard  out:
715*8bfffbccSCorey Minyard     return;
716*8bfffbccSCorey Minyard }
717*8bfffbccSCorey Minyard 
718*8bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
719*8bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
720*8bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
721*8bfffbccSCorey Minyard                             unsigned int max_rsp_len)
722*8bfffbccSCorey Minyard {
723*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
724*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
725*8bfffbccSCorey Minyard 
726*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
727*8bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
728*8bfffbccSCorey Minyard     case 0: /* power down */
729*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
730*8bfffbccSCorey Minyard         break;
731*8bfffbccSCorey Minyard     case 1: /* power up */
732*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
733*8bfffbccSCorey Minyard         break;
734*8bfffbccSCorey Minyard     case 2: /* power cycle */
735*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
736*8bfffbccSCorey Minyard         break;
737*8bfffbccSCorey Minyard     case 3: /* hard reset */
738*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
739*8bfffbccSCorey Minyard         break;
740*8bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
741*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
742*8bfffbccSCorey Minyard         break;
743*8bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
744*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s,
745*8bfffbccSCorey Minyard                              IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
746*8bfffbccSCorey Minyard         break;
747*8bfffbccSCorey Minyard     default:
748*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
749*8bfffbccSCorey Minyard         goto out;
750*8bfffbccSCorey Minyard     }
751*8bfffbccSCorey Minyard  out:
752*8bfffbccSCorey Minyard     return;
753*8bfffbccSCorey Minyard }
754*8bfffbccSCorey Minyard 
755*8bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
756*8bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
757*8bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
758*8bfffbccSCorey Minyard                           unsigned int max_rsp_len)
759*8bfffbccSCorey Minyard {
760*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_id);
761*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf);
762*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f);
763*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev2);
764*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->ipmi_version);
765*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */
766*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[0]);
767*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[1]);
768*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
769*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[0]);
770*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[1]);
771*8bfffbccSCorey Minyard  out:
772*8bfffbccSCorey Minyard     return;
773*8bfffbccSCorey Minyard }
774*8bfffbccSCorey Minyard 
775*8bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
776*8bfffbccSCorey Minyard {
777*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
778*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
779*8bfffbccSCorey Minyard     bool irqs_on;
780*8bfffbccSCorey Minyard 
781*8bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
782*8bfffbccSCorey Minyard 
783*8bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
784*8bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
785*8bfffbccSCorey Minyard 
786*8bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
787*8bfffbccSCorey Minyard }
788*8bfffbccSCorey Minyard 
789*8bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
790*8bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
791*8bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
792*8bfffbccSCorey Minyard                        unsigned int max_rsp_len)
793*8bfffbccSCorey Minyard {
794*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
795*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
796*8bfffbccSCorey Minyard 
797*8bfffbccSCorey Minyard     /* Disable all interrupts */
798*8bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
799*8bfffbccSCorey Minyard 
800*8bfffbccSCorey Minyard     if (k->reset) {
801*8bfffbccSCorey Minyard         k->reset(s, true);
802*8bfffbccSCorey Minyard     }
803*8bfffbccSCorey Minyard }
804*8bfffbccSCorey Minyard 
805*8bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
806*8bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
807*8bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
808*8bfffbccSCorey Minyard                        unsigned int max_rsp_len)
809*8bfffbccSCorey Minyard {
810*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
811*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
812*8bfffbccSCorey Minyard 
813*8bfffbccSCorey Minyard     if (k->reset) {
814*8bfffbccSCorey Minyard         k->reset(s, false);
815*8bfffbccSCorey Minyard     }
816*8bfffbccSCorey Minyard }
817*8bfffbccSCorey Minyard 
818*8bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
819*8bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
820*8bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
821*8bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
822*8bfffbccSCorey Minyard {
823*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
824*8bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
825*8bfffbccSCorey Minyard  out:
826*8bfffbccSCorey Minyard     return;
827*8bfffbccSCorey Minyard }
828*8bfffbccSCorey Minyard 
829*8bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
830*8bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
831*8bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
832*8bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
833*8bfffbccSCorey Minyard {
834*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
835*8bfffbccSCorey Minyard  out:
836*8bfffbccSCorey Minyard     return;
837*8bfffbccSCorey Minyard }
838*8bfffbccSCorey Minyard 
839*8bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
840*8bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
841*8bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
842*8bfffbccSCorey Minyard                           unsigned int max_rsp_len)
843*8bfffbccSCorey Minyard {
844*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
845*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
846*8bfffbccSCorey Minyard 
847*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
848*8bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
849*8bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
850*8bfffbccSCorey Minyard  out:
851*8bfffbccSCorey Minyard     return;
852*8bfffbccSCorey Minyard }
853*8bfffbccSCorey Minyard 
854*8bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
855*8bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
856*8bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
857*8bfffbccSCorey Minyard                           unsigned int max_rsp_len)
858*8bfffbccSCorey Minyard {
859*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->msg_flags);
860*8bfffbccSCorey Minyard  out:
861*8bfffbccSCorey Minyard     return;
862*8bfffbccSCorey Minyard }
863*8bfffbccSCorey Minyard 
864*8bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
865*8bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
866*8bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
867*8bfffbccSCorey Minyard                             unsigned int max_rsp_len)
868*8bfffbccSCorey Minyard {
869*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
870*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
871*8bfffbccSCorey Minyard     unsigned int i;
872*8bfffbccSCorey Minyard 
873*8bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
874*8bfffbccSCorey Minyard         rsp[2] = 0x80;
875*8bfffbccSCorey Minyard         goto out;
876*8bfffbccSCorey Minyard     }
877*8bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
878*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
879*8bfffbccSCorey Minyard     }
880*8bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
881*8bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
882*8bfffbccSCorey Minyard  out:
883*8bfffbccSCorey Minyard     return;
884*8bfffbccSCorey Minyard }
885*8bfffbccSCorey Minyard 
886*8bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
887*8bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
888*8bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
889*8bfffbccSCorey Minyard                     unsigned int max_rsp_len)
890*8bfffbccSCorey Minyard {
891*8bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
892*8bfffbccSCorey Minyard 
893*8bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
894*8bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
895*8bfffbccSCorey Minyard         rsp[2] = 0x80; /* Queue empty */
896*8bfffbccSCorey Minyard         goto out;
897*8bfffbccSCorey Minyard     }
898*8bfffbccSCorey Minyard     rsp[3] = 0; /* Channel 0 */
899*8bfffbccSCorey Minyard     *rsp_len += 1;
900*8bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
901*8bfffbccSCorey Minyard     memcpy(rsp + 4, msg->buf, msg->len);
902*8bfffbccSCorey Minyard     *rsp_len += msg->len;
903*8bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
904*8bfffbccSCorey Minyard     g_free(msg);
905*8bfffbccSCorey Minyard 
906*8bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
907*8bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
908*8bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
909*8bfffbccSCorey Minyard 
910*8bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
911*8bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
912*8bfffbccSCorey Minyard     }
913*8bfffbccSCorey Minyard 
914*8bfffbccSCorey Minyard  out:
915*8bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
916*8bfffbccSCorey Minyard     return;
917*8bfffbccSCorey Minyard }
918*8bfffbccSCorey Minyard 
919*8bfffbccSCorey Minyard static unsigned char
920*8bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
921*8bfffbccSCorey Minyard {
922*8bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
923*8bfffbccSCorey Minyard             csum += *data;
924*8bfffbccSCorey Minyard     }
925*8bfffbccSCorey Minyard 
926*8bfffbccSCorey Minyard     return -csum;
927*8bfffbccSCorey Minyard }
928*8bfffbccSCorey Minyard 
929*8bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
930*8bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
931*8bfffbccSCorey Minyard                      uint8_t *rsp, unsigned int *rsp_len,
932*8bfffbccSCorey Minyard                      unsigned int max_rsp_len)
933*8bfffbccSCorey Minyard {
934*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
935*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
936*8bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
937*8bfffbccSCorey Minyard     uint8_t *buf;
938*8bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
939*8bfffbccSCorey Minyard 
940*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
941*8bfffbccSCorey Minyard 
942*8bfffbccSCorey Minyard     if (cmd[2] != 0) {
943*8bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
944*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
945*8bfffbccSCorey Minyard         goto out;
946*8bfffbccSCorey Minyard     }
947*8bfffbccSCorey Minyard 
948*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(10);
949*8bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
950*8bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
951*8bfffbccSCorey Minyard         rsp[2] = 0x83; /* NAK on write */
952*8bfffbccSCorey Minyard         goto out;
953*8bfffbccSCorey Minyard     }
954*8bfffbccSCorey Minyard 
955*8bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
956*8bfffbccSCorey Minyard     cmd_len -= 3;
957*8bfffbccSCorey Minyard 
958*8bfffbccSCorey Minyard     /*
959*8bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
960*8bfffbccSCorey Minyard      * be returned in the response.
961*8bfffbccSCorey Minyard      */
962*8bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
963*8bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
964*8bfffbccSCorey Minyard         goto out; /* No response */
965*8bfffbccSCorey Minyard     }
966*8bfffbccSCorey Minyard 
967*8bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
968*8bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
969*8bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
970*8bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
971*8bfffbccSCorey Minyard 
972*8bfffbccSCorey Minyard     if (rqLun != 2) {
973*8bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
974*8bfffbccSCorey Minyard         goto out;
975*8bfffbccSCorey Minyard     }
976*8bfffbccSCorey Minyard 
977*8bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
978*8bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
979*8bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
980*8bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
981*8bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
982*8bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
983*8bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
984*8bfffbccSCorey Minyard     msg->len = 6;
985*8bfffbccSCorey Minyard 
986*8bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
987*8bfffbccSCorey Minyard         /* Not a command we handle. */
988*8bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
989*8bfffbccSCorey Minyard         goto end_msg;
990*8bfffbccSCorey Minyard     }
991*8bfffbccSCorey Minyard 
992*8bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
993*8bfffbccSCorey Minyard     buf[0] = 0;
994*8bfffbccSCorey Minyard     buf[1] = 0;
995*8bfffbccSCorey Minyard     buf[2] = 0;
996*8bfffbccSCorey Minyard     buf[3] = 0;
997*8bfffbccSCorey Minyard     buf[4] = 0x51;
998*8bfffbccSCorey Minyard     buf[5] = 0;
999*8bfffbccSCorey Minyard     buf[6] = 0;
1000*8bfffbccSCorey Minyard     buf[7] = 0;
1001*8bfffbccSCorey Minyard     buf[8] = 0;
1002*8bfffbccSCorey Minyard     buf[9] = 0;
1003*8bfffbccSCorey Minyard     buf[10] = 0;
1004*8bfffbccSCorey Minyard     msg->len += 11;
1005*8bfffbccSCorey Minyard 
1006*8bfffbccSCorey Minyard  end_msg:
1007*8bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
1008*8bfffbccSCorey Minyard     msg->len++;
1009*8bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
1010*8bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
1011*8bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
1012*8bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
1013*8bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
1014*8bfffbccSCorey Minyard 
1015*8bfffbccSCorey Minyard  out:
1016*8bfffbccSCorey Minyard     return;
1017*8bfffbccSCorey Minyard }
1018*8bfffbccSCorey Minyard 
1019*8bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
1020*8bfffbccSCorey Minyard {
1021*8bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
1022*8bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
1023*8bfffbccSCorey Minyard         ibs->watchdog_running = 0;
1024*8bfffbccSCorey Minyard         return;
1025*8bfffbccSCorey Minyard     }
1026*8bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
1027*8bfffbccSCorey Minyard 
1028*8bfffbccSCorey Minyard 
1029*8bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
1030*8bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
1031*8bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
1032*8bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
1033*8bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
1034*8bfffbccSCorey Minyard     }
1035*8bfffbccSCorey Minyard     ibs->watchdog_running = 1;
1036*8bfffbccSCorey Minyard }
1037*8bfffbccSCorey Minyard 
1038*8bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
1039*8bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1040*8bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
1041*8bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
1042*8bfffbccSCorey Minyard {
1043*8bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
1044*8bfffbccSCorey Minyard         rsp[2] = 0x80;
1045*8bfffbccSCorey Minyard         goto out;
1046*8bfffbccSCorey Minyard     }
1047*8bfffbccSCorey Minyard     do_watchdog_reset(ibs);
1048*8bfffbccSCorey Minyard  out:
1049*8bfffbccSCorey Minyard     return;
1050*8bfffbccSCorey Minyard }
1051*8bfffbccSCorey Minyard 
1052*8bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
1053*8bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1054*8bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
1055*8bfffbccSCorey Minyard                                unsigned int max_rsp_len)
1056*8bfffbccSCorey Minyard {
1057*8bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
1058*8bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
1059*8bfffbccSCorey Minyard     unsigned int val;
1060*8bfffbccSCorey Minyard 
1061*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
1062*8bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
1063*8bfffbccSCorey Minyard     if (val == 0 || val > 5) {
1064*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1065*8bfffbccSCorey Minyard         goto out;
1066*8bfffbccSCorey Minyard     }
1067*8bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
1068*8bfffbccSCorey Minyard     switch (val) {
1069*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
1070*8bfffbccSCorey Minyard         break;
1071*8bfffbccSCorey Minyard 
1072*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
1073*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
1074*8bfffbccSCorey Minyard         break;
1075*8bfffbccSCorey Minyard 
1076*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
1077*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
1078*8bfffbccSCorey Minyard         break;
1079*8bfffbccSCorey Minyard 
1080*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
1081*8bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
1082*8bfffbccSCorey Minyard         break;
1083*8bfffbccSCorey Minyard 
1084*8bfffbccSCorey Minyard     default:
1085*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1086*8bfffbccSCorey Minyard     }
1087*8bfffbccSCorey Minyard     if (rsp[2]) {
1088*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1089*8bfffbccSCorey Minyard         goto out;
1090*8bfffbccSCorey Minyard     }
1091*8bfffbccSCorey Minyard 
1092*8bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
1093*8bfffbccSCorey Minyard     switch (val) {
1094*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
1095*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
1096*8bfffbccSCorey Minyard         break;
1097*8bfffbccSCorey Minyard 
1098*8bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
1099*8bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
1100*8bfffbccSCorey Minyard             /* NMI not supported. */
1101*8bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1102*8bfffbccSCorey Minyard             goto out;
1103*8bfffbccSCorey Minyard         }
1104*8bfffbccSCorey Minyard     default:
1105*8bfffbccSCorey Minyard         /* We don't support PRE_SMI */
1106*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1107*8bfffbccSCorey Minyard         goto out;
1108*8bfffbccSCorey Minyard     }
1109*8bfffbccSCorey Minyard 
1110*8bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
1111*8bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
1112*8bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
1113*8bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
1114*8bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
1115*8bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
1116*8bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
1117*8bfffbccSCorey Minyard         do_watchdog_reset(ibs);
1118*8bfffbccSCorey Minyard     } else {
1119*8bfffbccSCorey Minyard         ibs->watchdog_running = 0;
1120*8bfffbccSCorey Minyard     }
1121*8bfffbccSCorey Minyard  out:
1122*8bfffbccSCorey Minyard     return;
1123*8bfffbccSCorey Minyard }
1124*8bfffbccSCorey Minyard 
1125*8bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
1126*8bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1127*8bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
1128*8bfffbccSCorey Minyard                                unsigned int max_rsp_len)
1129*8bfffbccSCorey Minyard {
1130*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_use);
1131*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_action);
1132*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout);
1133*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_expired);
1134*8bfffbccSCorey Minyard     if (ibs->watchdog_running) {
1135*8bfffbccSCorey Minyard         long timeout;
1136*8bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
1137*8bfffbccSCorey Minyard                    / 100000000);
1138*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(timeout & 0xff);
1139*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff);
1140*8bfffbccSCorey Minyard     } else {
1141*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
1142*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
1143*8bfffbccSCorey Minyard     }
1144*8bfffbccSCorey Minyard  out:
1145*8bfffbccSCorey Minyard     return;
1146*8bfffbccSCorey Minyard }
1147*8bfffbccSCorey Minyard 
1148*8bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
1149*8bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1150*8bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
1151*8bfffbccSCorey Minyard                              unsigned int max_rsp_len)
1152*8bfffbccSCorey Minyard {
1153*8bfffbccSCorey Minyard     unsigned int i;
1154*8bfffbccSCorey Minyard 
1155*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */
1156*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff);
1157*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff);
1158*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1159*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
1160*8bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1161*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]);
1162*8bfffbccSCorey Minyard     }
1163*8bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1164*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]);
1165*8bfffbccSCorey Minyard     }
1166*8bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1167*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
1168*8bfffbccSCorey Minyard  out:
1169*8bfffbccSCorey Minyard     return;
1170*8bfffbccSCorey Minyard }
1171*8bfffbccSCorey Minyard 
1172*8bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
1173*8bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1174*8bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
1175*8bfffbccSCorey Minyard                             unsigned int max_rsp_len)
1176*8bfffbccSCorey Minyard {
1177*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
1178*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
1179*8bfffbccSCorey Minyard  out:
1180*8bfffbccSCorey Minyard     return;
1181*8bfffbccSCorey Minyard }
1182*8bfffbccSCorey Minyard 
1183*8bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
1184*8bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1185*8bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
1186*8bfffbccSCorey Minyard                     unsigned int max_rsp_len)
1187*8bfffbccSCorey Minyard {
1188*8bfffbccSCorey Minyard     unsigned int pos;
1189*8bfffbccSCorey Minyard     uint16_t nextrec;
1190*8bfffbccSCorey Minyard 
1191*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
1192*8bfffbccSCorey Minyard     if (cmd[6]) {
1193*8bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
1194*8bfffbccSCorey Minyard     }
1195*8bfffbccSCorey Minyard     pos = 0;
1196*8bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
1197*8bfffbccSCorey Minyard                        &pos, &nextrec)) {
1198*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1199*8bfffbccSCorey Minyard         goto out;
1200*8bfffbccSCorey Minyard     }
1201*8bfffbccSCorey Minyard     if (cmd[6] > (ibs->sdr.sdr[pos + 4])) {
1202*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1203*8bfffbccSCorey Minyard         goto out;
1204*8bfffbccSCorey Minyard     }
1205*8bfffbccSCorey Minyard 
1206*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(nextrec & 0xff);
1207*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
1208*8bfffbccSCorey Minyard 
1209*8bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1210*8bfffbccSCorey Minyard         cmd[7] = ibs->sdr.sdr[pos + 4] - cmd[6];
1211*8bfffbccSCorey Minyard     }
1212*8bfffbccSCorey Minyard 
1213*8bfffbccSCorey Minyard     if ((cmd[7] + *rsp_len) > max_rsp_len) {
1214*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1215*8bfffbccSCorey Minyard         goto out;
1216*8bfffbccSCorey Minyard     }
1217*8bfffbccSCorey Minyard     memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
1218*8bfffbccSCorey Minyard     *rsp_len += cmd[7];
1219*8bfffbccSCorey Minyard  out:
1220*8bfffbccSCorey Minyard     return;
1221*8bfffbccSCorey Minyard }
1222*8bfffbccSCorey Minyard 
1223*8bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
1224*8bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1225*8bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
1226*8bfffbccSCorey Minyard                     unsigned int max_rsp_len)
1227*8bfffbccSCorey Minyard {
1228*8bfffbccSCorey Minyard     uint16_t recid;
1229*8bfffbccSCorey Minyard 
1230*8bfffbccSCorey Minyard     if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) {
1231*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1232*8bfffbccSCorey Minyard         goto out;
1233*8bfffbccSCorey Minyard     }
1234*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(recid & 0xff);
1235*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
1236*8bfffbccSCorey Minyard  out:
1237*8bfffbccSCorey Minyard     return;
1238*8bfffbccSCorey Minyard }
1239*8bfffbccSCorey Minyard 
1240*8bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
1241*8bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1242*8bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
1243*8bfffbccSCorey Minyard                           unsigned int max_rsp_len)
1244*8bfffbccSCorey Minyard {
1245*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
1246*8bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
1247*8bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1248*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1249*8bfffbccSCorey Minyard         goto out;
1250*8bfffbccSCorey Minyard     }
1251*8bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
1252*8bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
1253*8bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
1254*8bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1255*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1256*8bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
1257*8bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1258*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1259*8bfffbccSCorey Minyard     } else {
1260*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1261*8bfffbccSCorey Minyard         goto out;
1262*8bfffbccSCorey Minyard     }
1263*8bfffbccSCorey Minyard  out:
1264*8bfffbccSCorey Minyard     return;
1265*8bfffbccSCorey Minyard }
1266*8bfffbccSCorey Minyard 
1267*8bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
1268*8bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1269*8bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
1270*8bfffbccSCorey Minyard                          unsigned int max_rsp_len)
1271*8bfffbccSCorey Minyard {
1272*8bfffbccSCorey Minyard     unsigned int i, val;
1273*8bfffbccSCorey Minyard 
1274*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */
1275*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff);
1276*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff);
1277*8bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1278*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
1279*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
1280*8bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1281*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]);
1282*8bfffbccSCorey Minyard     }
1283*8bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1284*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]);
1285*8bfffbccSCorey Minyard     }
1286*8bfffbccSCorey Minyard     /* Only support Reserve SEL */
1287*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
1288*8bfffbccSCorey Minyard  out:
1289*8bfffbccSCorey Minyard     return;
1290*8bfffbccSCorey Minyard }
1291*8bfffbccSCorey Minyard 
1292*8bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
1293*8bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1294*8bfffbccSCorey Minyard                         uint8_t *rsp, unsigned int *rsp_len,
1295*8bfffbccSCorey Minyard                         unsigned int max_rsp_len)
1296*8bfffbccSCorey Minyard {
1297*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
1298*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
1299*8bfffbccSCorey Minyard  out:
1300*8bfffbccSCorey Minyard     return;
1301*8bfffbccSCorey Minyard }
1302*8bfffbccSCorey Minyard 
1303*8bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
1304*8bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1305*8bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
1306*8bfffbccSCorey Minyard                           unsigned int max_rsp_len)
1307*8bfffbccSCorey Minyard {
1308*8bfffbccSCorey Minyard     unsigned int val;
1309*8bfffbccSCorey Minyard 
1310*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
1311*8bfffbccSCorey Minyard     if (cmd[6]) {
1312*8bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
1313*8bfffbccSCorey Minyard     }
1314*8bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
1315*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1316*8bfffbccSCorey Minyard         goto out;
1317*8bfffbccSCorey Minyard     }
1318*8bfffbccSCorey Minyard     if (cmd[6] > 15) {
1319*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1320*8bfffbccSCorey Minyard         goto out;
1321*8bfffbccSCorey Minyard     }
1322*8bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1323*8bfffbccSCorey Minyard         cmd[7] = 16;
1324*8bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
1325*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1326*8bfffbccSCorey Minyard         goto out;
1327*8bfffbccSCorey Minyard     } else {
1328*8bfffbccSCorey Minyard         cmd[7] += cmd[6];
1329*8bfffbccSCorey Minyard     }
1330*8bfffbccSCorey Minyard 
1331*8bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
1332*8bfffbccSCorey Minyard     if (val == 0xffff) {
1333*8bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
1334*8bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
1335*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1336*8bfffbccSCorey Minyard         goto out;
1337*8bfffbccSCorey Minyard     }
1338*8bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1339*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
1340*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
1341*8bfffbccSCorey Minyard     } else {
1342*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((val + 1) & 0xff);
1343*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff);
1344*8bfffbccSCorey Minyard     }
1345*8bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1346*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
1347*8bfffbccSCorey Minyard     }
1348*8bfffbccSCorey Minyard  out:
1349*8bfffbccSCorey Minyard     return;
1350*8bfffbccSCorey Minyard }
1351*8bfffbccSCorey Minyard 
1352*8bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
1353*8bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1354*8bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
1355*8bfffbccSCorey Minyard                           unsigned int max_rsp_len)
1356*8bfffbccSCorey Minyard {
1357*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(18);
1358*8bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
1359*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_OUT_OF_SPACE;
1360*8bfffbccSCorey Minyard         goto out;
1361*8bfffbccSCorey Minyard     }
1362*8bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1363*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[2]);
1364*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[3]);
1365*8bfffbccSCorey Minyard  out:
1366*8bfffbccSCorey Minyard     return;
1367*8bfffbccSCorey Minyard }
1368*8bfffbccSCorey Minyard 
1369*8bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
1370*8bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1371*8bfffbccSCorey Minyard                       uint8_t *rsp, unsigned int *rsp_len,
1372*8bfffbccSCorey Minyard                       unsigned int max_rsp_len)
1373*8bfffbccSCorey Minyard {
1374*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
1375*8bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
1376*8bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1377*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1378*8bfffbccSCorey Minyard         goto out;
1379*8bfffbccSCorey Minyard     }
1380*8bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
1381*8bfffbccSCorey Minyard         ibs->sel.next_free = 0;
1382*8bfffbccSCorey Minyard         ibs->sel.overflow = 0;
1383*8bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1384*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1385*8bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
1386*8bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1387*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
1388*8bfffbccSCorey Minyard     } else {
1389*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1390*8bfffbccSCorey Minyard         goto out;
1391*8bfffbccSCorey Minyard     }
1392*8bfffbccSCorey Minyard  out:
1393*8bfffbccSCorey Minyard     return;
1394*8bfffbccSCorey Minyard }
1395*8bfffbccSCorey Minyard 
1396*8bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
1397*8bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1398*8bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
1399*8bfffbccSCorey Minyard                          unsigned int max_rsp_len)
1400*8bfffbccSCorey Minyard {
1401*8bfffbccSCorey Minyard     uint32_t val;
1402*8bfffbccSCorey Minyard     struct ipmi_time now;
1403*8bfffbccSCorey Minyard 
1404*8bfffbccSCorey Minyard     ipmi_gettime(&now);
1405*8bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1406*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
1407*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
1408*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
1409*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
1410*8bfffbccSCorey Minyard  out:
1411*8bfffbccSCorey Minyard     return;
1412*8bfffbccSCorey Minyard }
1413*8bfffbccSCorey Minyard 
1414*8bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
1415*8bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1416*8bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
1417*8bfffbccSCorey Minyard                          unsigned int max_rsp_len)
1418*8bfffbccSCorey Minyard {
1419*8bfffbccSCorey Minyard     uint32_t val;
1420*8bfffbccSCorey Minyard     struct ipmi_time now;
1421*8bfffbccSCorey Minyard 
1422*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(6);
1423*8bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
1424*8bfffbccSCorey Minyard     ipmi_gettime(&now);
1425*8bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
1426*8bfffbccSCorey Minyard  out:
1427*8bfffbccSCorey Minyard     return;
1428*8bfffbccSCorey Minyard }
1429*8bfffbccSCorey Minyard 
1430*8bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
1431*8bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1432*8bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
1433*8bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
1434*8bfffbccSCorey Minyard {
1435*8bfffbccSCorey Minyard     IPMISensor *sens;
1436*8bfffbccSCorey Minyard 
1437*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
1438*8bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
1439*8bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1440*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1441*8bfffbccSCorey Minyard         goto out;
1442*8bfffbccSCorey Minyard     }
1443*8bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1444*8bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
1445*8bfffbccSCorey Minyard     case 0: /* Do not change */
1446*8bfffbccSCorey Minyard         break;
1447*8bfffbccSCorey Minyard     case 1: /* Enable bits */
1448*8bfffbccSCorey Minyard         if (cmd_len > 4) {
1449*8bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
1450*8bfffbccSCorey Minyard         }
1451*8bfffbccSCorey Minyard         if (cmd_len > 5) {
1452*8bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
1453*8bfffbccSCorey Minyard         }
1454*8bfffbccSCorey Minyard         if (cmd_len > 6) {
1455*8bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
1456*8bfffbccSCorey Minyard         }
1457*8bfffbccSCorey Minyard         if (cmd_len > 7) {
1458*8bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
1459*8bfffbccSCorey Minyard         }
1460*8bfffbccSCorey Minyard         break;
1461*8bfffbccSCorey Minyard     case 2: /* Disable bits */
1462*8bfffbccSCorey Minyard         if (cmd_len > 4) {
1463*8bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
1464*8bfffbccSCorey Minyard         }
1465*8bfffbccSCorey Minyard         if (cmd_len > 5) {
1466*8bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
1467*8bfffbccSCorey Minyard         }
1468*8bfffbccSCorey Minyard         if (cmd_len > 6) {
1469*8bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
1470*8bfffbccSCorey Minyard         }
1471*8bfffbccSCorey Minyard         if (cmd_len > 7) {
1472*8bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
1473*8bfffbccSCorey Minyard         }
1474*8bfffbccSCorey Minyard         break;
1475*8bfffbccSCorey Minyard     case 3:
1476*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1477*8bfffbccSCorey Minyard         goto out;
1478*8bfffbccSCorey Minyard     }
1479*8bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
1480*8bfffbccSCorey Minyard  out:
1481*8bfffbccSCorey Minyard     return;
1482*8bfffbccSCorey Minyard }
1483*8bfffbccSCorey Minyard 
1484*8bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
1485*8bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1486*8bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
1487*8bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
1488*8bfffbccSCorey Minyard {
1489*8bfffbccSCorey Minyard     IPMISensor *sens;
1490*8bfffbccSCorey Minyard 
1491*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
1492*8bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
1493*8bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1494*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1495*8bfffbccSCorey Minyard         goto out;
1496*8bfffbccSCorey Minyard     }
1497*8bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1498*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
1499*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff);
1500*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
1501*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
1502*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
1503*8bfffbccSCorey Minyard  out:
1504*8bfffbccSCorey Minyard     return;
1505*8bfffbccSCorey Minyard }
1506*8bfffbccSCorey Minyard 
1507*8bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
1508*8bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1509*8bfffbccSCorey Minyard                               uint8_t *rsp, unsigned int *rsp_len,
1510*8bfffbccSCorey Minyard                               unsigned int max_rsp_len)
1511*8bfffbccSCorey Minyard {
1512*8bfffbccSCorey Minyard     IPMISensor *sens;
1513*8bfffbccSCorey Minyard 
1514*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
1515*8bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
1516*8bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1517*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1518*8bfffbccSCorey Minyard         goto out;
1519*8bfffbccSCorey Minyard     }
1520*8bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1521*8bfffbccSCorey Minyard 
1522*8bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
1523*8bfffbccSCorey Minyard         /* Just clear everything */
1524*8bfffbccSCorey Minyard         sens->states = 0;
1525*8bfffbccSCorey Minyard         goto out;
1526*8bfffbccSCorey Minyard     }
1527*8bfffbccSCorey Minyard  out:
1528*8bfffbccSCorey Minyard     return;
1529*8bfffbccSCorey Minyard }
1530*8bfffbccSCorey Minyard 
1531*8bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
1532*8bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1533*8bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
1534*8bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
1535*8bfffbccSCorey Minyard {
1536*8bfffbccSCorey Minyard     IPMISensor *sens;
1537*8bfffbccSCorey Minyard 
1538*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
1539*8bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
1540*8bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1541*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1542*8bfffbccSCorey Minyard         goto out;
1543*8bfffbccSCorey Minyard     }
1544*8bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1545*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
1546*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
1547*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_states & 0xff);
1548*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
1549*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
1550*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
1551*8bfffbccSCorey Minyard  out:
1552*8bfffbccSCorey Minyard     return;
1553*8bfffbccSCorey Minyard }
1554*8bfffbccSCorey Minyard 
1555*8bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
1556*8bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1557*8bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
1558*8bfffbccSCorey Minyard                                unsigned int max_rsp_len)
1559*8bfffbccSCorey Minyard {
1560*8bfffbccSCorey Minyard     IPMISensor *sens;
1561*8bfffbccSCorey Minyard 
1562*8bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
1563*8bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
1564*8bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1565*8bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1566*8bfffbccSCorey Minyard         goto out;
1567*8bfffbccSCorey Minyard     }
1568*8bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1569*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
1570*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
1571*8bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->states & 0xff);
1572*8bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1573*8bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
1574*8bfffbccSCorey Minyard     }
1575*8bfffbccSCorey Minyard  out:
1576*8bfffbccSCorey Minyard     return;
1577*8bfffbccSCorey Minyard }
1578*8bfffbccSCorey Minyard 
1579*8bfffbccSCorey Minyard static const IPMICmdHandler chassis_cmds[IPMI_NETFN_CHASSIS_MAXCMD] = {
1580*8bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
1581*8bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
1582*8bfffbccSCorey Minyard     [IPMI_CMD_CHASSIS_CONTROL] = chassis_control
1583*8bfffbccSCorey Minyard };
1584*8bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
1585*8bfffbccSCorey Minyard     .cmd_nums = IPMI_NETFN_CHASSIS_MAXCMD,
1586*8bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
1587*8bfffbccSCorey Minyard };
1588*8bfffbccSCorey Minyard 
1589*8bfffbccSCorey Minyard static const IPMICmdHandler
1590*8bfffbccSCorey Minyard sensor_event_cmds[IPMI_NETFN_SENSOR_EVENT_MAXCMD] = {
1591*8bfffbccSCorey Minyard     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
1592*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
1593*8bfffbccSCorey Minyard     [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
1594*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
1595*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading
1596*8bfffbccSCorey Minyard };
1597*8bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
1598*8bfffbccSCorey Minyard     .cmd_nums = IPMI_NETFN_SENSOR_EVENT_MAXCMD,
1599*8bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
1600*8bfffbccSCorey Minyard };
1601*8bfffbccSCorey Minyard 
1602*8bfffbccSCorey Minyard static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = {
1603*8bfffbccSCorey Minyard     [IPMI_CMD_GET_DEVICE_ID] = get_device_id,
1604*8bfffbccSCorey Minyard     [IPMI_CMD_COLD_RESET] = cold_reset,
1605*8bfffbccSCorey Minyard     [IPMI_CMD_WARM_RESET] = warm_reset,
1606*8bfffbccSCorey Minyard     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
1607*8bfffbccSCorey Minyard     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
1608*8bfffbccSCorey Minyard     [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
1609*8bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags,
1610*8bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG] = get_msg,
1611*8bfffbccSCorey Minyard     [IPMI_CMD_SEND_MSG] = send_msg,
1612*8bfffbccSCorey Minyard     [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf,
1613*8bfffbccSCorey Minyard     [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer,
1614*8bfffbccSCorey Minyard     [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer,
1615*8bfffbccSCorey Minyard     [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
1616*8bfffbccSCorey Minyard };
1617*8bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
1618*8bfffbccSCorey Minyard     .cmd_nums = IPMI_NETFN_APP_MAXCMD,
1619*8bfffbccSCorey Minyard     .cmd_handlers = app_cmds
1620*8bfffbccSCorey Minyard };
1621*8bfffbccSCorey Minyard 
1622*8bfffbccSCorey Minyard static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = {
1623*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
1624*8bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
1625*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR] = get_sdr,
1626*8bfffbccSCorey Minyard     [IPMI_CMD_ADD_SDR] = add_sdr,
1627*8bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep,
1628*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_INFO] = get_sel_info,
1629*8bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SEL] = reserve_sel,
1630*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry,
1631*8bfffbccSCorey Minyard     [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry,
1632*8bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SEL] = clear_sel,
1633*8bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = get_sel_time,
1634*8bfffbccSCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = set_sel_time,
1635*8bfffbccSCorey Minyard };
1636*8bfffbccSCorey Minyard 
1637*8bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
1638*8bfffbccSCorey Minyard     .cmd_nums = IPMI_NETFN_STORAGE_MAXCMD,
1639*8bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
1640*8bfffbccSCorey Minyard };
1641*8bfffbccSCorey Minyard 
1642*8bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
1643*8bfffbccSCorey Minyard {
1644*8bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
1645*8bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
1646*8bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
1647*8bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
1648*8bfffbccSCorey Minyard }
1649*8bfffbccSCorey Minyard 
1650*8bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
1651*8bfffbccSCorey Minyard     /* Watchdog device */
1652*8bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
1653*8bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
1654*8bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1655*8bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
1656*8bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
1657*8bfffbccSCorey Minyard     /* End */
1658*8bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
1659*8bfffbccSCorey Minyard };
1660*8bfffbccSCorey Minyard 
1661*8bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj)
1662*8bfffbccSCorey Minyard {
1663*8bfffbccSCorey Minyard     IPMIBmc *b = IPMI_BMC(obj);
1664*8bfffbccSCorey Minyard     unsigned int i;
1665*8bfffbccSCorey Minyard     unsigned int recid;
1666*8bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
1667*8bfffbccSCorey Minyard 
1668*8bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
1669*8bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
1670*8bfffbccSCorey Minyard 
1671*8bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
1672*8bfffbccSCorey Minyard     ibs->device_id = 0x20;
1673*8bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1674*8bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1675*8bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
1676*8bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
1677*8bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
1678*8bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
1679*8bfffbccSCorey Minyard     }
1680*8bfffbccSCorey Minyard 
1681*8bfffbccSCorey Minyard     for (i = 0;;) {
1682*8bfffbccSCorey Minyard         int len;
1683*8bfffbccSCorey Minyard         if ((i + 5) > sizeof(init_sdrs)) {
1684*8bfffbccSCorey Minyard             error_report("Problem with recid 0x%4.4x: \n", i);
1685*8bfffbccSCorey Minyard             return;
1686*8bfffbccSCorey Minyard         }
1687*8bfffbccSCorey Minyard         len = init_sdrs[i + 4];
1688*8bfffbccSCorey Minyard         recid = init_sdrs[i] | (init_sdrs[i + 1] << 8);
1689*8bfffbccSCorey Minyard         if (recid == 0xffff) {
1690*8bfffbccSCorey Minyard             break;
1691*8bfffbccSCorey Minyard         }
1692*8bfffbccSCorey Minyard         if ((i + len + 5) > sizeof(init_sdrs)) {
1693*8bfffbccSCorey Minyard             error_report("Problem with recid 0x%4.4x\n", i);
1694*8bfffbccSCorey Minyard             return;
1695*8bfffbccSCorey Minyard         }
1696*8bfffbccSCorey Minyard         sdr_add_entry(ibs, init_sdrs + i, len, NULL);
1697*8bfffbccSCorey Minyard         i += len + 5;
1698*8bfffbccSCorey Minyard     }
1699*8bfffbccSCorey Minyard 
1700*8bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
1701*8bfffbccSCorey Minyard     register_cmds(ibs);
1702*8bfffbccSCorey Minyard 
1703*8bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1704*8bfffbccSCorey Minyard }
1705*8bfffbccSCorey Minyard 
1706*8bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
1707*8bfffbccSCorey Minyard {
1708*8bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
1709*8bfffbccSCorey Minyard 
1710*8bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
1711*8bfffbccSCorey Minyard }
1712*8bfffbccSCorey Minyard 
1713*8bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
1714*8bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
1715*8bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
1716*8bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
1717*8bfffbccSCorey Minyard     .instance_init = ipmi_sim_init,
1718*8bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
1719*8bfffbccSCorey Minyard };
1720*8bfffbccSCorey Minyard 
1721*8bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
1722*8bfffbccSCorey Minyard {
1723*8bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
1724*8bfffbccSCorey Minyard }
1725*8bfffbccSCorey Minyard 
1726*8bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1727