xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 7f996411ad3c41e064c1f14aaa48afda09242f5e)
18bfffbccSCorey Minyard /*
28bfffbccSCorey Minyard  * IPMI BMC emulation
38bfffbccSCorey Minyard  *
48bfffbccSCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
58bfffbccSCorey Minyard  *
68bfffbccSCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
78bfffbccSCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
88bfffbccSCorey Minyard  * in the Software without restriction, including without limitation the rights
98bfffbccSCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108bfffbccSCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
118bfffbccSCorey Minyard  * furnished to do so, subject to the following conditions:
128bfffbccSCorey Minyard  *
138bfffbccSCorey Minyard  * The above copyright notice and this permission notice shall be included in
148bfffbccSCorey Minyard  * all copies or substantial portions of the Software.
158bfffbccSCorey Minyard  *
168bfffbccSCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178bfffbccSCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188bfffbccSCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198bfffbccSCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208bfffbccSCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218bfffbccSCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228bfffbccSCorey Minyard  * THE SOFTWARE.
238bfffbccSCorey Minyard  */
248bfffbccSCorey Minyard 
250430891cSPeter Maydell #include "qemu/osdep.h"
2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h"
278bfffbccSCorey Minyard #include "qemu/timer.h"
288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
298bfffbccSCorey Minyard #include "qemu/error-report.h"
308bfffbccSCorey Minyard 
318bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
328bfffbccSCorey Minyard 
338bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
358bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
36b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
378bfffbccSCorey Minyard 
388bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
398bfffbccSCorey Minyard 
408bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
418bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
428bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
438bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
45728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
46728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
478bfffbccSCorey Minyard 
488bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
498bfffbccSCorey Minyard 
508bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
518bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
528bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
5352ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
5452ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
568bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
578bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
588bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
598bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
608bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
618bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
628bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
648bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
658bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
668bfffbccSCorey Minyard 
678bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
688bfffbccSCorey Minyard 
698bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
718bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
728bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
738bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
748bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
758bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
768bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
788bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
798bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
808bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
818bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
828bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
848bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
858bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
868bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
878bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
888bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
898bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
908bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
918bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
928bfffbccSCorey Minyard 
938bfffbccSCorey Minyard 
948bfffbccSCorey Minyard /* Same as a timespec struct. */
958bfffbccSCorey Minyard struct ipmi_time {
968bfffbccSCorey Minyard     long tv_sec;
978bfffbccSCorey Minyard     long tv_nsec;
988bfffbccSCorey Minyard };
998bfffbccSCorey Minyard 
1008bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1018bfffbccSCorey Minyard 
1028bfffbccSCorey Minyard typedef struct IPMISel {
1038bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1048bfffbccSCorey Minyard     unsigned int next_free;
1058bfffbccSCorey Minyard     long time_offset;
1068bfffbccSCorey Minyard     uint16_t reservation;
1078bfffbccSCorey Minyard     uint8_t last_addition[4];
1088bfffbccSCorey Minyard     uint8_t last_clear[4];
1098bfffbccSCorey Minyard     uint8_t overflow;
1108bfffbccSCorey Minyard } IPMISel;
1118bfffbccSCorey Minyard 
1128bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1138bfffbccSCorey Minyard 
1148bfffbccSCorey Minyard typedef struct IPMISdr {
1158bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1168bfffbccSCorey Minyard     unsigned int next_free;
1178bfffbccSCorey Minyard     uint16_t next_rec_id;
1188bfffbccSCorey Minyard     uint16_t reservation;
1198bfffbccSCorey Minyard     uint8_t last_addition[4];
1208bfffbccSCorey Minyard     uint8_t last_clear[4];
1218bfffbccSCorey Minyard     uint8_t overflow;
1228bfffbccSCorey Minyard } IPMISdr;
1238bfffbccSCorey Minyard 
1248bfffbccSCorey Minyard typedef struct IPMISensor {
1258bfffbccSCorey Minyard     uint8_t status;
1268bfffbccSCorey Minyard     uint8_t reading;
1278bfffbccSCorey Minyard     uint16_t states_suppt;
1288bfffbccSCorey Minyard     uint16_t assert_suppt;
1298bfffbccSCorey Minyard     uint16_t deassert_suppt;
1308bfffbccSCorey Minyard     uint16_t states;
1318bfffbccSCorey Minyard     uint16_t assert_states;
1328bfffbccSCorey Minyard     uint16_t deassert_states;
1338bfffbccSCorey Minyard     uint16_t assert_enable;
1348bfffbccSCorey Minyard     uint16_t deassert_enable;
1358bfffbccSCorey Minyard     uint8_t  sensor_type;
1368bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1378bfffbccSCorey Minyard } IPMISensor;
1388bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1398bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1408bfffbccSCorey Minyard                                              !!(v))
1418bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1428bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1438bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1448bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1458bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1468bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1478bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1488bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1498bfffbccSCorey Minyard                                              (v & 0xc0))
1508bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1518bfffbccSCorey Minyard 
1528bfffbccSCorey Minyard #define MAX_SENSORS 20
1538bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1548bfffbccSCorey Minyard 
1558bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
156a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer;
1578bfffbccSCorey Minyard 
1588bfffbccSCorey Minyard #define MAX_NETFNS 64
1594f298a4bSCédric Le Goater 
1604f298a4bSCédric Le Goater typedef struct IPMICmdHandler {
1614f298a4bSCédric Le Goater     void (*cmd_handler)(IPMIBmcSim *s,
1628bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
163a580d820SCédric Le Goater                         RspBuffer *rsp);
1644f298a4bSCédric Le Goater     unsigned int cmd_len_min;
1654f298a4bSCédric Le Goater } IPMICmdHandler;
1664f298a4bSCédric Le Goater 
1678bfffbccSCorey Minyard typedef struct IPMINetfn {
1688bfffbccSCorey Minyard     unsigned int cmd_nums;
1698bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1708bfffbccSCorey Minyard } IPMINetfn;
1718bfffbccSCorey Minyard 
1728bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1738bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1748bfffbccSCorey Minyard     uint8_t len;
1758bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1768bfffbccSCorey Minyard } IPMIRcvBufEntry;
1778bfffbccSCorey Minyard 
1788bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1798bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1808bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1818bfffbccSCorey Minyard struct IPMIBmcSim {
1828bfffbccSCorey Minyard     IPMIBmc parent;
1838bfffbccSCorey Minyard 
1848bfffbccSCorey Minyard     QEMUTimer *timer;
1858bfffbccSCorey Minyard 
1868bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1878bfffbccSCorey Minyard     uint8_t msg_flags;
1888bfffbccSCorey Minyard 
1898bfffbccSCorey Minyard     bool     watchdog_initialized;
1908bfffbccSCorey Minyard     uint8_t  watchdog_use;
1918bfffbccSCorey Minyard     uint8_t  watchdog_action;
1928bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1938bfffbccSCorey Minyard     bool     watchdog_expired;
1948bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1958bfffbccSCorey Minyard 
1968bfffbccSCorey Minyard     bool     watchdog_running;
1978bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1988bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1998bfffbccSCorey Minyard 
2008bfffbccSCorey Minyard     uint8_t device_id;
2018bfffbccSCorey Minyard     uint8_t ipmi_version;
2028bfffbccSCorey Minyard     uint8_t device_rev;
2038bfffbccSCorey Minyard     uint8_t fwrev1;
2048bfffbccSCorey Minyard     uint8_t fwrev2;
2058bfffbccSCorey Minyard     uint8_t mfg_id[3];
2068bfffbccSCorey Minyard     uint8_t product_id[2];
2078bfffbccSCorey Minyard 
208b7088392SCédric Le Goater     uint8_t restart_cause;
209b7088392SCédric Le Goater 
21052ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
21152ba4d50SCédric Le Goater     uint8_t uuid[16];
21252ba4d50SCédric Le Goater 
2138bfffbccSCorey Minyard     IPMISel sel;
2148bfffbccSCorey Minyard     IPMISdr sdr;
2158bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2168bfffbccSCorey Minyard 
2178bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2188bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2198bfffbccSCorey Minyard 
2208bfffbccSCorey Minyard     QemuMutex lock;
2218bfffbccSCorey Minyard     /* We allow one event in the buffer */
2228bfffbccSCorey Minyard     uint8_t evtbuf[16];
2238bfffbccSCorey Minyard 
2248bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2258bfffbccSCorey Minyard };
2268bfffbccSCorey Minyard 
2278bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2318bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2328bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2338bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2348bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2358bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2368bfffbccSCorey Minyard 
2378bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2388bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2398bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2428bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2438bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2448bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2458bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2468bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2478bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2488bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2498bfffbccSCorey Minyard 
2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2658bfffbccSCorey Minyard 
266a580d820SCédric Le Goater struct RspBuffer {
267a580d820SCédric Le Goater     uint8_t buffer[MAX_IPMI_MSG_SIZE];
268a580d820SCédric Le Goater     unsigned int len;
269a580d820SCédric Le Goater };
270a580d820SCédric Le Goater 
271a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2728bfffbccSCorey Minyard 
2738bfffbccSCorey Minyard /* Add a byte to the response. */
274a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
275a580d820SCédric Le Goater {
276a580d820SCédric Le Goater     if (rsp->len >= sizeof(rsp->buffer)) {
277a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
278a580d820SCédric Le Goater         return;
279a580d820SCédric Le Goater     }
280a580d820SCédric Le Goater     rsp->buffer[rsp->len++] = byte;
281a580d820SCédric Le Goater }
282a580d820SCédric Le Goater 
283a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
284a580d820SCédric Le Goater                                        unsigned int n)
285a580d820SCédric Le Goater {
286a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
287a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
288a580d820SCédric Le Goater         return;
289a580d820SCédric Le Goater     }
290a580d820SCédric Le Goater 
291a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
292a580d820SCédric Le Goater     rsp->len += n;
293a580d820SCédric Le Goater }
2948bfffbccSCorey Minyard 
2958bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2968bfffbccSCorey Minyard 
2978bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2988bfffbccSCorey Minyard {
2998bfffbccSCorey Minyard     int64_t stime;
3008bfffbccSCorey Minyard 
3018bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
3028bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
3038bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
3048bfffbccSCorey Minyard }
3058bfffbccSCorey Minyard 
3068bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3078bfffbccSCorey Minyard {
3088bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3098bfffbccSCorey Minyard }
3108bfffbccSCorey Minyard 
3118bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3128bfffbccSCorey Minyard {
3138bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3148bfffbccSCorey Minyard 
3158bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3168bfffbccSCorey Minyard }
3178bfffbccSCorey Minyard 
3188bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3198bfffbccSCorey Minyard {
3208bfffbccSCorey Minyard     unsigned int val;
3218bfffbccSCorey Minyard     struct ipmi_time now;
3228bfffbccSCorey Minyard 
3238bfffbccSCorey Minyard     ipmi_gettime(&now);
3248bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3258bfffbccSCorey Minyard     ts[0] = val & 0xff;
3268bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3278bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3288bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3298bfffbccSCorey Minyard }
3308bfffbccSCorey Minyard 
3318bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3328bfffbccSCorey Minyard {
3338bfffbccSCorey Minyard     sdr->reservation++;
3348bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3358bfffbccSCorey Minyard         sdr->reservation = 1;
3368bfffbccSCorey Minyard     }
3378bfffbccSCorey Minyard }
3388bfffbccSCorey Minyard 
339a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
340a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3418bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3428bfffbccSCorey Minyard {
343a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
344a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
345a2295f0aSCédric Le Goater 
346a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3478bfffbccSCorey Minyard         return 1;
3488bfffbccSCorey Minyard     }
3498bfffbccSCorey Minyard 
350a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3518bfffbccSCorey Minyard         return 1;
3528bfffbccSCorey Minyard     }
3538bfffbccSCorey Minyard 
3548bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3558bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3568bfffbccSCorey Minyard         return 1;
3578bfffbccSCorey Minyard     }
3588bfffbccSCorey Minyard 
359a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
360a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
361a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
362a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3638bfffbccSCorey Minyard 
3648bfffbccSCorey Minyard     if (recid) {
3658bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3668bfffbccSCorey Minyard     }
3678bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3688bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3698bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3708bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3718bfffbccSCorey Minyard     return 0;
3728bfffbccSCorey Minyard }
3738bfffbccSCorey Minyard 
3748bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3758bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3768bfffbccSCorey Minyard {
3778bfffbccSCorey Minyard     unsigned int pos = *retpos;
3788bfffbccSCorey Minyard 
3798bfffbccSCorey Minyard     while (pos < sdr->next_free) {
380a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
381a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
382a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
383a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3848bfffbccSCorey Minyard 
3858bfffbccSCorey Minyard         if (trec == recid) {
3868bfffbccSCorey Minyard             if (nextrec) {
3878bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3888bfffbccSCorey Minyard                     *nextrec = 0xffff;
3898bfffbccSCorey Minyard                 } else {
3908bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3918bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3928bfffbccSCorey Minyard                 }
3938bfffbccSCorey Minyard             }
3948bfffbccSCorey Minyard             *retpos = pos;
3958bfffbccSCorey Minyard             return 0;
3968bfffbccSCorey Minyard         }
3978bfffbccSCorey Minyard         pos = nextpos;
3988bfffbccSCorey Minyard     }
3998bfffbccSCorey Minyard     return 1;
4008bfffbccSCorey Minyard }
4018bfffbccSCorey Minyard 
4028bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4038bfffbccSCorey Minyard {
4048bfffbccSCorey Minyard     sel->reservation++;
4058bfffbccSCorey Minyard     if (sel->reservation == 0) {
4068bfffbccSCorey Minyard         sel->reservation = 1;
4078bfffbccSCorey Minyard     }
4088bfffbccSCorey Minyard }
4098bfffbccSCorey Minyard 
4108bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4118bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4128bfffbccSCorey Minyard {
4138bfffbccSCorey Minyard     event[0] = 0xff;
4148bfffbccSCorey Minyard     event[1] = 0xff;
4158bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
4168bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4178bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4188bfffbccSCorey Minyard         return 1;
4198bfffbccSCorey Minyard     }
4208bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4218bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4228bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4238bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4248bfffbccSCorey Minyard     ibs->sel.next_free++;
4258bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4268bfffbccSCorey Minyard     return 0;
4278bfffbccSCorey Minyard }
4288bfffbccSCorey Minyard 
4298bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4308bfffbccSCorey Minyard {
4318bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4328bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4338bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4348bfffbccSCorey Minyard }
4358bfffbccSCorey Minyard 
4368bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4378bfffbccSCorey Minyard {
4388bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4398bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4408bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4418bfffbccSCorey Minyard }
4428bfffbccSCorey Minyard 
4438bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4448bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4458bfffbccSCorey Minyard {
4468bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4478bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4488bfffbccSCorey Minyard     uint8_t evt[16];
4498bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4508bfffbccSCorey Minyard 
4518bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4528bfffbccSCorey Minyard         return;
4538bfffbccSCorey Minyard     }
4548bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4558bfffbccSCorey Minyard         return;
4568bfffbccSCorey Minyard     }
4578bfffbccSCorey Minyard 
4588bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4598bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4608bfffbccSCorey Minyard     evt[8] = 0;
4618bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4628bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4638bfffbccSCorey Minyard     evt[11] = sens_num;
4648bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4658bfffbccSCorey Minyard     evt[13] = evd1;
4668bfffbccSCorey Minyard     evt[14] = evd2;
4678bfffbccSCorey Minyard     evt[15] = evd3;
4688bfffbccSCorey Minyard 
4698bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4708bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4718bfffbccSCorey Minyard     }
4728bfffbccSCorey Minyard 
4738bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
474d13ada5dSCédric Le Goater         return;
4758bfffbccSCorey Minyard     }
4768bfffbccSCorey Minyard 
4778bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4788bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4798bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4808bfffbccSCorey Minyard }
4818bfffbccSCorey Minyard 
4828bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4838bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4848bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4858bfffbccSCorey Minyard {
4868bfffbccSCorey Minyard     IPMISensor *sens;
4878bfffbccSCorey Minyard     uint16_t mask;
4888bfffbccSCorey Minyard 
4898bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4908bfffbccSCorey Minyard         return;
4918bfffbccSCorey Minyard     }
4928bfffbccSCorey Minyard     if (bit >= 16) {
4938bfffbccSCorey Minyard         return;
4948bfffbccSCorey Minyard     }
4958bfffbccSCorey Minyard 
4968bfffbccSCorey Minyard     mask = (1 << bit);
4978bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
4988bfffbccSCorey Minyard     if (val) {
4998bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5008bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5018bfffbccSCorey Minyard             return; /* Already asserted */
5028bfffbccSCorey Minyard         }
5038bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5048bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5058bfffbccSCorey Minyard             /* Send an event on assert */
5068bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5078bfffbccSCorey Minyard         }
5088bfffbccSCorey Minyard     } else {
5098bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5108bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5118bfffbccSCorey Minyard             return; /* Already deasserted */
5128bfffbccSCorey Minyard         }
5138bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5148bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5158bfffbccSCorey Minyard             /* Send an event on deassert */
5168bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5178bfffbccSCorey Minyard         }
5188bfffbccSCorey Minyard     }
5198bfffbccSCorey Minyard }
5208bfffbccSCorey Minyard 
5218bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5228bfffbccSCorey Minyard {
5238bfffbccSCorey Minyard     unsigned int i, pos;
5248bfffbccSCorey Minyard     IPMISensor *sens;
5258bfffbccSCorey Minyard 
5268bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5278bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5288bfffbccSCorey Minyard     }
5298bfffbccSCorey Minyard 
5308bfffbccSCorey Minyard     pos = 0;
5318bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
532a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
533a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
534a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5358bfffbccSCorey Minyard 
5368bfffbccSCorey Minyard         if (len < 20) {
5378bfffbccSCorey Minyard             continue;
5388bfffbccSCorey Minyard         }
539a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5408bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5418bfffbccSCorey Minyard         }
5428bfffbccSCorey Minyard 
54373d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5448bfffbccSCorey Minyard             continue;
5458bfffbccSCorey Minyard         }
546a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5478bfffbccSCorey Minyard 
5488bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
549a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
550a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
551a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
552a2295f0aSCédric Le Goater         sens->deassert_suppt =
553a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
554a2295f0aSCédric Le Goater         sens->states_suppt =
555a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
556a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
557a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5588bfffbccSCorey Minyard 
5598bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5608bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5618bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5628bfffbccSCorey Minyard     }
5638bfffbccSCorey Minyard }
5648bfffbccSCorey Minyard 
5658bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5668bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5678bfffbccSCorey Minyard {
56893a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
5698bfffbccSCorey Minyard         return -1;
5708bfffbccSCorey Minyard     }
5718bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5728bfffbccSCorey Minyard     return 0;
5738bfffbccSCorey Minyard }
5748bfffbccSCorey Minyard 
5754f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
5764f298a4bSCédric Le Goater                                               unsigned int netfn,
5774f298a4bSCédric Le Goater                                               unsigned int cmd)
5784f298a4bSCédric Le Goater {
5794f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
5804f298a4bSCédric Le Goater 
5814f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
5824f298a4bSCédric Le Goater         return NULL;
5834f298a4bSCédric Le Goater     }
5844f298a4bSCédric Le Goater 
5854f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
5864f298a4bSCédric Le Goater         return NULL;
5874f298a4bSCédric Le Goater     }
5884f298a4bSCédric Le Goater 
5894f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
5904f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
5914f298a4bSCédric Le Goater         return NULL;
5924f298a4bSCédric Le Goater     }
5934f298a4bSCédric Le Goater 
5944f298a4bSCédric Le Goater     return hdl;
5954f298a4bSCédric Le Goater }
5964f298a4bSCédric Le Goater 
5978bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
5988bfffbccSCorey Minyard {
5998bfffbccSCorey Minyard     int64_t next;
6008bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6018bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6028bfffbccSCorey Minyard     } else {
6038bfffbccSCorey Minyard         /* Wait a minute */
6048bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6058bfffbccSCorey Minyard     }
6068bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6078bfffbccSCorey Minyard }
6088bfffbccSCorey Minyard 
6098bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6108bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6118bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6128bfffbccSCorey Minyard                                     uint8_t msg_id)
6138bfffbccSCorey Minyard {
6148bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6158bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6168bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6174f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
618a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6198bfffbccSCorey Minyard 
6208bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6218bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
622a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
623a580d820SCédric Le Goater         rsp.buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
624d13ada5dSCédric Le Goater         goto out;
625d13ada5dSCédric Le Goater     }
626d13ada5dSCédric Le Goater 
627a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
628a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
629a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6308bfffbccSCorey Minyard 
6318bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6328bfffbccSCorey Minyard     if (cmd_len < 2) {
633a580d820SCédric Le Goater         rsp.buffer[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
6348bfffbccSCorey Minyard         goto out;
6358bfffbccSCorey Minyard     }
6368bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
637a580d820SCédric Le Goater         rsp.buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
6388bfffbccSCorey Minyard         goto out;
6398bfffbccSCorey Minyard     }
6408bfffbccSCorey Minyard 
6418bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6428bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
643a580d820SCédric Le Goater         rsp.buffer[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
6448bfffbccSCorey Minyard         goto out;
6458bfffbccSCorey Minyard     }
6468bfffbccSCorey Minyard 
6474f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6484f298a4bSCédric Le Goater     if (!hdl) {
649a580d820SCédric Le Goater         rsp.buffer[2] = IPMI_CC_INVALID_CMD;
6508bfffbccSCorey Minyard         goto out;
6518bfffbccSCorey Minyard     }
6528bfffbccSCorey Minyard 
6534f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
654a580d820SCédric Le Goater         rsp.buffer[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
6554f298a4bSCédric Le Goater         goto out;
6564f298a4bSCédric Le Goater     }
6574f298a4bSCédric Le Goater 
658a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6598bfffbccSCorey Minyard 
6608bfffbccSCorey Minyard  out:
661a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6628bfffbccSCorey Minyard 
6638bfffbccSCorey Minyard     next_timeout(ibs);
6648bfffbccSCorey Minyard }
6658bfffbccSCorey Minyard 
6668bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6678bfffbccSCorey Minyard {
6688bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6698bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6708bfffbccSCorey Minyard 
6718bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6728bfffbccSCorey Minyard         goto out;
6738bfffbccSCorey Minyard     }
6748bfffbccSCorey Minyard 
6758bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6768bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6778bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6788bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6798bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6808bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6818bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6828bfffbccSCorey Minyard             break;
6838bfffbccSCorey Minyard 
6848bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6858bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6868bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6878bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6888bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6898bfffbccSCorey Minyard             break;
6908bfffbccSCorey Minyard 
6918bfffbccSCorey Minyard         default:
6928bfffbccSCorey Minyard             goto do_full_expiry;
6938bfffbccSCorey Minyard         }
6948bfffbccSCorey Minyard 
6958bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
6968bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
6978bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
6988bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
6998bfffbccSCorey Minyard         goto out;
7008bfffbccSCorey Minyard     }
7018bfffbccSCorey Minyard 
7028bfffbccSCorey Minyard  do_full_expiry:
7038bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7048bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7058bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7068bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7078bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7088bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7098bfffbccSCorey Minyard         break;
7108bfffbccSCorey Minyard 
7118bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7128bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7138bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7148bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7158bfffbccSCorey Minyard         break;
7168bfffbccSCorey Minyard 
7178bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7188bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7198bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7208bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7218bfffbccSCorey Minyard         break;
7228bfffbccSCorey Minyard 
7238bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7248bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7258bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7268bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7278bfffbccSCorey Minyard         break;
7288bfffbccSCorey Minyard     }
7298bfffbccSCorey Minyard 
7308bfffbccSCorey Minyard  out:
7318bfffbccSCorey Minyard     next_timeout(ibs);
7328bfffbccSCorey Minyard }
7338bfffbccSCorey Minyard 
7348bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7358bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
736a580d820SCédric Le Goater                                  RspBuffer *rsp)
7378bfffbccSCorey Minyard {
738a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
739a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
740a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
741a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
742a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
7438bfffbccSCorey Minyard }
7448bfffbccSCorey Minyard 
7458bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7468bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
747a580d820SCédric Le Goater                            RspBuffer *rsp)
7488bfffbccSCorey Minyard {
749a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
750a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
751a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
752a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7538bfffbccSCorey Minyard }
7548bfffbccSCorey Minyard 
7558bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7568bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
757a580d820SCédric Le Goater                             RspBuffer *rsp)
7588bfffbccSCorey Minyard {
7598bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7608bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7618bfffbccSCorey Minyard 
7628bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7638bfffbccSCorey Minyard     case 0: /* power down */
764a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7658bfffbccSCorey Minyard         break;
7668bfffbccSCorey Minyard     case 1: /* power up */
767a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
7688bfffbccSCorey Minyard         break;
7698bfffbccSCorey Minyard     case 2: /* power cycle */
770a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7718bfffbccSCorey Minyard         break;
7728bfffbccSCorey Minyard     case 3: /* hard reset */
773a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7748bfffbccSCorey Minyard         break;
7758bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
776a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
7778bfffbccSCorey Minyard         break;
7788bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
779a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s,
7808bfffbccSCorey Minyard                              IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
7818bfffbccSCorey Minyard         break;
7828bfffbccSCorey Minyard     default:
783a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
7848bfffbccSCorey Minyard         return;
7858bfffbccSCorey Minyard     }
786d13ada5dSCédric Le Goater }
7878bfffbccSCorey Minyard 
788b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
789b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
790a580d820SCédric Le Goater                            RspBuffer *rsp)
791a580d820SCédric Le Goater 
792b7088392SCédric Le Goater {
793a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
794a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
795b7088392SCédric Le Goater }
796b7088392SCédric Le Goater 
7978bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
7988bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
799a580d820SCédric Le Goater                           RspBuffer *rsp)
8008bfffbccSCorey Minyard {
801a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
802a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
803a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
804a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
805a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
806a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
807a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[0]);
808a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[1]);
809a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[2]);
810a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[0]);
811a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[1]);
8128bfffbccSCorey Minyard }
8138bfffbccSCorey Minyard 
8148bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8158bfffbccSCorey Minyard {
8168bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8178bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8188bfffbccSCorey Minyard     bool irqs_on;
8198bfffbccSCorey Minyard 
8208bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8218bfffbccSCorey Minyard 
8228bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8238bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8248bfffbccSCorey Minyard 
8258bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8268bfffbccSCorey Minyard }
8278bfffbccSCorey Minyard 
8288bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8298bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
830a580d820SCédric Le Goater                        RspBuffer *rsp)
8318bfffbccSCorey Minyard {
8328bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8338bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8348bfffbccSCorey Minyard 
8358bfffbccSCorey Minyard     /* Disable all interrupts */
8368bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8378bfffbccSCorey Minyard 
8388bfffbccSCorey Minyard     if (k->reset) {
8398bfffbccSCorey Minyard         k->reset(s, true);
8408bfffbccSCorey Minyard     }
8418bfffbccSCorey Minyard }
8428bfffbccSCorey Minyard 
8438bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8448bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
845a580d820SCédric Le Goater                        RspBuffer *rsp)
8468bfffbccSCorey Minyard {
8478bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8488bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8498bfffbccSCorey Minyard 
8508bfffbccSCorey Minyard     if (k->reset) {
8518bfffbccSCorey Minyard         k->reset(s, false);
8528bfffbccSCorey Minyard     }
8538bfffbccSCorey Minyard }
85452ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
85552ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
856a580d820SCédric Le Goater                                  RspBuffer *rsp)
85752ba4d50SCédric Le Goater {
85852ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
85952ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
86052ba4d50SCédric Le Goater }
86152ba4d50SCédric Le Goater 
86252ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
86352ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
864a580d820SCédric Le Goater                                  RspBuffer *rsp)
86552ba4d50SCédric Le Goater {
866a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
867a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
86852ba4d50SCédric Le Goater }
86952ba4d50SCédric Le Goater 
87052ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
87152ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
872a580d820SCédric Le Goater                             RspBuffer *rsp)
87352ba4d50SCédric Le Goater {
87452ba4d50SCédric Le Goater     unsigned int i;
87552ba4d50SCédric Le Goater 
87652ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
877a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->uuid[i]);
87852ba4d50SCédric Le Goater     }
87952ba4d50SCédric Le Goater }
8808bfffbccSCorey Minyard 
8818bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
8828bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
883a580d820SCédric Le Goater                                    RspBuffer *rsp)
8848bfffbccSCorey Minyard {
8858bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8868bfffbccSCorey Minyard }
8878bfffbccSCorey Minyard 
8888bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8898bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
890a580d820SCédric Le Goater                                    RspBuffer *rsp)
8918bfffbccSCorey Minyard {
892a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
8938bfffbccSCorey Minyard }
8948bfffbccSCorey Minyard 
8958bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
8968bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
897a580d820SCédric Le Goater                           RspBuffer *rsp)
8988bfffbccSCorey Minyard {
8998bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9008bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9018bfffbccSCorey Minyard 
9028bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9038bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9048bfffbccSCorey Minyard }
9058bfffbccSCorey Minyard 
9068bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9078bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
908a580d820SCédric Le Goater                           RspBuffer *rsp)
9098bfffbccSCorey Minyard {
910a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9118bfffbccSCorey Minyard }
9128bfffbccSCorey Minyard 
9138bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9148bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
915a580d820SCédric Le Goater                              RspBuffer *rsp)
9168bfffbccSCorey Minyard {
9178bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9188bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9198bfffbccSCorey Minyard     unsigned int i;
9208bfffbccSCorey Minyard 
9218bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
922a580d820SCédric Le Goater         rsp->buffer[2] = 0x80;
923d13ada5dSCédric Le Goater         return;
9248bfffbccSCorey Minyard     }
9258bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
926a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9278bfffbccSCorey Minyard     }
9288bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9298bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9308bfffbccSCorey Minyard }
9318bfffbccSCorey Minyard 
9328bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9338bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
934a580d820SCédric Le Goater                     RspBuffer *rsp)
9358bfffbccSCorey Minyard {
9368bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9378bfffbccSCorey Minyard 
9388bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
9398bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
940a580d820SCédric Le Goater         rsp->buffer[2] = 0x80; /* Queue empty */
9418bfffbccSCorey Minyard         goto out;
9428bfffbccSCorey Minyard     }
943a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
9448bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
945a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
9468bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9478bfffbccSCorey Minyard     g_free(msg);
9488bfffbccSCorey Minyard 
9498bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9508bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
9518bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9528bfffbccSCorey Minyard 
9538bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9548bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9558bfffbccSCorey Minyard     }
9568bfffbccSCorey Minyard 
9578bfffbccSCorey Minyard out:
9588bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
9598bfffbccSCorey Minyard     return;
9608bfffbccSCorey Minyard }
9618bfffbccSCorey Minyard 
9628bfffbccSCorey Minyard static unsigned char
9638bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9648bfffbccSCorey Minyard {
9658bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9668bfffbccSCorey Minyard             csum += *data;
9678bfffbccSCorey Minyard     }
9688bfffbccSCorey Minyard 
9698bfffbccSCorey Minyard     return -csum;
9708bfffbccSCorey Minyard }
9718bfffbccSCorey Minyard 
9728bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9738bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
974a580d820SCédric Le Goater                      RspBuffer *rsp)
9758bfffbccSCorey Minyard {
9768bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9778bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9788bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9798bfffbccSCorey Minyard     uint8_t *buf;
9808bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9818bfffbccSCorey Minyard 
9828bfffbccSCorey Minyard     if (cmd[2] != 0) {
9838bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
984a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
985d13ada5dSCédric Le Goater         return;
9868bfffbccSCorey Minyard     }
9878bfffbccSCorey Minyard 
9884f298a4bSCédric Le Goater     if (cmd_len < 10) {
989a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
9904f298a4bSCédric Le Goater         return;
9914f298a4bSCédric Le Goater     }
9924f298a4bSCédric Le Goater 
9938bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9948bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
995a580d820SCédric Le Goater         rsp->buffer[2] = 0x83; /* NAK on write */
996d13ada5dSCédric Le Goater         return;
9978bfffbccSCorey Minyard     }
9988bfffbccSCorey Minyard 
9998bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10008bfffbccSCorey Minyard     cmd_len -= 3;
10018bfffbccSCorey Minyard 
10028bfffbccSCorey Minyard     /*
10038bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10048bfffbccSCorey Minyard      * be returned in the response.
10058bfffbccSCorey Minyard      */
10068bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10078bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1008d13ada5dSCédric Le Goater         return; /* No response */
10098bfffbccSCorey Minyard     }
10108bfffbccSCorey Minyard 
10118bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10128bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10138bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10148bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10158bfffbccSCorey Minyard 
10168bfffbccSCorey Minyard     if (rqLun != 2) {
10178bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1018d13ada5dSCédric Le Goater         return;
10198bfffbccSCorey Minyard     }
10208bfffbccSCorey Minyard 
10218bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10228bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10238bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10248bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10258bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10268bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10278bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10288bfffbccSCorey Minyard     msg->len = 6;
10298bfffbccSCorey Minyard 
10308bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10318bfffbccSCorey Minyard         /* Not a command we handle. */
10328bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10338bfffbccSCorey Minyard         goto end_msg;
10348bfffbccSCorey Minyard     }
10358bfffbccSCorey Minyard 
10368bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10378bfffbccSCorey Minyard     buf[0] = 0;
10388bfffbccSCorey Minyard     buf[1] = 0;
10398bfffbccSCorey Minyard     buf[2] = 0;
10408bfffbccSCorey Minyard     buf[3] = 0;
10418bfffbccSCorey Minyard     buf[4] = 0x51;
10428bfffbccSCorey Minyard     buf[5] = 0;
10438bfffbccSCorey Minyard     buf[6] = 0;
10448bfffbccSCorey Minyard     buf[7] = 0;
10458bfffbccSCorey Minyard     buf[8] = 0;
10468bfffbccSCorey Minyard     buf[9] = 0;
10478bfffbccSCorey Minyard     buf[10] = 0;
10488bfffbccSCorey Minyard     msg->len += 11;
10498bfffbccSCorey Minyard 
10508bfffbccSCorey Minyard  end_msg:
10518bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10528bfffbccSCorey Minyard     msg->len++;
10538bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
10548bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10558bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10568bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10578bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
10588bfffbccSCorey Minyard }
10598bfffbccSCorey Minyard 
10608bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
10618bfffbccSCorey Minyard {
10628bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
10638bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
10648bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10658bfffbccSCorey Minyard         return;
10668bfffbccSCorey Minyard     }
10678bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10688bfffbccSCorey Minyard 
10698bfffbccSCorey Minyard 
10708bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10718bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10728bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10738bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10748bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10758bfffbccSCorey Minyard     }
10768bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10778bfffbccSCorey Minyard }
10788bfffbccSCorey Minyard 
10798bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10808bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1081a580d820SCédric Le Goater                                  RspBuffer *rsp)
10828bfffbccSCorey Minyard {
10838bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
1084a580d820SCédric Le Goater         rsp->buffer[2] = 0x80;
1085d13ada5dSCédric Le Goater         return;
10868bfffbccSCorey Minyard     }
10878bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10888bfffbccSCorey Minyard }
10898bfffbccSCorey Minyard 
10908bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10918bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1092a580d820SCédric Le Goater                                RspBuffer *rsp)
10938bfffbccSCorey Minyard {
10948bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10958bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10968bfffbccSCorey Minyard     unsigned int val;
10978bfffbccSCorey Minyard 
10988bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
10998bfffbccSCorey Minyard     if (val == 0 || val > 5) {
1100a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1101d13ada5dSCédric Le Goater         return;
11028bfffbccSCorey Minyard     }
11038bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11048bfffbccSCorey Minyard     switch (val) {
11058bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11068bfffbccSCorey Minyard         break;
11078bfffbccSCorey Minyard 
11088bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
1109a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
11108bfffbccSCorey Minyard         break;
11118bfffbccSCorey Minyard 
11128bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
1113a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
11148bfffbccSCorey Minyard         break;
11158bfffbccSCorey Minyard 
11168bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
1117a580d820SCédric Le Goater         rsp->buffer[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
11188bfffbccSCorey Minyard         break;
11198bfffbccSCorey Minyard 
11208bfffbccSCorey Minyard     default:
1121a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
11228bfffbccSCorey Minyard     }
1123a580d820SCédric Le Goater     if (rsp->buffer[2]) {
1124a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1125d13ada5dSCédric Le Goater         return;
11268bfffbccSCorey Minyard     }
11278bfffbccSCorey Minyard 
11288bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11298bfffbccSCorey Minyard     switch (val) {
11308bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11318bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11328bfffbccSCorey Minyard         break;
11338bfffbccSCorey Minyard 
11348bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11358bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11368bfffbccSCorey Minyard             /* NMI not supported. */
1137a580d820SCédric Le Goater             rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1138d13ada5dSCédric Le Goater             return;
11398bfffbccSCorey Minyard         }
114037eebb86SCorey Minyard         break;
114137eebb86SCorey Minyard 
11428bfffbccSCorey Minyard     default:
11438bfffbccSCorey Minyard         /* We don't support PRE_SMI */
1144a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1145d13ada5dSCédric Le Goater         return;
11468bfffbccSCorey Minyard     }
11478bfffbccSCorey Minyard 
11488bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11498bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11508bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11518bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11528bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11538bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11548bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11558bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11568bfffbccSCorey Minyard     } else {
11578bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11588bfffbccSCorey Minyard     }
11598bfffbccSCorey Minyard }
11608bfffbccSCorey Minyard 
11618bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
11628bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1163a580d820SCédric Le Goater                                RspBuffer *rsp)
11648bfffbccSCorey Minyard {
1165a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1166a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1167a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1168a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
11698bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11708bfffbccSCorey Minyard         long timeout;
11718bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11728bfffbccSCorey Minyard                    / 100000000);
1173a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1174a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
11758bfffbccSCorey Minyard     } else {
1176a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1177a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
11788bfffbccSCorey Minyard     }
11798bfffbccSCorey Minyard }
11808bfffbccSCorey Minyard 
11818bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11828bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1183a580d820SCédric Le Goater                              RspBuffer *rsp)
11848bfffbccSCorey Minyard {
11858bfffbccSCorey Minyard     unsigned int i;
11868bfffbccSCorey Minyard 
1187a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1188a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1189a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1190a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1191a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11928bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1193a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
11948bfffbccSCorey Minyard     }
11958bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1196a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
11978bfffbccSCorey Minyard     }
11988bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1199a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12008bfffbccSCorey Minyard }
12018bfffbccSCorey Minyard 
12028bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12038bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1204a580d820SCédric Le Goater                             RspBuffer *rsp)
12058bfffbccSCorey Minyard {
1206a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1207a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12088bfffbccSCorey Minyard }
12098bfffbccSCorey Minyard 
12108bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12118bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1212a580d820SCédric Le Goater                     RspBuffer *rsp)
12138bfffbccSCorey Minyard {
12148bfffbccSCorey Minyard     unsigned int pos;
12158bfffbccSCorey Minyard     uint16_t nextrec;
1216a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12178bfffbccSCorey Minyard 
12188bfffbccSCorey Minyard     if (cmd[6]) {
1219*7f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
1220*7f996411SCédric Le Goater             rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION;
1221*7f996411SCédric Le Goater             return;
12228bfffbccSCorey Minyard         }
1223*7f996411SCédric Le Goater     }
1224*7f996411SCédric Le Goater 
12258bfffbccSCorey Minyard     pos = 0;
12268bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12278bfffbccSCorey Minyard                        &pos, &nextrec)) {
1228a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1229d13ada5dSCédric Le Goater         return;
12308bfffbccSCorey Minyard     }
1231a2295f0aSCédric Le Goater 
1232a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1233a2295f0aSCédric Le Goater 
1234a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
1235a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1236d13ada5dSCédric Le Goater         return;
12378bfffbccSCorey Minyard     }
12388bfffbccSCorey Minyard 
1239a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1240a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
12418bfffbccSCorey Minyard 
12428bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1243a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12448bfffbccSCorey Minyard     }
12458bfffbccSCorey Minyard 
1246a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
1247a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1248d13ada5dSCédric Le Goater         return;
12498bfffbccSCorey Minyard     }
1250a580d820SCédric Le Goater 
1251a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12528bfffbccSCorey Minyard }
12538bfffbccSCorey Minyard 
12548bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12558bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1256a580d820SCédric Le Goater                     RspBuffer *rsp)
12578bfffbccSCorey Minyard {
12588bfffbccSCorey Minyard     uint16_t recid;
1259a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
12608bfffbccSCorey Minyard 
1261a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
1262a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1263d13ada5dSCédric Le Goater         return;
12648bfffbccSCorey Minyard     }
1265a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1266a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
12678bfffbccSCorey Minyard }
12688bfffbccSCorey Minyard 
12698bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12708bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1271a580d820SCédric Le Goater                           RspBuffer *rsp)
12728bfffbccSCorey Minyard {
1273*7f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
1274*7f996411SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION;
1275*7f996411SCédric Le Goater         return;
1276*7f996411SCédric Le Goater     }
1277*7f996411SCédric Le Goater 
12788bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1279a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1280d13ada5dSCédric Le Goater         return;
12818bfffbccSCorey Minyard     }
12828bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12838bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12848bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12858bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1286a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
12878bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12888bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1289a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
12908bfffbccSCorey Minyard     } else {
1291a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
12928bfffbccSCorey Minyard         return;
12938bfffbccSCorey Minyard     }
1294d13ada5dSCédric Le Goater }
12958bfffbccSCorey Minyard 
12968bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
12978bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1298a580d820SCédric Le Goater                          RspBuffer *rsp)
12998bfffbccSCorey Minyard {
13008bfffbccSCorey Minyard     unsigned int i, val;
13018bfffbccSCorey Minyard 
1302a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1303a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1304a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13058bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1306a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1307a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13088bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1309a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13108bfffbccSCorey Minyard     }
13118bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1312a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13138bfffbccSCorey Minyard     }
13148bfffbccSCorey Minyard     /* Only support Reserve SEL */
1315a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13168bfffbccSCorey Minyard }
13178bfffbccSCorey Minyard 
13188bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
13198bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1320a580d820SCédric Le Goater                         RspBuffer *rsp)
13218bfffbccSCorey Minyard {
1322a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1323a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
13248bfffbccSCorey Minyard }
13258bfffbccSCorey Minyard 
13268bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
13278bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1328a580d820SCédric Le Goater                           RspBuffer *rsp)
13298bfffbccSCorey Minyard {
13308bfffbccSCorey Minyard     unsigned int val;
13318bfffbccSCorey Minyard 
13328bfffbccSCorey Minyard     if (cmd[6]) {
1333*7f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
1334*7f996411SCédric Le Goater             rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION;
1335*7f996411SCédric Le Goater             return;
1336*7f996411SCédric Le Goater         }
13378bfffbccSCorey Minyard     }
13388bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
1339a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1340d13ada5dSCédric Le Goater         return;
13418bfffbccSCorey Minyard     }
13428bfffbccSCorey Minyard     if (cmd[6] > 15) {
1343a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1344d13ada5dSCédric Le Goater         return;
13458bfffbccSCorey Minyard     }
13468bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
13478bfffbccSCorey Minyard         cmd[7] = 16;
13488bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
1349a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1350d13ada5dSCédric Le Goater         return;
13518bfffbccSCorey Minyard     } else {
13528bfffbccSCorey Minyard         cmd[7] += cmd[6];
13538bfffbccSCorey Minyard     }
13548bfffbccSCorey Minyard 
13558bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
13568bfffbccSCorey Minyard     if (val == 0xffff) {
13578bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
13588bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
1359a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1360d13ada5dSCédric Le Goater         return;
13618bfffbccSCorey Minyard     }
13628bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1363a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1364a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
13658bfffbccSCorey Minyard     } else {
1366a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1367a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
13688bfffbccSCorey Minyard     }
13698bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1370a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
13718bfffbccSCorey Minyard     }
13728bfffbccSCorey Minyard }
13738bfffbccSCorey Minyard 
13748bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13758bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1376a580d820SCédric Le Goater                           RspBuffer *rsp)
13778bfffbccSCorey Minyard {
13788bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
1379a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_OUT_OF_SPACE;
1380d13ada5dSCédric Le Goater         return;
13818bfffbccSCorey Minyard     }
13828bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1383a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1384a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
13858bfffbccSCorey Minyard }
13868bfffbccSCorey Minyard 
13878bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13888bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1389a580d820SCédric Le Goater                       RspBuffer *rsp)
13908bfffbccSCorey Minyard {
1391*7f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
1392*7f996411SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION;
1393*7f996411SCédric Le Goater         return;
1394*7f996411SCédric Le Goater     }
1395*7f996411SCédric Le Goater 
13968bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
1397a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1398d13ada5dSCédric Le Goater         return;
13998bfffbccSCorey Minyard     }
14008bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
14018bfffbccSCorey Minyard         ibs->sel.next_free = 0;
14028bfffbccSCorey Minyard         ibs->sel.overflow = 0;
14038bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1404a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14058bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
14068bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1407a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14088bfffbccSCorey Minyard     } else {
1409a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
14108bfffbccSCorey Minyard         return;
14118bfffbccSCorey Minyard     }
1412d13ada5dSCédric Le Goater }
14138bfffbccSCorey Minyard 
14148bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
14158bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1416a580d820SCédric Le Goater                          RspBuffer *rsp)
14178bfffbccSCorey Minyard {
14188bfffbccSCorey Minyard     uint32_t val;
14198bfffbccSCorey Minyard     struct ipmi_time now;
14208bfffbccSCorey Minyard 
14218bfffbccSCorey Minyard     ipmi_gettime(&now);
14228bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1423a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1424a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1425a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1426a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
14278bfffbccSCorey Minyard }
14288bfffbccSCorey Minyard 
14298bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
14308bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1431a580d820SCédric Le Goater                          RspBuffer *rsp)
14328bfffbccSCorey Minyard {
14338bfffbccSCorey Minyard     uint32_t val;
14348bfffbccSCorey Minyard     struct ipmi_time now;
14358bfffbccSCorey Minyard 
14368bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
14378bfffbccSCorey Minyard     ipmi_gettime(&now);
14388bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
14398bfffbccSCorey Minyard }
14408bfffbccSCorey Minyard 
14418bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
14428bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1443a580d820SCédric Le Goater                                   RspBuffer *rsp)
14448bfffbccSCorey Minyard {
14458bfffbccSCorey Minyard     IPMISensor *sens;
14468bfffbccSCorey Minyard 
144773d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
14488bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1449a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1450d13ada5dSCédric Le Goater         return;
14518bfffbccSCorey Minyard     }
14528bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14538bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
14548bfffbccSCorey Minyard     case 0: /* Do not change */
14558bfffbccSCorey Minyard         break;
14568bfffbccSCorey Minyard     case 1: /* Enable bits */
14578bfffbccSCorey Minyard         if (cmd_len > 4) {
14588bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
14598bfffbccSCorey Minyard         }
14608bfffbccSCorey Minyard         if (cmd_len > 5) {
14618bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
14628bfffbccSCorey Minyard         }
14638bfffbccSCorey Minyard         if (cmd_len > 6) {
14648bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
14658bfffbccSCorey Minyard         }
14668bfffbccSCorey Minyard         if (cmd_len > 7) {
14678bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
14688bfffbccSCorey Minyard         }
14698bfffbccSCorey Minyard         break;
14708bfffbccSCorey Minyard     case 2: /* Disable bits */
14718bfffbccSCorey Minyard         if (cmd_len > 4) {
14728bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14738bfffbccSCorey Minyard         }
14748bfffbccSCorey Minyard         if (cmd_len > 5) {
14758bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14768bfffbccSCorey Minyard         }
14778bfffbccSCorey Minyard         if (cmd_len > 6) {
14788bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14798bfffbccSCorey Minyard         }
14808bfffbccSCorey Minyard         if (cmd_len > 7) {
14818bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14828bfffbccSCorey Minyard         }
14838bfffbccSCorey Minyard         break;
14848bfffbccSCorey Minyard     case 3:
1485a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD;
1486d13ada5dSCédric Le Goater         return;
14878bfffbccSCorey Minyard     }
14888bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14898bfffbccSCorey Minyard }
14908bfffbccSCorey Minyard 
14918bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14928bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1493a580d820SCédric Le Goater                                   RspBuffer *rsp)
14948bfffbccSCorey Minyard {
14958bfffbccSCorey Minyard     IPMISensor *sens;
14968bfffbccSCorey Minyard 
149773d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
14988bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1499a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1500d13ada5dSCédric Le Goater         return;
15018bfffbccSCorey Minyard     }
15028bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1503a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1504a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1505a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1506a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1507a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
15088bfffbccSCorey Minyard }
15098bfffbccSCorey Minyard 
15108bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
15118bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1512a580d820SCédric Le Goater                               RspBuffer *rsp)
15138bfffbccSCorey Minyard {
15148bfffbccSCorey Minyard     IPMISensor *sens;
15158bfffbccSCorey Minyard 
151673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15178bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1518a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1519d13ada5dSCédric Le Goater         return;
15208bfffbccSCorey Minyard     }
15218bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15228bfffbccSCorey Minyard 
15238bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
15248bfffbccSCorey Minyard         /* Just clear everything */
15258bfffbccSCorey Minyard         sens->states = 0;
15268bfffbccSCorey Minyard         return;
15278bfffbccSCorey Minyard     }
1528d13ada5dSCédric Le Goater }
15298bfffbccSCorey Minyard 
15308bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
15318bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1532a580d820SCédric Le Goater                                   RspBuffer *rsp)
15338bfffbccSCorey Minyard {
15348bfffbccSCorey Minyard     IPMISensor *sens;
15358bfffbccSCorey Minyard 
153673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15378bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1538a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1539d13ada5dSCédric Le Goater         return;
15408bfffbccSCorey Minyard     }
15418bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1542a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1543a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1544a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1545a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1546a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1547a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
15488bfffbccSCorey Minyard }
15498bfffbccSCorey Minyard 
15508bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
15518bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1552a580d820SCédric Le Goater                                RspBuffer *rsp)
15538bfffbccSCorey Minyard {
15548bfffbccSCorey Minyard     IPMISensor *sens;
15558bfffbccSCorey Minyard 
155673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15578bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1558a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1559d13ada5dSCédric Le Goater         return;
15608bfffbccSCorey Minyard     }
15618bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1562a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1563a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1564a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
15658bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1566a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
15678bfffbccSCorey Minyard     }
15688bfffbccSCorey Minyard }
15698bfffbccSCorey Minyard 
1570728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1571728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1572a580d820SCédric Le Goater                             RspBuffer *rsp)
1573728710e1SCédric Le Goater {
1574728710e1SCédric Le Goater     IPMISensor *sens;
1575728710e1SCédric Le Goater 
1576728710e1SCédric Le Goater 
157773d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1578728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1579a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1580728710e1SCédric Le Goater         return;
1581728710e1SCédric Le Goater     }
1582728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1583728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1584728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1585728710e1SCédric Le Goater }
1586728710e1SCédric Le Goater 
1587728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1588728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1589a580d820SCédric Le Goater                             RspBuffer *rsp)
1590728710e1SCédric Le Goater {
1591728710e1SCédric Le Goater     IPMISensor *sens;
1592728710e1SCédric Le Goater 
1593728710e1SCédric Le Goater 
159473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1595728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1596a580d820SCédric Le Goater         rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1597728710e1SCédric Le Goater         return;
1598728710e1SCédric Le Goater     }
1599728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1600a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1601a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1602728710e1SCédric Le Goater }
1603728710e1SCédric Le Goater 
1604728710e1SCédric Le Goater 
160562a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
16064f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
16074f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
16084f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
16094f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
16108bfffbccSCorey Minyard };
16118bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
161262a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
16138bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
16148bfffbccSCorey Minyard };
16158bfffbccSCorey Minyard 
161662a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
16174f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
16184f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
16194f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
16204f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
16214f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
16224f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
16234f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
16248bfffbccSCorey Minyard };
16258bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
162662a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
16278bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
16288bfffbccSCorey Minyard };
16298bfffbccSCorey Minyard 
163062a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
16314f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
16324f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
16334f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
16344f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
16354f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
16364f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
16374f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
16384f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
16394f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
16404f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
16414f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
16424f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
16434f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
16444f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
16454f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
16464f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
16478bfffbccSCorey Minyard };
16488bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
164962a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
16508bfffbccSCorey Minyard     .cmd_handlers = app_cmds
16518bfffbccSCorey Minyard };
16528bfffbccSCorey Minyard 
165362a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
16544f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
16554f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
16564f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
16574f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
16584f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
16594f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
16604f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
16614f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
16624f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
16634f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
16644f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 },
16654f298a4bSCédric Le Goater     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time },
16668bfffbccSCorey Minyard };
16678bfffbccSCorey Minyard 
16688bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
166962a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
16708bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
16718bfffbccSCorey Minyard };
16728bfffbccSCorey Minyard 
16738bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
16748bfffbccSCorey Minyard {
16758bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
16768bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
16778bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
16788bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
16798bfffbccSCorey Minyard }
16808bfffbccSCorey Minyard 
16818bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
16828bfffbccSCorey Minyard     /* Watchdog device */
16838bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
16848bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
16858bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16868bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
16878bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
16888bfffbccSCorey Minyard     /* End */
16898bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
16908bfffbccSCorey Minyard };
16918bfffbccSCorey Minyard 
1692bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1693bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1694bd66bcfcSCorey Minyard     .version_id = 1,
1695bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1696bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1697bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1698bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1699bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1700bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1701bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1702bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1703bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1704bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1705bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1706bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1707bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1708bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1709bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1710bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1711bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1712bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1713bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1714bd66bcfcSCorey Minyard                        IPMIBmcSim),
1715bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1716bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1717bd66bcfcSCorey Minyard     }
1718bd66bcfcSCorey Minyard };
1719bd66bcfcSCorey Minyard 
17208bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj)
17218bfffbccSCorey Minyard {
17228bfffbccSCorey Minyard     IPMIBmc *b = IPMI_BMC(obj);
17238bfffbccSCorey Minyard     unsigned int i;
17248bfffbccSCorey Minyard     unsigned int recid;
17258bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
17268bfffbccSCorey Minyard 
17278bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
17288bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
17298bfffbccSCorey Minyard 
17308bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
17318bfffbccSCorey Minyard     ibs->device_id = 0x20;
17328bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1733b7088392SCédric Le Goater     ibs->restart_cause = 0;
17348bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
17358bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
17368bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
17378bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
17388bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
17398bfffbccSCorey Minyard     }
17408bfffbccSCorey Minyard 
17418bfffbccSCorey Minyard     for (i = 0;;) {
1742a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh;
17438bfffbccSCorey Minyard         int len;
1744a2295f0aSCédric Le Goater         if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) {
17457cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
17468bfffbccSCorey Minyard             return;
17478bfffbccSCorey Minyard         }
1748a2295f0aSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &init_sdrs[i];
1749a2295f0aSCédric Le Goater         len = ipmi_sdr_length(sdrh);
1750a2295f0aSCédric Le Goater         recid = ipmi_sdr_recid(sdrh);
17518bfffbccSCorey Minyard         if (recid == 0xffff) {
17528bfffbccSCorey Minyard             break;
17538bfffbccSCorey Minyard         }
1754792afddbSCédric Le Goater         if ((i + len) > sizeof(init_sdrs)) {
17557cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
17568bfffbccSCorey Minyard             return;
17578bfffbccSCorey Minyard         }
1758a2295f0aSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
1759792afddbSCédric Le Goater         i += len;
17608bfffbccSCorey Minyard     }
17618bfffbccSCorey Minyard 
176252ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
176352ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
176452ba4d50SCédric Le Goater 
176552ba4d50SCédric Le Goater     if (qemu_uuid_set) {
176652ba4d50SCédric Le Goater         memcpy(&ibs->uuid, qemu_uuid, 16);
176752ba4d50SCédric Le Goater     } else {
176852ba4d50SCédric Le Goater         memset(&ibs->uuid, 0, 16);
176952ba4d50SCédric Le Goater     }
177052ba4d50SCédric Le Goater 
17718bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
17728bfffbccSCorey Minyard     register_cmds(ibs);
17738bfffbccSCorey Minyard 
17748bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1775bd66bcfcSCorey Minyard 
1776bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
17778bfffbccSCorey Minyard }
17788bfffbccSCorey Minyard 
17798bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
17808bfffbccSCorey Minyard {
17818bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
17828bfffbccSCorey Minyard 
17838bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
17848bfffbccSCorey Minyard }
17858bfffbccSCorey Minyard 
17868bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
17878bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
17888bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
17898bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
17908bfffbccSCorey Minyard     .instance_init = ipmi_sim_init,
17918bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
17928bfffbccSCorey Minyard };
17938bfffbccSCorey Minyard 
17948bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
17958bfffbccSCorey Minyard {
17968bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
17978bfffbccSCorey Minyard }
17988bfffbccSCorey Minyard 
17998bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1800