xref: /openbmc/qemu/hw/ipmi/ipmi_bmc_sim.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
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"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
318c6fd7f3SCédric Le Goater #include "hw/loader.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
33ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
34d6454270SMarkus Armbruster #include "migration/vmstate.h"
358bfffbccSCorey Minyard 
368bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
378bfffbccSCorey Minyard 
388bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
398bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
408bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
41b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
428bfffbccSCorey Minyard 
438bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
448bfffbccSCorey Minyard 
459380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG       0x02
468bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
478bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
488bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
498bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
508bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
51728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
52728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
53e3f7320cSCédric Le Goater #define IPMI_CMD_SET_SENSOR_READING       0x30
548bfffbccSCorey Minyard 
558bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
568bfffbccSCorey Minyard 
578bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
588bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
598bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
6052ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
6152ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
6252ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
638bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
648bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
658bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
668bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
678bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
688bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
698bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
708bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
718bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
728bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
738bfffbccSCorey Minyard 
748bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
758bfffbccSCorey Minyard 
768bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
788bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
798bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
808bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
818bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
828bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
838bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
848bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
858bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
868bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
878bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
888bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
89540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO        0x10
90540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA            0x11
91540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA           0x12
928bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
948bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
958bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
968bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
978bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
988bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
998bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
1008bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
1018bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
1028bfffbccSCorey Minyard 
1038bfffbccSCorey Minyard 
1048bfffbccSCorey Minyard /* Same as a timespec struct. */
1058bfffbccSCorey Minyard struct ipmi_time {
1068bfffbccSCorey Minyard     long tv_sec;
1078bfffbccSCorey Minyard     long tv_nsec;
1088bfffbccSCorey Minyard };
1098bfffbccSCorey Minyard 
1108bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1118bfffbccSCorey Minyard 
1128bfffbccSCorey Minyard typedef struct IPMISel {
1138bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1148bfffbccSCorey Minyard     unsigned int next_free;
1158bfffbccSCorey Minyard     long time_offset;
1168bfffbccSCorey Minyard     uint16_t reservation;
1178bfffbccSCorey Minyard     uint8_t last_addition[4];
1188bfffbccSCorey Minyard     uint8_t last_clear[4];
1198bfffbccSCorey Minyard     uint8_t overflow;
1208bfffbccSCorey Minyard } IPMISel;
1218bfffbccSCorey Minyard 
1228bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1238bfffbccSCorey Minyard 
1248bfffbccSCorey Minyard typedef struct IPMISdr {
1258bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1268bfffbccSCorey Minyard     unsigned int next_free;
1278bfffbccSCorey Minyard     uint16_t next_rec_id;
1288bfffbccSCorey Minyard     uint16_t reservation;
1298bfffbccSCorey Minyard     uint8_t last_addition[4];
1308bfffbccSCorey Minyard     uint8_t last_clear[4];
1318bfffbccSCorey Minyard     uint8_t overflow;
1328bfffbccSCorey Minyard } IPMISdr;
1338bfffbccSCorey Minyard 
134540c07d3SCédric Le Goater typedef struct IPMIFru {
135540c07d3SCédric Le Goater     char *filename;
136540c07d3SCédric Le Goater     unsigned int nentries;
137540c07d3SCédric Le Goater     uint16_t areasize;
138540c07d3SCédric Le Goater     uint8_t *data;
139540c07d3SCédric Le Goater } IPMIFru;
140540c07d3SCédric Le Goater 
1418bfffbccSCorey Minyard typedef struct IPMISensor {
1428bfffbccSCorey Minyard     uint8_t status;
1438bfffbccSCorey Minyard     uint8_t reading;
1448bfffbccSCorey Minyard     uint16_t states_suppt;
1458bfffbccSCorey Minyard     uint16_t assert_suppt;
1468bfffbccSCorey Minyard     uint16_t deassert_suppt;
1478bfffbccSCorey Minyard     uint16_t states;
1488bfffbccSCorey Minyard     uint16_t assert_states;
1498bfffbccSCorey Minyard     uint16_t deassert_states;
1508bfffbccSCorey Minyard     uint16_t assert_enable;
1518bfffbccSCorey Minyard     uint16_t deassert_enable;
1528bfffbccSCorey Minyard     uint8_t  sensor_type;
1538bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1548bfffbccSCorey Minyard } IPMISensor;
1558bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1568bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1578bfffbccSCorey Minyard                                              !!(v))
1588bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1598bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1608bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1618bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1628bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1638bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1648bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1658bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1668bfffbccSCorey Minyard                                              (v & 0xc0))
1678bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1688bfffbccSCorey Minyard 
1698bfffbccSCorey Minyard #define MAX_SENSORS 20
1708bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1718bfffbccSCorey Minyard 
1728bfffbccSCorey Minyard #define MAX_NETFNS 64
1734f298a4bSCédric Le Goater 
1748bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1758bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1768bfffbccSCorey Minyard     uint8_t len;
1778bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1788bfffbccSCorey Minyard } IPMIRcvBufEntry;
1798bfffbccSCorey Minyard 
1808bfffbccSCorey Minyard struct IPMIBmcSim {
1818bfffbccSCorey Minyard     IPMIBmc parent;
1828bfffbccSCorey Minyard 
1838bfffbccSCorey Minyard     QEMUTimer *timer;
1848bfffbccSCorey Minyard 
1858bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1868bfffbccSCorey Minyard     uint8_t msg_flags;
1878bfffbccSCorey Minyard 
1888bfffbccSCorey Minyard     bool     watchdog_initialized;
1898bfffbccSCorey Minyard     uint8_t  watchdog_use;
1908bfffbccSCorey Minyard     uint8_t  watchdog_action;
1918bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1929e744990SJinhua Cao     uint8_t  watchdog_expired;
1938bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1948bfffbccSCorey Minyard 
1958bfffbccSCorey Minyard     bool     watchdog_running;
1968bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1978bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1988bfffbccSCorey Minyard 
1998bfffbccSCorey Minyard     uint8_t device_id;
2008bfffbccSCorey Minyard     uint8_t ipmi_version;
2018bfffbccSCorey Minyard     uint8_t device_rev;
2028bfffbccSCorey Minyard     uint8_t fwrev1;
2038bfffbccSCorey Minyard     uint8_t fwrev2;
20420b23364SCorey Minyard     uint32_t mfg_id;
20520b23364SCorey Minyard     uint16_t product_id;
2068bfffbccSCorey Minyard 
207b7088392SCédric Le Goater     uint8_t restart_cause;
208b7088392SCédric Le Goater 
20952ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
2107b0cd78bSCorey Minyard     QemuUUID uuid;
21152ba4d50SCédric Le Goater 
2128bfffbccSCorey Minyard     IPMISel sel;
2138bfffbccSCorey Minyard     IPMISdr sdr;
214540c07d3SCédric Le Goater     IPMIFru fru;
2158bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2168c6fd7f3SCédric Le Goater     char *sdr_filename;
2178bfffbccSCorey Minyard 
2188bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2198bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2208bfffbccSCorey Minyard 
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 #define RSP_BUFFER_INITIALIZER { }
2678bfffbccSCorey Minyard 
rsp_buffer_pushmore(RspBuffer * rsp,uint8_t * bytes,unsigned int n)268a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
269a580d820SCédric Le Goater                                        unsigned int n)
270a580d820SCédric Le Goater {
271a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
2726acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
273a580d820SCédric Le Goater         return;
274a580d820SCédric Le Goater     }
275a580d820SCédric Le Goater 
276a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
277a580d820SCédric Le Goater     rsp->len += n;
278a580d820SCédric Le Goater }
2798bfffbccSCorey Minyard 
2808bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2818bfffbccSCorey Minyard 
ipmi_gettime(struct ipmi_time * time)2828bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2838bfffbccSCorey Minyard {
2848bfffbccSCorey Minyard     int64_t stime;
2858bfffbccSCorey Minyard 
2868bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2878bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
2888bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
2898bfffbccSCorey Minyard }
2908bfffbccSCorey Minyard 
ipmi_getmonotime(void)2918bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2928bfffbccSCorey Minyard {
2938bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2948bfffbccSCorey Minyard }
2958bfffbccSCorey Minyard 
ipmi_timeout(void * opaque)2968bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2978bfffbccSCorey Minyard {
2988bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
2998bfffbccSCorey Minyard 
3008bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3018bfffbccSCorey Minyard }
3028bfffbccSCorey Minyard 
set_timestamp(IPMIBmcSim * ibs,uint8_t * ts)3038bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3048bfffbccSCorey Minyard {
3058bfffbccSCorey Minyard     unsigned int val;
3068bfffbccSCorey Minyard     struct ipmi_time now;
3078bfffbccSCorey Minyard 
3088bfffbccSCorey Minyard     ipmi_gettime(&now);
3098bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3108bfffbccSCorey Minyard     ts[0] = val & 0xff;
3118bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3128bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3138bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3148bfffbccSCorey Minyard }
3158bfffbccSCorey Minyard 
sdr_inc_reservation(IPMISdr * sdr)3168bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3178bfffbccSCorey Minyard {
3188bfffbccSCorey Minyard     sdr->reservation++;
3198bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3208bfffbccSCorey Minyard         sdr->reservation = 1;
3218bfffbccSCorey Minyard     }
3228bfffbccSCorey Minyard }
3238bfffbccSCorey Minyard 
sdr_add_entry(IPMIBmcSim * ibs,const struct ipmi_sdr_header * sdrh_entry,unsigned int len,uint16_t * recid)324a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
325a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3268bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3278bfffbccSCorey Minyard {
328a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
329a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
330a2295f0aSCédric Le Goater 
331a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3328bfffbccSCorey Minyard         return 1;
3338bfffbccSCorey Minyard     }
3348bfffbccSCorey Minyard 
335a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3368bfffbccSCorey Minyard         return 1;
3378bfffbccSCorey Minyard     }
3388bfffbccSCorey Minyard 
3398bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3408bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3418bfffbccSCorey Minyard         return 1;
3428bfffbccSCorey Minyard     }
3438bfffbccSCorey Minyard 
344a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
345a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
346a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
347a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3488bfffbccSCorey Minyard 
3498bfffbccSCorey Minyard     if (recid) {
3508bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3518bfffbccSCorey Minyard     }
3528bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3538bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3548bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3558bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3568bfffbccSCorey Minyard     return 0;
3578bfffbccSCorey Minyard }
3588bfffbccSCorey Minyard 
sdr_find_entry(IPMISdr * sdr,uint16_t recid,unsigned int * retpos,uint16_t * nextrec)3598bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3608bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3618bfffbccSCorey Minyard {
3628bfffbccSCorey Minyard     unsigned int pos = *retpos;
3638bfffbccSCorey Minyard 
3648bfffbccSCorey Minyard     while (pos < sdr->next_free) {
365a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
366a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
367a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
368a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3698bfffbccSCorey Minyard 
3708bfffbccSCorey Minyard         if (trec == recid) {
3718bfffbccSCorey Minyard             if (nextrec) {
3728bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3738bfffbccSCorey Minyard                     *nextrec = 0xffff;
3748bfffbccSCorey Minyard                 } else {
3758bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3768bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3778bfffbccSCorey Minyard                 }
3788bfffbccSCorey Minyard             }
3798bfffbccSCorey Minyard             *retpos = pos;
3808bfffbccSCorey Minyard             return 0;
3818bfffbccSCorey Minyard         }
3828bfffbccSCorey Minyard         pos = nextpos;
3838bfffbccSCorey Minyard     }
3848bfffbccSCorey Minyard     return 1;
3858bfffbccSCorey Minyard }
3868bfffbccSCorey Minyard 
ipmi_bmc_sdr_find(IPMIBmc * b,uint16_t recid,const struct ipmi_sdr_compact ** sdr,uint16_t * nextrec)3877fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
3887fabcdb9SCédric Le Goater                       const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
3897fabcdb9SCédric Le Goater 
3907fabcdb9SCédric Le Goater {
3917fabcdb9SCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
3927fabcdb9SCédric Le Goater     unsigned int pos;
3937fabcdb9SCédric Le Goater 
3947fabcdb9SCédric Le Goater     pos = 0;
3957fabcdb9SCédric Le Goater     if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
3967fabcdb9SCédric Le Goater         return -1;
3977fabcdb9SCédric Le Goater     }
3987fabcdb9SCédric Le Goater 
3997fabcdb9SCédric Le Goater     *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4007fabcdb9SCédric Le Goater     return 0;
4017fabcdb9SCédric Le Goater }
4027fabcdb9SCédric Le Goater 
sel_inc_reservation(IPMISel * sel)4038bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4048bfffbccSCorey Minyard {
4058bfffbccSCorey Minyard     sel->reservation++;
4068bfffbccSCorey Minyard     if (sel->reservation == 0) {
4078bfffbccSCorey Minyard         sel->reservation = 1;
4088bfffbccSCorey Minyard     }
4098bfffbccSCorey Minyard }
4108bfffbccSCorey Minyard 
4118bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
sel_add_event(IPMIBmcSim * ibs,uint8_t * event)4128bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4138bfffbccSCorey Minyard {
4149f7d1d92SCorey Minyard     uint8_t ts[4];
4159f7d1d92SCorey Minyard 
4168bfffbccSCorey Minyard     event[0] = 0xff;
4178bfffbccSCorey Minyard     event[1] = 0xff;
4189f7d1d92SCorey Minyard     set_timestamp(ibs, ts);
4199f7d1d92SCorey Minyard     if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4209f7d1d92SCorey Minyard         memcpy(event + 3, ts, 4);
4219f7d1d92SCorey Minyard     }
4228bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4238bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4248bfffbccSCorey Minyard         return 1;
4258bfffbccSCorey Minyard     }
4268bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4278bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4289f7d1d92SCorey Minyard     memcpy(ibs->sel.last_addition, ts, 4);
4298bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4308bfffbccSCorey Minyard     ibs->sel.next_free++;
4318bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4328bfffbccSCorey Minyard     return 0;
4338bfffbccSCorey Minyard }
4348bfffbccSCorey Minyard 
attn_set(IPMIBmcSim * ibs)4358bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4368bfffbccSCorey Minyard {
4378bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4388bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4398bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4408bfffbccSCorey Minyard }
4418bfffbccSCorey Minyard 
attn_irq_enabled(IPMIBmcSim * ibs)4428bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4438bfffbccSCorey Minyard {
4448bc8af69SCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) &&
4458bc8af69SCorey Minyard             (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
4468bc8af69SCorey Minyard              IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
4478bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4488bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4498bfffbccSCorey Minyard }
4508bfffbccSCorey Minyard 
ipmi_bmc_gen_event(IPMIBmc * b,uint8_t * evt,bool log)451cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
452cd60d85eSCédric Le Goater {
453cd60d85eSCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
454cd60d85eSCédric Le Goater     IPMIInterface *s = ibs->parent.intf;
455cd60d85eSCédric Le Goater     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
456cd60d85eSCédric Le Goater 
457cd60d85eSCédric Le Goater     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
458cd60d85eSCédric Le Goater         return;
459cd60d85eSCédric Le Goater     }
460cd60d85eSCédric Le Goater 
461cd60d85eSCédric Le Goater     if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
462cd60d85eSCédric Le Goater         sel_add_event(ibs, evt);
463cd60d85eSCédric Le Goater     }
464cd60d85eSCédric Le Goater 
465cd60d85eSCédric Le Goater     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
466cd60d85eSCédric Le Goater         goto out;
467cd60d85eSCédric Le Goater     }
468cd60d85eSCédric Le Goater 
469cd60d85eSCédric Le Goater     memcpy(ibs->evtbuf, evt, 16);
470cd60d85eSCédric Le Goater     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
471cd60d85eSCédric Le Goater     k->set_atn(s, 1, attn_irq_enabled(ibs));
472cd60d85eSCédric Le Goater  out:
473cd60d85eSCédric Le Goater     return;
474cd60d85eSCédric Le Goater }
gen_event(IPMIBmcSim * ibs,unsigned int sens_num,uint8_t deassert,uint8_t evd1,uint8_t evd2,uint8_t evd3)4758bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4768bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4778bfffbccSCorey Minyard {
4788bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4798bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4808bfffbccSCorey Minyard     uint8_t evt[16];
4818bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4828bfffbccSCorey Minyard 
4838bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4848bfffbccSCorey Minyard         return;
4858bfffbccSCorey Minyard     }
4868bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4878bfffbccSCorey Minyard         return;
4888bfffbccSCorey Minyard     }
4898bfffbccSCorey Minyard 
4908bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4918bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4928bfffbccSCorey Minyard     evt[8] = 0;
4938bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4948bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4958bfffbccSCorey Minyard     evt[11] = sens_num;
4968bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4978bfffbccSCorey Minyard     evt[13] = evd1;
4988bfffbccSCorey Minyard     evt[14] = evd2;
4998bfffbccSCorey Minyard     evt[15] = evd3;
5008bfffbccSCorey Minyard 
5018bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5028bfffbccSCorey Minyard         sel_add_event(ibs, evt);
5038bfffbccSCorey Minyard     }
5048bfffbccSCorey Minyard 
5058bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
506d13ada5dSCédric Le Goater         return;
5078bfffbccSCorey Minyard     }
5088bfffbccSCorey Minyard 
5098bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
5108bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5118bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
5128bfffbccSCorey Minyard }
5138bfffbccSCorey Minyard 
sensor_set_discrete_bit(IPMIBmcSim * ibs,unsigned int sensor,unsigned int bit,unsigned int val,uint8_t evd1,uint8_t evd2,uint8_t evd3)5148bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5158bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
5168bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
5178bfffbccSCorey Minyard {
5188bfffbccSCorey Minyard     IPMISensor *sens;
5198bfffbccSCorey Minyard     uint16_t mask;
5208bfffbccSCorey Minyard 
5218bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5228bfffbccSCorey Minyard         return;
5238bfffbccSCorey Minyard     }
5248bfffbccSCorey Minyard     if (bit >= 16) {
5258bfffbccSCorey Minyard         return;
5268bfffbccSCorey Minyard     }
5278bfffbccSCorey Minyard 
5288bfffbccSCorey Minyard     mask = (1 << bit);
5298bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5308bfffbccSCorey Minyard     if (val) {
5318bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5328bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5338bfffbccSCorey Minyard             return; /* Already asserted */
5348bfffbccSCorey Minyard         }
5358bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5368bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5378bfffbccSCorey Minyard             /* Send an event on assert */
5388bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5398bfffbccSCorey Minyard         }
5408bfffbccSCorey Minyard     } else {
5418bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5428bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5438bfffbccSCorey Minyard             return; /* Already deasserted */
5448bfffbccSCorey Minyard         }
5458bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5468bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5478bfffbccSCorey Minyard             /* Send an event on deassert */
5488bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5498bfffbccSCorey Minyard         }
5508bfffbccSCorey Minyard     }
5518bfffbccSCorey Minyard }
5528bfffbccSCorey Minyard 
ipmi_init_sensors_from_sdrs(IPMIBmcSim * s)5538bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5548bfffbccSCorey Minyard {
5558bfffbccSCorey Minyard     unsigned int i, pos;
5568bfffbccSCorey Minyard     IPMISensor *sens;
5578bfffbccSCorey Minyard 
5588bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5598bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5608bfffbccSCorey Minyard     }
5618bfffbccSCorey Minyard 
5628bfffbccSCorey Minyard     pos = 0;
5638bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
564a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
565a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
566a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5678bfffbccSCorey Minyard 
5688bfffbccSCorey Minyard         if (len < 20) {
5698bfffbccSCorey Minyard             continue;
5708bfffbccSCorey Minyard         }
571a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5728bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5738bfffbccSCorey Minyard         }
5748bfffbccSCorey Minyard 
57573d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5768bfffbccSCorey Minyard             continue;
5778bfffbccSCorey Minyard         }
578a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5798bfffbccSCorey Minyard 
5808bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
581a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
582a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
583a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
584a2295f0aSCédric Le Goater         sens->deassert_suppt =
585a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
586a2295f0aSCédric Le Goater         sens->states_suppt =
587a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
588a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
589a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5908bfffbccSCorey Minyard 
5918bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5928bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5938bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5948bfffbccSCorey Minyard     }
5958bfffbccSCorey Minyard }
5968bfffbccSCorey Minyard 
ipmi_sim_register_netfn(IPMIBmcSim * s,unsigned int netfn,const IPMINetfn * netfnd)597ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5988bfffbccSCorey Minyard                         const IPMINetfn *netfnd)
5998bfffbccSCorey Minyard {
60093a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6018bfffbccSCorey Minyard         return -1;
6028bfffbccSCorey Minyard     }
6038bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6048bfffbccSCorey Minyard     return 0;
6058bfffbccSCorey Minyard }
6068bfffbccSCorey Minyard 
ipmi_get_handler(IPMIBmcSim * ibs,unsigned int netfn,unsigned int cmd)6074f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6084f298a4bSCédric Le Goater                                               unsigned int netfn,
6094f298a4bSCédric Le Goater                                               unsigned int cmd)
6104f298a4bSCédric Le Goater {
6114f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6124f298a4bSCédric Le Goater 
6134f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6144f298a4bSCédric Le Goater         return NULL;
6154f298a4bSCédric Le Goater     }
6164f298a4bSCédric Le Goater 
6174f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6184f298a4bSCédric Le Goater         return NULL;
6194f298a4bSCédric Le Goater     }
6204f298a4bSCédric Le Goater 
6214f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6224f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6234f298a4bSCédric Le Goater         return NULL;
6244f298a4bSCédric Le Goater     }
6254f298a4bSCédric Le Goater 
6264f298a4bSCédric Le Goater     return hdl;
6274f298a4bSCédric Le Goater }
6284f298a4bSCédric Le Goater 
next_timeout(IPMIBmcSim * ibs)6298bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6308bfffbccSCorey Minyard {
6318bfffbccSCorey Minyard     int64_t next;
6328bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6338bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6348bfffbccSCorey Minyard     } else {
6358bfffbccSCorey Minyard         /* Wait a minute */
6368bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6378bfffbccSCorey Minyard     }
6388bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6398bfffbccSCorey Minyard }
6408bfffbccSCorey Minyard 
ipmi_sim_handle_command(IPMIBmc * b,uint8_t * cmd,unsigned int cmd_len,unsigned int max_cmd_len,uint8_t msg_id)6418bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6428bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6438bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6448bfffbccSCorey Minyard                                     uint8_t msg_id)
6458bfffbccSCorey Minyard {
6468bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6478bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6488bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6494f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
650a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6518bfffbccSCorey Minyard 
6528bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6538bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
654a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6556acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
656d13ada5dSCédric Le Goater         goto out;
657d13ada5dSCédric Le Goater     }
658d13ada5dSCédric Le Goater 
659a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
660a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
661a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6628bfffbccSCorey Minyard 
6638bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6648bfffbccSCorey Minyard     if (cmd_len < 2) {
6656acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6668bfffbccSCorey Minyard         goto out;
6678bfffbccSCorey Minyard     }
6688bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6696acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6708bfffbccSCorey Minyard         goto out;
6718bfffbccSCorey Minyard     }
6728bfffbccSCorey Minyard 
6738bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6748bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6756acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6768bfffbccSCorey Minyard         goto out;
6778bfffbccSCorey Minyard     }
6788bfffbccSCorey Minyard 
6794f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6804f298a4bSCédric Le Goater     if (!hdl) {
6816acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6828bfffbccSCorey Minyard         goto out;
6838bfffbccSCorey Minyard     }
6848bfffbccSCorey Minyard 
6854f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
6866acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6874f298a4bSCédric Le Goater         goto out;
6884f298a4bSCédric Le Goater     }
6894f298a4bSCédric Le Goater 
690a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6918bfffbccSCorey Minyard 
6928bfffbccSCorey Minyard  out:
693a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6948bfffbccSCorey Minyard 
6958bfffbccSCorey Minyard     next_timeout(ibs);
6968bfffbccSCorey Minyard }
6978bfffbccSCorey Minyard 
ipmi_sim_handle_timeout(IPMIBmcSim * ibs)6988bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6998bfffbccSCorey Minyard {
7008bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7018bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7028bfffbccSCorey Minyard 
7038bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7048bfffbccSCorey Minyard         goto out;
7058bfffbccSCorey Minyard     }
7068bfffbccSCorey Minyard 
7078bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7088bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7098bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7108bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7118bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7128bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7138bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
7148bfffbccSCorey Minyard             break;
7158bfffbccSCorey Minyard 
7168bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7178bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7188bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7198bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7208bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
7218bfffbccSCorey Minyard             break;
7228bfffbccSCorey Minyard 
7238bfffbccSCorey Minyard         default:
7248bfffbccSCorey Minyard             goto do_full_expiry;
7258bfffbccSCorey Minyard         }
7268bfffbccSCorey Minyard 
7278bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7288bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7298bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7308bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7318bfffbccSCorey Minyard         goto out;
7328bfffbccSCorey Minyard     }
7338bfffbccSCorey Minyard 
7348bfffbccSCorey Minyard  do_full_expiry:
7358bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7368bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7378bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7388bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7398bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7408bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7418bfffbccSCorey Minyard         break;
7428bfffbccSCorey Minyard 
7438bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7448bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7458bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7468bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7478bfffbccSCorey Minyard         break;
7488bfffbccSCorey Minyard 
7498bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7508bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7518bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7528bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7538bfffbccSCorey Minyard         break;
7548bfffbccSCorey Minyard 
7558bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7568bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7578bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7588bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7598bfffbccSCorey Minyard         break;
7608bfffbccSCorey Minyard     }
7618bfffbccSCorey Minyard 
7628bfffbccSCorey Minyard  out:
7638bfffbccSCorey Minyard     next_timeout(ibs);
7648bfffbccSCorey Minyard }
7658bfffbccSCorey Minyard 
chassis_capabilities(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7668bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7678bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
768a580d820SCédric Le Goater                                  RspBuffer *rsp)
7698bfffbccSCorey Minyard {
770a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
771a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
772a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
773a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
774a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
7758bfffbccSCorey Minyard }
7768bfffbccSCorey Minyard 
chassis_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7778bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7788bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
779a580d820SCédric Le Goater                            RspBuffer *rsp)
7808bfffbccSCorey Minyard {
781a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
782a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
783a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
784a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7858bfffbccSCorey Minyard }
7868bfffbccSCorey Minyard 
chassis_control(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7878bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7888bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
789a580d820SCédric Le Goater                             RspBuffer *rsp)
7908bfffbccSCorey Minyard {
7918bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7928bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7938bfffbccSCorey Minyard 
7948bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7958bfffbccSCorey Minyard     case 0: /* power down */
7966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
7978bfffbccSCorey Minyard         break;
7988bfffbccSCorey Minyard     case 1: /* power up */
7996acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8008bfffbccSCorey Minyard         break;
8018bfffbccSCorey Minyard     case 2: /* power cycle */
8026acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8038bfffbccSCorey Minyard         break;
8048bfffbccSCorey Minyard     case 3: /* hard reset */
8056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8068bfffbccSCorey Minyard         break;
8078bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8086acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8098bfffbccSCorey Minyard         break;
8108bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8116acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8126acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8138bfffbccSCorey Minyard         break;
8148bfffbccSCorey Minyard     default:
8156acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8168bfffbccSCorey Minyard         return;
8178bfffbccSCorey Minyard     }
818d13ada5dSCédric Le Goater }
8198bfffbccSCorey Minyard 
chassis_get_sys_restart_cause(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)820b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
821b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
822a580d820SCédric Le Goater                            RspBuffer *rsp)
823a580d820SCédric Le Goater 
824b7088392SCédric Le Goater {
825a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
826a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
827b7088392SCédric Le Goater }
828b7088392SCédric Le Goater 
get_device_id(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8298bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8308bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
831a580d820SCédric Le Goater                           RspBuffer *rsp)
8328bfffbccSCorey Minyard {
833a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
834a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
835a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
836a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
837a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
838a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
83920b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
84020b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
84120b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
84220b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->product_id & 0xff);
84320b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8448bfffbccSCorey Minyard }
8458bfffbccSCorey Minyard 
set_global_enables(IPMIBmcSim * ibs,uint8_t val)8468bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8478bfffbccSCorey Minyard {
8488bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8498bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8508bfffbccSCorey Minyard     bool irqs_on;
8518bfffbccSCorey Minyard 
8528bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8538bfffbccSCorey Minyard 
8548bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8558bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8568bfffbccSCorey Minyard 
8578bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8588bfffbccSCorey Minyard }
8598bfffbccSCorey Minyard 
cold_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8608bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8618bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
862a580d820SCédric Le Goater                        RspBuffer *rsp)
8638bfffbccSCorey Minyard {
8648bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8658bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8668bfffbccSCorey Minyard 
8678bfffbccSCorey Minyard     /* Disable all interrupts */
8688bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8698bfffbccSCorey Minyard 
8708bfffbccSCorey Minyard     if (k->reset) {
8718bfffbccSCorey Minyard         k->reset(s, true);
8728bfffbccSCorey Minyard     }
8738bfffbccSCorey Minyard }
8748bfffbccSCorey Minyard 
warm_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8758bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8768bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
877a580d820SCédric Le Goater                        RspBuffer *rsp)
8788bfffbccSCorey Minyard {
8798bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8808bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8818bfffbccSCorey Minyard 
8828bfffbccSCorey Minyard     if (k->reset) {
8838bfffbccSCorey Minyard         k->reset(s, false);
8848bfffbccSCorey Minyard     }
8858bfffbccSCorey Minyard }
set_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)88652ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
88752ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
888a580d820SCédric Le Goater                                  RspBuffer *rsp)
88952ba4d50SCédric Le Goater {
89052ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
89152ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
89252ba4d50SCédric Le Goater }
89352ba4d50SCédric Le Goater 
get_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)89452ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
89552ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
896a580d820SCédric Le Goater                                  RspBuffer *rsp)
89752ba4d50SCédric Le Goater {
898a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
899a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
90052ba4d50SCédric Le Goater }
90152ba4d50SCédric Le Goater 
get_device_guid(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)90252ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
90352ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
904a580d820SCédric Le Goater                             RspBuffer *rsp)
90552ba4d50SCédric Le Goater {
90652ba4d50SCédric Le Goater     unsigned int i;
90752ba4d50SCédric Le Goater 
9087b0cd78bSCorey Minyard     /* An uninitialized uuid is all zeros, use that to know if it is set. */
90952ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
9107b0cd78bSCorey Minyard         if (ibs->uuid.data[i]) {
9117b0cd78bSCorey Minyard             goto uuid_set;
9127b0cd78bSCorey Minyard         }
9137b0cd78bSCorey Minyard     }
9147b0cd78bSCorey Minyard     /* No uuid is set, return an error. */
9157b0cd78bSCorey Minyard     rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
9167b0cd78bSCorey Minyard     return;
9177b0cd78bSCorey Minyard 
9187b0cd78bSCorey Minyard  uuid_set:
9197b0cd78bSCorey Minyard     for (i = 0; i < 16; i++) {
9207b0cd78bSCorey Minyard         rsp_buffer_push(rsp, ibs->uuid.data[i]);
92152ba4d50SCédric Le Goater     }
92252ba4d50SCédric Le Goater }
9238bfffbccSCorey Minyard 
set_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9248bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9258bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
926a580d820SCédric Le Goater                                    RspBuffer *rsp)
9278bfffbccSCorey Minyard {
9288bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
9298bfffbccSCorey Minyard }
9308bfffbccSCorey Minyard 
get_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9318bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9328bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
933a580d820SCédric Le Goater                                    RspBuffer *rsp)
9348bfffbccSCorey Minyard {
935a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9368bfffbccSCorey Minyard }
9378bfffbccSCorey Minyard 
clr_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9388bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9398bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
940a580d820SCédric Le Goater                           RspBuffer *rsp)
9418bfffbccSCorey Minyard {
9428bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9438bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9448bfffbccSCorey Minyard 
9458bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9468bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9478bfffbccSCorey Minyard }
9488bfffbccSCorey Minyard 
get_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9498bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9508bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
951a580d820SCédric Le Goater                           RspBuffer *rsp)
9528bfffbccSCorey Minyard {
953a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9548bfffbccSCorey Minyard }
9558bfffbccSCorey Minyard 
read_evt_msg_buf(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9568bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9578bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
958a580d820SCédric Le Goater                              RspBuffer *rsp)
9598bfffbccSCorey Minyard {
9608bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9618bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9628bfffbccSCorey Minyard     unsigned int i;
9638bfffbccSCorey Minyard 
9648bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9656acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
966d13ada5dSCédric Le Goater         return;
9678bfffbccSCorey Minyard     }
9688bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
969a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9708bfffbccSCorey Minyard     }
9718bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9728bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9738bfffbccSCorey Minyard }
9748bfffbccSCorey Minyard 
get_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9758bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9768bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
977a580d820SCédric Le Goater                     RspBuffer *rsp)
9788bfffbccSCorey Minyard {
9798bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9808bfffbccSCorey Minyard 
9818bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9826acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
9838bfffbccSCorey Minyard         goto out;
9848bfffbccSCorey Minyard     }
985a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
9868bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
987a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
9888bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9898bfffbccSCorey Minyard     g_free(msg);
9908bfffbccSCorey Minyard 
9918bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9928bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
9938bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9948bfffbccSCorey Minyard 
9958bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9968bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9978bfffbccSCorey Minyard     }
9988bfffbccSCorey Minyard 
9998bfffbccSCorey Minyard out:
10008bfffbccSCorey Minyard     return;
10018bfffbccSCorey Minyard }
10028bfffbccSCorey Minyard 
10038bfffbccSCorey Minyard static unsigned char
ipmb_checksum(unsigned char * data,int size,unsigned char csum)10048bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10058bfffbccSCorey Minyard {
10068bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10078bfffbccSCorey Minyard             csum += *data;
10088bfffbccSCorey Minyard     }
10098bfffbccSCorey Minyard 
10108bfffbccSCorey Minyard     return -csum;
10118bfffbccSCorey Minyard }
10128bfffbccSCorey Minyard 
send_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)10138bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10148bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1015a580d820SCédric Le Goater                      RspBuffer *rsp)
10168bfffbccSCorey Minyard {
10178bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10188bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10198bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10208bfffbccSCorey Minyard     uint8_t *buf;
10218bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10228bfffbccSCorey Minyard 
10238bfffbccSCorey Minyard     if (cmd[2] != 0) {
10248bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
10256acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1026d13ada5dSCédric Le Goater         return;
10278bfffbccSCorey Minyard     }
10288bfffbccSCorey Minyard 
10294f298a4bSCédric Le Goater     if (cmd_len < 10) {
10306acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10314f298a4bSCédric Le Goater         return;
10324f298a4bSCédric Le Goater     }
10334f298a4bSCédric Le Goater 
10348bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10358bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10366acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1037d13ada5dSCédric Le Goater         return;
10388bfffbccSCorey Minyard     }
10398bfffbccSCorey Minyard 
10408bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10418bfffbccSCorey Minyard     cmd_len -= 3;
10428bfffbccSCorey Minyard 
10438bfffbccSCorey Minyard     /*
10448bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10458bfffbccSCorey Minyard      * be returned in the response.
10468bfffbccSCorey Minyard      */
10478bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10488bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1049d13ada5dSCédric Le Goater         return; /* No response */
10508bfffbccSCorey Minyard     }
10518bfffbccSCorey Minyard 
10528bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10538bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10548bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10558bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10568bfffbccSCorey Minyard 
10578bfffbccSCorey Minyard     if (rqLun != 2) {
10588bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1059d13ada5dSCédric Le Goater         return;
10608bfffbccSCorey Minyard     }
10618bfffbccSCorey Minyard 
10628bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10638bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10648bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10658bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10668bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10678bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10688bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10698bfffbccSCorey Minyard     msg->len = 6;
10708bfffbccSCorey Minyard 
10718bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10728bfffbccSCorey Minyard         /* Not a command we handle. */
10738bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10748bfffbccSCorey Minyard         goto end_msg;
10758bfffbccSCorey Minyard     }
10768bfffbccSCorey Minyard 
10778bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10788bfffbccSCorey Minyard     buf[0] = 0;
10798bfffbccSCorey Minyard     buf[1] = 0;
10808bfffbccSCorey Minyard     buf[2] = 0;
10818bfffbccSCorey Minyard     buf[3] = 0;
10828bfffbccSCorey Minyard     buf[4] = 0x51;
10838bfffbccSCorey Minyard     buf[5] = 0;
10848bfffbccSCorey Minyard     buf[6] = 0;
10858bfffbccSCorey Minyard     buf[7] = 0;
10868bfffbccSCorey Minyard     buf[8] = 0;
10878bfffbccSCorey Minyard     buf[9] = 0;
10888bfffbccSCorey Minyard     buf[10] = 0;
10898bfffbccSCorey Minyard     msg->len += 11;
10908bfffbccSCorey Minyard 
10918bfffbccSCorey Minyard  end_msg:
10928bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10938bfffbccSCorey Minyard     msg->len++;
10948bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10958bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10968bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10978bfffbccSCorey Minyard }
10988bfffbccSCorey Minyard 
do_watchdog_reset(IPMIBmcSim * ibs)10998bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11008bfffbccSCorey Minyard {
11018bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11028bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11038bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11048bfffbccSCorey Minyard         return;
11058bfffbccSCorey Minyard     }
11068bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11078bfffbccSCorey Minyard 
11088bfffbccSCorey Minyard 
11098bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11108bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11118bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11128bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11138bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11148bfffbccSCorey Minyard     }
11158bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11168bfffbccSCorey Minyard }
11178bfffbccSCorey Minyard 
reset_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11188bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11198bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1120a580d820SCédric Le Goater                                  RspBuffer *rsp)
11218bfffbccSCorey Minyard {
11228bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11236acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1124d13ada5dSCédric Le Goater         return;
11258bfffbccSCorey Minyard     }
11268bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11278bfffbccSCorey Minyard }
11288bfffbccSCorey Minyard 
set_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11298bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11308bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1131a580d820SCédric Le Goater                                RspBuffer *rsp)
11328bfffbccSCorey Minyard {
11338bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11348bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11358bfffbccSCorey Minyard     unsigned int val;
11368bfffbccSCorey Minyard 
11378bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11388bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1140d13ada5dSCédric Le Goater         return;
11418bfffbccSCorey Minyard     }
11428bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11438bfffbccSCorey Minyard     switch (val) {
11448bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11458bfffbccSCorey Minyard         break;
11468bfffbccSCorey Minyard 
11478bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11486acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11498bfffbccSCorey Minyard         break;
11508bfffbccSCorey Minyard 
11518bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11526acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11538bfffbccSCorey Minyard         break;
11548bfffbccSCorey Minyard 
11558bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11566acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11578bfffbccSCorey Minyard         break;
11588bfffbccSCorey Minyard 
11598bfffbccSCorey Minyard     default:
11606acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11618bfffbccSCorey Minyard     }
1162a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11636acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1164d13ada5dSCédric Le Goater         return;
11658bfffbccSCorey Minyard     }
11668bfffbccSCorey Minyard 
11678bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11688bfffbccSCorey Minyard     switch (val) {
11698bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11708bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11718bfffbccSCorey Minyard         break;
11728bfffbccSCorey Minyard 
11738bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11746af94767SCorey Minyard         if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11758bfffbccSCorey Minyard             /* NMI not supported. */
11766acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1177d13ada5dSCédric Le Goater             return;
11788bfffbccSCorey Minyard         }
117937eebb86SCorey Minyard         break;
118037eebb86SCorey Minyard 
11818bfffbccSCorey Minyard     default:
11828bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11836acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1184d13ada5dSCédric Le Goater         return;
11858bfffbccSCorey Minyard     }
11868bfffbccSCorey Minyard 
11878bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11888bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11898bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11908bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11918bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11928bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11938bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11948bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11958bfffbccSCorey Minyard     } else {
11968bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11978bfffbccSCorey Minyard     }
11988bfffbccSCorey Minyard }
11998bfffbccSCorey Minyard 
get_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12008bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12018bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1202a580d820SCédric Le Goater                                RspBuffer *rsp)
12038bfffbccSCorey Minyard {
1204a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1205a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1206a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1207a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
1208fb45770bSCorey Minyard     rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1209fb45770bSCorey Minyard     rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12108bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12118bfffbccSCorey Minyard         long timeout;
12128bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12138bfffbccSCorey Minyard                    / 100000000);
1214a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1215a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12168bfffbccSCorey Minyard     } else {
1217a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1218a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12198bfffbccSCorey Minyard     }
12208bfffbccSCorey Minyard }
12218bfffbccSCorey Minyard 
get_sdr_rep_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12228bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12238bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1224a580d820SCédric Le Goater                              RspBuffer *rsp)
12258bfffbccSCorey Minyard {
12268bfffbccSCorey Minyard     unsigned int i;
12278bfffbccSCorey Minyard 
1228a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1229a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1230a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1231a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1232a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
12338bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1234a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
12358bfffbccSCorey Minyard     }
12368bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1237a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
12388bfffbccSCorey Minyard     }
12398bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1240a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12418bfffbccSCorey Minyard }
12428bfffbccSCorey Minyard 
reserve_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12438bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12448bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1245a580d820SCédric Le Goater                             RspBuffer *rsp)
12468bfffbccSCorey Minyard {
1247a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1248a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12498bfffbccSCorey Minyard }
12508bfffbccSCorey Minyard 
get_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12518bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12528bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1253a580d820SCédric Le Goater                     RspBuffer *rsp)
12548bfffbccSCorey Minyard {
12558bfffbccSCorey Minyard     unsigned int pos;
12568bfffbccSCorey Minyard     uint16_t nextrec;
1257a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12588bfffbccSCorey Minyard 
12598bfffbccSCorey Minyard     if (cmd[6]) {
12607f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12616acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12627f996411SCédric Le Goater             return;
12638bfffbccSCorey Minyard         }
12647f996411SCédric Le Goater     }
12657f996411SCédric Le Goater 
12668bfffbccSCorey Minyard     pos = 0;
12678bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12688bfffbccSCorey Minyard                        &pos, &nextrec)) {
12696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1270d13ada5dSCédric Le Goater         return;
12718bfffbccSCorey Minyard     }
1272a2295f0aSCédric Le Goater 
1273a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1274a2295f0aSCédric Le Goater 
1275a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
12766acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1277d13ada5dSCédric Le Goater         return;
12788bfffbccSCorey Minyard     }
12798bfffbccSCorey Minyard 
1280a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1281a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
12828bfffbccSCorey Minyard 
12838bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1284a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12858bfffbccSCorey Minyard     }
12868bfffbccSCorey Minyard 
1287a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
12886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1289d13ada5dSCédric Le Goater         return;
12908bfffbccSCorey Minyard     }
1291a580d820SCédric Le Goater 
1292a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12938bfffbccSCorey Minyard }
12948bfffbccSCorey Minyard 
add_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12958bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12968bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1297a580d820SCédric Le Goater                     RspBuffer *rsp)
12988bfffbccSCorey Minyard {
12998bfffbccSCorey Minyard     uint16_t recid;
1300a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13018bfffbccSCorey Minyard 
1302a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13036acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1304d13ada5dSCédric Le Goater         return;
13058bfffbccSCorey Minyard     }
1306a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1307a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13088bfffbccSCorey Minyard }
13098bfffbccSCorey Minyard 
clear_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13108bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13118bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1312a580d820SCédric Le Goater                           RspBuffer *rsp)
13138bfffbccSCorey Minyard {
13147f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13156acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13167f996411SCédric Le Goater         return;
13177f996411SCédric Le Goater     }
13187f996411SCédric Le Goater 
13198bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13206acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1321d13ada5dSCédric Le Goater         return;
13228bfffbccSCorey Minyard     }
13238bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13248bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13258bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
13268bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1327a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13288bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
13298bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1330a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13318bfffbccSCorey Minyard     } else {
13326acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
13338bfffbccSCorey Minyard         return;
13348bfffbccSCorey Minyard     }
1335d13ada5dSCédric Le Goater }
13368bfffbccSCorey Minyard 
get_sel_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13378bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
13388bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1339a580d820SCédric Le Goater                          RspBuffer *rsp)
13408bfffbccSCorey Minyard {
13418bfffbccSCorey Minyard     unsigned int i, val;
13428bfffbccSCorey Minyard 
1343a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1344a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1345a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13468bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1347a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1348a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13498bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1350a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13518bfffbccSCorey Minyard     }
13528bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1353a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13548bfffbccSCorey Minyard     }
13558bfffbccSCorey Minyard     /* Only support Reserve SEL */
1356a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13578bfffbccSCorey Minyard }
13588bfffbccSCorey Minyard 
get_fru_area_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1359540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1360540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1361540c07d3SCédric Le Goater                          RspBuffer *rsp)
1362540c07d3SCédric Le Goater {
1363540c07d3SCédric Le Goater     uint8_t fruid;
1364540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1365540c07d3SCédric Le Goater 
1366540c07d3SCédric Le Goater     fruid = cmd[2];
1367540c07d3SCédric Le Goater 
1368540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1369540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1370540c07d3SCédric Le Goater         return;
1371540c07d3SCédric Le Goater     }
1372540c07d3SCédric Le Goater 
1373540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1374540c07d3SCédric Le Goater 
1375540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1376540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1377540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1378540c07d3SCédric Le Goater }
1379540c07d3SCédric Le Goater 
read_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1380540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1381540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1382540c07d3SCédric Le Goater                          RspBuffer *rsp)
1383540c07d3SCédric Le Goater {
1384540c07d3SCédric Le Goater     uint8_t fruid;
1385540c07d3SCédric Le Goater     uint16_t offset;
1386540c07d3SCédric Le Goater     int i;
1387540c07d3SCédric Le Goater     uint8_t *fru_entry;
1388540c07d3SCédric Le Goater     unsigned int count;
1389540c07d3SCédric Le Goater 
1390540c07d3SCédric Le Goater     fruid = cmd[2];
1391540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1392540c07d3SCédric Le Goater 
1393540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1394540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1395540c07d3SCédric Le Goater         return;
1396540c07d3SCédric Le Goater     }
1397540c07d3SCédric Le Goater 
1398540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1399540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1400540c07d3SCédric Le Goater         return;
1401540c07d3SCédric Le Goater     }
1402540c07d3SCédric Le Goater 
1403540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1404540c07d3SCédric Le Goater 
1405540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1406540c07d3SCédric Le Goater 
1407540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1408540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1409540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1410540c07d3SCédric Le Goater     }
1411540c07d3SCédric Le Goater }
1412540c07d3SCédric Le Goater 
write_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1413540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1414540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1415540c07d3SCédric Le Goater                          RspBuffer *rsp)
1416540c07d3SCédric Le Goater {
1417540c07d3SCédric Le Goater     uint8_t fruid;
1418540c07d3SCédric Le Goater     uint16_t offset;
1419540c07d3SCédric Le Goater     uint8_t *fru_entry;
1420540c07d3SCédric Le Goater     unsigned int count;
1421540c07d3SCédric Le Goater 
1422540c07d3SCédric Le Goater     fruid = cmd[2];
1423540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1424540c07d3SCédric Le Goater 
1425540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1426540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1427540c07d3SCédric Le Goater         return;
1428540c07d3SCédric Le Goater     }
1429540c07d3SCédric Le Goater 
1430540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1431540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1432540c07d3SCédric Le Goater         return;
1433540c07d3SCédric Le Goater     }
1434540c07d3SCédric Le Goater 
1435540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1436540c07d3SCédric Le Goater 
1437540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1438540c07d3SCédric Le Goater 
1439540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1440540c07d3SCédric Le Goater 
1441540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1442540c07d3SCédric Le Goater }
1443540c07d3SCédric Le Goater 
reserve_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)14448bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
14458bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1446a580d820SCédric Le Goater                         RspBuffer *rsp)
14478bfffbccSCorey Minyard {
1448a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1449a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
14508bfffbccSCorey Minyard }
14518bfffbccSCorey Minyard 
get_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)14528bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
14538bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1454a580d820SCédric Le Goater                           RspBuffer *rsp)
14558bfffbccSCorey Minyard {
14568bfffbccSCorey Minyard     unsigned int val;
14578bfffbccSCorey Minyard 
14588bfffbccSCorey Minyard     if (cmd[6]) {
14597f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
14606acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
14617f996411SCédric Le Goater             return;
14627f996411SCédric Le Goater         }
14638bfffbccSCorey Minyard     }
14648bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
14656acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1466d13ada5dSCédric Le Goater         return;
14678bfffbccSCorey Minyard     }
14688bfffbccSCorey Minyard     if (cmd[6] > 15) {
14696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1470d13ada5dSCédric Le Goater         return;
14718bfffbccSCorey Minyard     }
14728bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
14738bfffbccSCorey Minyard         cmd[7] = 16;
14748bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
14756acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1476d13ada5dSCédric Le Goater         return;
14778bfffbccSCorey Minyard     } else {
14788bfffbccSCorey Minyard         cmd[7] += cmd[6];
14798bfffbccSCorey Minyard     }
14808bfffbccSCorey Minyard 
14818bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
14828bfffbccSCorey Minyard     if (val == 0xffff) {
14838bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
14848bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
14856acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1486d13ada5dSCédric Le Goater         return;
14878bfffbccSCorey Minyard     }
14888bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1489a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1490a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
14918bfffbccSCorey Minyard     } else {
1492a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1493a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
14948bfffbccSCorey Minyard     }
14958bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1496a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
14978bfffbccSCorey Minyard     }
14988bfffbccSCorey Minyard }
14998bfffbccSCorey Minyard 
add_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15008bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15018bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1502a580d820SCédric Le Goater                           RspBuffer *rsp)
15038bfffbccSCorey Minyard {
15048bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1506d13ada5dSCédric Le Goater         return;
15078bfffbccSCorey Minyard     }
15088bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1509a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1510a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15118bfffbccSCorey Minyard }
15128bfffbccSCorey Minyard 
clear_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15138bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15148bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1515a580d820SCédric Le Goater                       RspBuffer *rsp)
15168bfffbccSCorey Minyard {
15177f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15186acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15197f996411SCédric Le Goater         return;
15207f996411SCédric Le Goater     }
15217f996411SCédric Le Goater 
15228bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15236acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1524d13ada5dSCédric Le Goater         return;
15258bfffbccSCorey Minyard     }
15268bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
15278bfffbccSCorey Minyard         ibs->sel.next_free = 0;
15288bfffbccSCorey Minyard         ibs->sel.overflow = 0;
15298bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1530a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15318bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
15328bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1533a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15348bfffbccSCorey Minyard     } else {
15356acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
15368bfffbccSCorey Minyard         return;
15378bfffbccSCorey Minyard     }
1538d13ada5dSCédric Le Goater }
15398bfffbccSCorey Minyard 
get_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15408bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
15418bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1542a580d820SCédric Le Goater                          RspBuffer *rsp)
15438bfffbccSCorey Minyard {
15448bfffbccSCorey Minyard     uint32_t val;
15458bfffbccSCorey Minyard     struct ipmi_time now;
15468bfffbccSCorey Minyard 
15478bfffbccSCorey Minyard     ipmi_gettime(&now);
15488bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1549a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1550a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1551a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1552a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
15538bfffbccSCorey Minyard }
15548bfffbccSCorey Minyard 
set_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15558bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
15568bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1557a580d820SCédric Le Goater                          RspBuffer *rsp)
15588bfffbccSCorey Minyard {
15598bfffbccSCorey Minyard     uint32_t val;
15608bfffbccSCorey Minyard     struct ipmi_time now;
15618bfffbccSCorey Minyard 
15628bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
15638bfffbccSCorey Minyard     ipmi_gettime(&now);
15648bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
15658bfffbccSCorey Minyard }
15668bfffbccSCorey Minyard 
platform_event_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15679380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
15689380d2edSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
15699380d2edSCorey Minyard                                RspBuffer *rsp)
15709380d2edSCorey Minyard {
15719380d2edSCorey Minyard     uint8_t event[16];
15729380d2edSCorey Minyard 
15739380d2edSCorey Minyard     event[2] = 2; /* System event record */
15749380d2edSCorey Minyard     event[7] = cmd[2]; /* Generator ID */
15759380d2edSCorey Minyard     event[8] = 0;
15769380d2edSCorey Minyard     event[9] = cmd[3]; /* EvMRev */
15779380d2edSCorey Minyard     event[10] = cmd[4]; /* Sensor type */
15789380d2edSCorey Minyard     event[11] = cmd[5]; /* Sensor number */
15799380d2edSCorey Minyard     event[12] = cmd[6]; /* Event dir / Event type */
15809380d2edSCorey Minyard     event[13] = cmd[7]; /* Event data 1 */
15819380d2edSCorey Minyard     event[14] = cmd[8]; /* Event data 2 */
15829380d2edSCorey Minyard     event[15] = cmd[9]; /* Event data 3 */
15839380d2edSCorey Minyard 
15849380d2edSCorey Minyard     if (sel_add_event(ibs, event)) {
15859380d2edSCorey Minyard         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
15869380d2edSCorey Minyard     }
15879380d2edSCorey Minyard }
15889380d2edSCorey Minyard 
set_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15898bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
15908bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1591a580d820SCédric Le Goater                                   RspBuffer *rsp)
15928bfffbccSCorey Minyard {
15938bfffbccSCorey Minyard     IPMISensor *sens;
15948bfffbccSCorey Minyard 
159573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15968bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1598d13ada5dSCédric Le Goater         return;
15998bfffbccSCorey Minyard     }
16008bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16018bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
16028bfffbccSCorey Minyard     case 0: /* Do not change */
16038bfffbccSCorey Minyard         break;
16048bfffbccSCorey Minyard     case 1: /* Enable bits */
16058bfffbccSCorey Minyard         if (cmd_len > 4) {
16068bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
16078bfffbccSCorey Minyard         }
16088bfffbccSCorey Minyard         if (cmd_len > 5) {
16098bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16108bfffbccSCorey Minyard         }
16118bfffbccSCorey Minyard         if (cmd_len > 6) {
16128bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16138bfffbccSCorey Minyard         }
16148bfffbccSCorey Minyard         if (cmd_len > 7) {
16158bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16168bfffbccSCorey Minyard         }
16178bfffbccSCorey Minyard         break;
16188bfffbccSCorey Minyard     case 2: /* Disable bits */
16198bfffbccSCorey Minyard         if (cmd_len > 4) {
16208bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16218bfffbccSCorey Minyard         }
16228bfffbccSCorey Minyard         if (cmd_len > 5) {
16238bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16248bfffbccSCorey Minyard         }
16258bfffbccSCorey Minyard         if (cmd_len > 6) {
16268bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
16278bfffbccSCorey Minyard         }
16288bfffbccSCorey Minyard         if (cmd_len > 7) {
16298bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
16308bfffbccSCorey Minyard         }
16318bfffbccSCorey Minyard         break;
16328bfffbccSCorey Minyard     case 3:
16336acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1634d13ada5dSCédric Le Goater         return;
16358bfffbccSCorey Minyard     }
16368bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
16378bfffbccSCorey Minyard }
16388bfffbccSCorey Minyard 
get_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16398bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
16408bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1641a580d820SCédric Le Goater                                   RspBuffer *rsp)
16428bfffbccSCorey Minyard {
16438bfffbccSCorey Minyard     IPMISensor *sens;
16448bfffbccSCorey Minyard 
164573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16468bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16476acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1648d13ada5dSCédric Le Goater         return;
16498bfffbccSCorey Minyard     }
16508bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1651a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1652a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1653a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1654a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1655a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
16568bfffbccSCorey Minyard }
16578bfffbccSCorey Minyard 
rearm_sensor_evts(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16588bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
16598bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1660a580d820SCédric Le Goater                               RspBuffer *rsp)
16618bfffbccSCorey Minyard {
16628bfffbccSCorey Minyard     IPMISensor *sens;
16638bfffbccSCorey Minyard 
166473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16658bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16666acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1667d13ada5dSCédric Le Goater         return;
16688bfffbccSCorey Minyard     }
16698bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16708bfffbccSCorey Minyard 
16718bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
16728bfffbccSCorey Minyard         /* Just clear everything */
16738bfffbccSCorey Minyard         sens->states = 0;
16748bfffbccSCorey Minyard         return;
16758bfffbccSCorey Minyard     }
1676d13ada5dSCédric Le Goater }
16778bfffbccSCorey Minyard 
get_sensor_evt_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16788bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
16798bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1680a580d820SCédric Le Goater                                   RspBuffer *rsp)
16818bfffbccSCorey Minyard {
16828bfffbccSCorey Minyard     IPMISensor *sens;
16838bfffbccSCorey Minyard 
168473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16858bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16866acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1687d13ada5dSCédric Le Goater         return;
16888bfffbccSCorey Minyard     }
16898bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1690a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1691a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1692a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1693a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1694a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1695a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
16968bfffbccSCorey Minyard }
16978bfffbccSCorey Minyard 
get_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16988bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
16998bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1700a580d820SCédric Le Goater                                RspBuffer *rsp)
17018bfffbccSCorey Minyard {
17028bfffbccSCorey Minyard     IPMISensor *sens;
17038bfffbccSCorey Minyard 
170473d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17058bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17066acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1707d13ada5dSCédric Le Goater         return;
17088bfffbccSCorey Minyard     }
17098bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1710a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1711a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1712a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17138bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1714a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17158bfffbccSCorey Minyard     }
17168bfffbccSCorey Minyard }
17178bfffbccSCorey Minyard 
set_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1718728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1719728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1720a580d820SCédric Le Goater                             RspBuffer *rsp)
1721728710e1SCédric Le Goater {
1722728710e1SCédric Le Goater     IPMISensor *sens;
1723728710e1SCédric Le Goater 
1724728710e1SCédric Le Goater 
172573d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1726728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17276acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1728728710e1SCédric Le Goater         return;
1729728710e1SCédric Le Goater     }
1730728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1731728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1732728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1733728710e1SCédric Le Goater }
1734728710e1SCédric Le Goater 
get_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1735728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1736728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1737a580d820SCédric Le Goater                             RspBuffer *rsp)
1738728710e1SCédric Le Goater {
1739728710e1SCédric Le Goater     IPMISensor *sens;
1740728710e1SCédric Le Goater 
1741728710e1SCédric Le Goater 
174273d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1743728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17446acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1745728710e1SCédric Le Goater         return;
1746728710e1SCédric Le Goater     }
1747728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1748a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1749a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1750728710e1SCédric Le Goater }
1751728710e1SCédric Le Goater 
1752e3f7320cSCédric Le Goater /*
1753e3f7320cSCédric Le Goater  * bytes   parameter
1754e3f7320cSCédric Le Goater  *    1    sensor number
1755e3f7320cSCédric Le Goater  *    2    operation (see below for bits meaning)
1756e3f7320cSCédric Le Goater  *    3    sensor reading
1757e3f7320cSCédric Le Goater  *  4:5    assertion states (optional)
1758e3f7320cSCédric Le Goater  *  6:7    deassertion states (optional)
1759e3f7320cSCédric Le Goater  *  8:10   event data 1,2,3 (optional)
1760e3f7320cSCédric Le Goater  */
set_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1761e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs,
1762e3f7320cSCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1763e3f7320cSCédric Le Goater                                RspBuffer *rsp)
1764e3f7320cSCédric Le Goater {
1765e3f7320cSCédric Le Goater     IPMISensor *sens;
1766e3f7320cSCédric Le Goater     uint8_t evd1 = 0;
1767e3f7320cSCédric Le Goater     uint8_t evd2 = 0;
1768e3f7320cSCédric Le Goater     uint8_t evd3 = 0;
1769e3f7320cSCédric Le Goater     uint8_t new_reading = 0;
1770e3f7320cSCédric Le Goater     uint16_t new_assert_states = 0;
1771e3f7320cSCédric Le Goater     uint16_t new_deassert_states = 0;
1772e3f7320cSCédric Le Goater     bool change_reading = false;
1773e3f7320cSCédric Le Goater     bool change_assert = false;
1774e3f7320cSCédric Le Goater     bool change_deassert = false;
1775e3f7320cSCédric Le Goater     enum {
1776e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_NONE,
1777e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_DATA,
1778e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_BMC,
1779e3f7320cSCédric Le Goater     } do_gen_event = SENSOR_GEN_EVENT_NONE;
1780e3f7320cSCédric Le Goater 
1781e3f7320cSCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1782e3f7320cSCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1783e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1784e3f7320cSCédric Le Goater         return;
1785e3f7320cSCédric Le Goater     }
1786e3f7320cSCédric Le Goater 
1787e3f7320cSCédric Le Goater     sens = ibs->sensors + cmd[2];
1788e3f7320cSCédric Le Goater 
1789e3f7320cSCédric Le Goater     /* [1:0] Sensor Reading operation */
1790e3f7320cSCédric Le Goater     switch ((cmd[3]) & 0x3) {
1791e3f7320cSCédric Le Goater     case 0: /* Do not change */
1792e3f7320cSCédric Le Goater         break;
1793e3f7320cSCédric Le Goater     case 1: /* write given value to sensor reading byte */
1794e3f7320cSCédric Le Goater         new_reading = cmd[4];
1795e3f7320cSCédric Le Goater         if (sens->reading != new_reading) {
1796e3f7320cSCédric Le Goater             change_reading = true;
1797e3f7320cSCédric Le Goater         }
1798e3f7320cSCédric Le Goater         break;
1799e3f7320cSCédric Le Goater     case 2:
1800e3f7320cSCédric Le Goater     case 3:
1801e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1802e3f7320cSCédric Le Goater         return;
1803e3f7320cSCédric Le Goater     }
1804e3f7320cSCédric Le Goater 
1805e3f7320cSCédric Le Goater     /* [3:2] Deassertion bits operation */
1806e3f7320cSCédric Le Goater     switch ((cmd[3] >> 2) & 0x3) {
1807e3f7320cSCédric Le Goater     case 0: /* Do not change */
1808e3f7320cSCédric Le Goater         break;
1809e3f7320cSCédric Le Goater     case 1: /* write given value */
1810e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1811e3f7320cSCédric Le Goater             new_deassert_states = cmd[7];
1812e3f7320cSCédric Le Goater             change_deassert = true;
1813e3f7320cSCédric Le Goater         }
1814e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1815e3f7320cSCédric Le Goater             new_deassert_states |= (cmd[8] << 8);
1816e3f7320cSCédric Le Goater         }
1817e3f7320cSCédric Le Goater         break;
1818e3f7320cSCédric Le Goater 
1819e3f7320cSCédric Le Goater     case 2: /* mask on */
1820e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1821e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states | cmd[7]);
1822e3f7320cSCédric Le Goater             change_deassert = true;
1823e3f7320cSCédric Le Goater         }
1824e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1825e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1826e3f7320cSCédric Le Goater         }
1827e3f7320cSCédric Le Goater         break;
1828e3f7320cSCédric Le Goater 
1829e3f7320cSCédric Le Goater     case 3: /* mask off */
1830e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1831e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states & cmd[7]);
1832e3f7320cSCédric Le Goater             change_deassert = true;
1833e3f7320cSCédric Le Goater         }
1834e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1835e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1836e3f7320cSCédric Le Goater         }
1837e3f7320cSCédric Le Goater         break;
1838e3f7320cSCédric Le Goater     }
1839e3f7320cSCédric Le Goater 
1840e3f7320cSCédric Le Goater     if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1841e3f7320cSCédric Le Goater         change_deassert = false;
1842e3f7320cSCédric Le Goater     }
1843e3f7320cSCédric Le Goater 
1844e3f7320cSCédric Le Goater     /* [5:4] Assertion bits operation */
1845e3f7320cSCédric Le Goater     switch ((cmd[3] >> 4) & 0x3) {
1846e3f7320cSCédric Le Goater     case 0: /* Do not change */
1847e3f7320cSCédric Le Goater         break;
1848e3f7320cSCédric Le Goater     case 1: /* write given value */
1849e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1850e3f7320cSCédric Le Goater             new_assert_states = cmd[5];
1851e3f7320cSCédric Le Goater             change_assert = true;
1852e3f7320cSCédric Le Goater         }
1853e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1854e3f7320cSCédric Le Goater             new_assert_states |= (cmd[6] << 8);
1855e3f7320cSCédric Le Goater         }
1856e3f7320cSCédric Le Goater         break;
1857e3f7320cSCédric Le Goater 
1858e3f7320cSCédric Le Goater     case 2: /* mask on */
1859e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1860e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states | cmd[5]);
1861e3f7320cSCédric Le Goater             change_assert = true;
1862e3f7320cSCédric Le Goater         }
1863e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1864e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1865e3f7320cSCédric Le Goater         }
1866e3f7320cSCédric Le Goater         break;
1867e3f7320cSCédric Le Goater 
1868e3f7320cSCédric Le Goater     case 3: /* mask off */
1869e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1870e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states & cmd[5]);
1871e3f7320cSCédric Le Goater             change_assert = true;
1872e3f7320cSCédric Le Goater         }
1873e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1874e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1875e3f7320cSCédric Le Goater         }
1876e3f7320cSCédric Le Goater         break;
1877e3f7320cSCédric Le Goater     }
1878e3f7320cSCédric Le Goater 
1879e3f7320cSCédric Le Goater     if (change_assert && (new_assert_states == sens->assert_states)) {
1880e3f7320cSCédric Le Goater         change_assert = false;
1881e3f7320cSCédric Le Goater     }
1882e3f7320cSCédric Le Goater 
1883e3f7320cSCédric Le Goater     if (cmd_len > 9) {
1884e3f7320cSCédric Le Goater         evd1 = cmd[9];
1885e3f7320cSCédric Le Goater     }
1886e3f7320cSCédric Le Goater     if (cmd_len > 10) {
1887e3f7320cSCédric Le Goater         evd2 = cmd[10];
1888e3f7320cSCédric Le Goater     }
1889e3f7320cSCédric Le Goater     if (cmd_len > 11) {
1890e3f7320cSCédric Le Goater         evd3 = cmd[11];
1891e3f7320cSCédric Le Goater     }
1892e3f7320cSCédric Le Goater 
1893e3f7320cSCédric Le Goater     /* [7:6] Event Data Bytes operation */
1894e3f7320cSCédric Le Goater     switch ((cmd[3] >> 6) & 0x3) {
1895e3f7320cSCédric Le Goater     case 0: /*
1896e3f7320cSCédric Le Goater              * Don’t use Event Data bytes from this command. BMC will
1897e3f7320cSCédric Le Goater              * generate it's own Event Data bytes based on its sensor
1898e3f7320cSCédric Le Goater              * implementation.
1899e3f7320cSCédric Le Goater              */
1900e3f7320cSCédric Le Goater         evd1 = evd2 = evd3 = 0x0;
1901e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_BMC;
1902e3f7320cSCédric Le Goater         break;
1903e3f7320cSCédric Le Goater     case 1: /*
1904e3f7320cSCédric Le Goater              * Write given values to event data bytes including bits
1905e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1906e3f7320cSCédric Le Goater              */
1907e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1908e3f7320cSCédric Le Goater         break;
1909e3f7320cSCédric Le Goater     case 2: /*
1910e3f7320cSCédric Le Goater              * Write given values to event data bytes excluding bits
1911e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1912e3f7320cSCédric Le Goater              */
1913e3f7320cSCédric Le Goater         evd1 &= 0xf0;
1914e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1915e3f7320cSCédric Le Goater         break;
1916e3f7320cSCédric Le Goater     case 3:
1917e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1918e3f7320cSCédric Le Goater         return;
1919e3f7320cSCédric Le Goater     }
1920e3f7320cSCédric Le Goater 
1921e3f7320cSCédric Le Goater     /*
1922e3f7320cSCédric Le Goater      * Event Data Bytes operation and parameter are inconsistent. The
1923e3f7320cSCédric Le Goater      * Specs are not clear on that topic but generating an error seems
1924e3f7320cSCédric Le Goater      * correct.
1925e3f7320cSCédric Le Goater      */
1926e3f7320cSCédric Le Goater     if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
1927e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1928e3f7320cSCédric Le Goater         return;
1929e3f7320cSCédric Le Goater     }
1930e3f7320cSCédric Le Goater 
1931e3f7320cSCédric Le Goater     /* commit values */
1932e3f7320cSCédric Le Goater     if (change_reading) {
1933e3f7320cSCédric Le Goater         sens->reading = new_reading;
1934e3f7320cSCédric Le Goater     }
1935e3f7320cSCédric Le Goater 
1936e3f7320cSCédric Le Goater     if (change_assert) {
1937e3f7320cSCédric Le Goater         sens->assert_states = new_assert_states;
1938e3f7320cSCédric Le Goater     }
1939e3f7320cSCédric Le Goater 
1940e3f7320cSCédric Le Goater     if (change_deassert) {
1941e3f7320cSCédric Le Goater         sens->deassert_states = new_deassert_states;
1942e3f7320cSCédric Le Goater     }
1943e3f7320cSCédric Le Goater 
1944e3f7320cSCédric Le Goater     /* TODO: handle threshold sensor */
1945e3f7320cSCédric Le Goater     if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
1946e3f7320cSCédric Le Goater         return;
1947e3f7320cSCédric Le Goater     }
1948e3f7320cSCédric Le Goater 
1949e3f7320cSCédric Le Goater     switch (do_gen_event) {
1950e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_DATA: {
1951e3f7320cSCédric Le Goater         unsigned int bit = evd1 & 0xf;
1952e3f7320cSCédric Le Goater         uint16_t mask = (1 << bit);
1953e3f7320cSCédric Le Goater 
1954e3f7320cSCédric Le Goater         if (sens->assert_states & mask & sens->assert_enable) {
1955e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
1956e3f7320cSCédric Le Goater         }
1957e3f7320cSCédric Le Goater 
1958e3f7320cSCédric Le Goater         if (sens->deassert_states & mask & sens->deassert_enable) {
1959e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
1960e3f7320cSCédric Le Goater         }
1961e3f7320cSCédric Le Goater         break;
1962e3f7320cSCédric Le Goater     }
1963e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_BMC:
1964e3f7320cSCédric Le Goater         /*
1965e3f7320cSCédric Le Goater          * TODO: generate event and event data bytes depending on the
1966e3f7320cSCédric Le Goater          * sensor
1967e3f7320cSCédric Le Goater          */
1968e3f7320cSCédric Le Goater         break;
1969e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_NONE:
1970e3f7320cSCédric Le Goater         break;
1971e3f7320cSCédric Le Goater     }
1972e3f7320cSCédric Le Goater }
1973728710e1SCédric Le Goater 
197462a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
19754f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
19764f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
19774f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
19784f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
19798bfffbccSCorey Minyard };
19808bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
198162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
19828bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
19838bfffbccSCorey Minyard };
19848bfffbccSCorey Minyard 
198562a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
19869380d2edSCorey Minyard     [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
19874f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
19884f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
19894f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
19904f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
19914f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
19924f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
19934f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
1994e3f7320cSCédric Le Goater     [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
19958bfffbccSCorey Minyard };
19968bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
199762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
19988bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
19998bfffbccSCorey Minyard };
20008bfffbccSCorey Minyard 
200162a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
20024f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
20034f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
20044f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
20054f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
20064f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
20074f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
20084f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
20094f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
20104f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
20114f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
20124f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
20134f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
20144f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
20154f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
20164f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
20174f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
20188bfffbccSCorey Minyard };
20198bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
202062a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
20218bfffbccSCorey Minyard     .cmd_handlers = app_cmds
20228bfffbccSCorey Minyard };
20238bfffbccSCorey Minyard 
202462a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
2025540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2026540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2027540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
20284f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
20294f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
20304f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
20314f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
20324f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
20334f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
20344f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
20354f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
20364f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
20374f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
20387f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
20397f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
20408bfffbccSCorey Minyard };
20418bfffbccSCorey Minyard 
20428bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
204362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
20448bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
20458bfffbccSCorey Minyard };
20468bfffbccSCorey Minyard 
register_cmds(IPMIBmcSim * s)20478bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
20488bfffbccSCorey Minyard {
2049ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2050ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2051ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2052ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
20538bfffbccSCorey Minyard }
20548bfffbccSCorey Minyard 
20555167560bSCédric Le Goater static uint8_t init_sdrs[] = {
20568bfffbccSCorey Minyard     /* Watchdog device */
20578bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
20588bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
20598bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20608bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
20618bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
20628bfffbccSCorey Minyard };
20638bfffbccSCorey Minyard 
ipmi_sdr_init(IPMIBmcSim * ibs)20644fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
20654fa9f08eSCédric Le Goater {
20664fa9f08eSCédric Le Goater     unsigned int i;
20674fa9f08eSCédric Le Goater     int len;
20685167560bSCédric Le Goater     size_t sdrs_size;
20695167560bSCédric Le Goater     uint8_t *sdrs;
207052fc01d9SCédric Le Goater 
20715167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
20725167560bSCédric Le Goater     sdrs = init_sdrs;
20738c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
20748c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
20758c6fd7f3SCédric Le Goater                              NULL)) {
20768c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
20778c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
20788c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
20798c6fd7f3SCédric Le Goater     }
20805167560bSCédric Le Goater 
20815167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
208252fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
208352fc01d9SCédric Le Goater 
20845167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
20854fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
20868c6fd7f3SCédric Le Goater             break;
20874fa9f08eSCédric Le Goater         }
20885167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
20894fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
20905167560bSCédric Le Goater         if (i + len > sdrs_size) {
20914fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
20928c6fd7f3SCédric Le Goater             break;
20934fa9f08eSCédric Le Goater         }
20944fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
20954fa9f08eSCédric Le Goater     }
20968c6fd7f3SCédric Le Goater 
20978c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
20988c6fd7f3SCédric Le Goater         g_free(sdrs);
20998c6fd7f3SCédric Le Goater     }
21004fa9f08eSCédric Le Goater }
21014fa9f08eSCédric Le Goater 
2102bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
2103bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
2104bd66bcfcSCorey Minyard     .version_id = 1,
2105bd66bcfcSCorey Minyard     .minimum_version_id = 1,
2106*09c6ac6dSRichard Henderson     .fields = (const VMStateField[]) {
2107bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2108bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2109bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2110bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2111bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2112bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
21139e744990SJinhua Cao         VMSTATE_UINT8(watchdog_expired, IPMIBmcSim),
2114bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2115bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2116bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2117bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2118bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2119bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2120bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2121bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2122bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2123bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2124bd66bcfcSCorey Minyard                        IPMIBmcSim),
2125bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2126bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
2127bd66bcfcSCorey Minyard     }
2128bd66bcfcSCorey Minyard };
2129bd66bcfcSCorey Minyard 
ipmi_fru_init(IPMIFru * fru)2130540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
2131540c07d3SCédric Le Goater {
2132540c07d3SCédric Le Goater     int fsize;
2133540c07d3SCédric Le Goater     int size = 0;
2134540c07d3SCédric Le Goater 
2135540c07d3SCédric Le Goater     if (!fru->filename) {
2136540c07d3SCédric Le Goater         goto out;
2137540c07d3SCédric Le Goater     }
2138540c07d3SCédric Le Goater 
2139540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
2140540c07d3SCédric Le Goater     if (fsize > 0) {
2141540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
2142540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2143540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2144540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
2145540c07d3SCédric Le Goater             g_free(fru->data);
2146540c07d3SCédric Le Goater             fru->data = NULL;
2147540c07d3SCédric Le Goater         }
2148540c07d3SCédric Le Goater     }
2149540c07d3SCédric Le Goater 
2150540c07d3SCédric Le Goater out:
2151540c07d3SCédric Le Goater     if (!fru->data) {
2152540c07d3SCédric Le Goater         /* give one default FRU */
2153540c07d3SCédric Le Goater         size = fru->areasize;
2154540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2155540c07d3SCédric Le Goater     }
2156540c07d3SCédric Le Goater 
2157540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
2158540c07d3SCédric Le Goater }
2159540c07d3SCédric Le Goater 
ipmi_sim_realize(DeviceState * dev,Error ** errp)21600bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
21618bfffbccSCorey Minyard {
21620bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
21638bfffbccSCorey Minyard     unsigned int i;
21648bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
21658bfffbccSCorey Minyard 
21668bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
21678bfffbccSCorey Minyard 
21688bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
21698bfffbccSCorey Minyard     ibs->device_id = 0x20;
21708bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
2171b7088392SCédric Le Goater     ibs->restart_cause = 0;
21728bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
21738bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
21748bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
21758bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
21768bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
21778bfffbccSCorey Minyard     }
21788bfffbccSCorey Minyard 
21794fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
21808bfffbccSCorey Minyard 
2181540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
2182540c07d3SCédric Le Goater 
218352ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
218452ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
218552ba4d50SCédric Le Goater 
21868bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
21878bfffbccSCorey Minyard     register_cmds(ibs);
21888bfffbccSCorey Minyard 
21898bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
2190bd66bcfcSCorey Minyard 
2191bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
21928bfffbccSCorey Minyard }
21938bfffbccSCorey Minyard 
21948c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = {
2195540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2196540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
21978c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
219820b23364SCorey Minyard     DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
219920b23364SCorey Minyard     DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
220020b23364SCorey Minyard     DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
220120b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
220220b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
220320b23364SCorey Minyard     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
220420b23364SCorey Minyard     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
22057b0cd78bSCorey Minyard     DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
22068c6fd7f3SCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
22078c6fd7f3SCédric Le Goater };
22088c6fd7f3SCédric Le Goater 
ipmi_sim_class_init(ObjectClass * oc,void * data)22098bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
22108bfffbccSCorey Minyard {
22110bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
22128bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
22138bfffbccSCorey Minyard 
221466abfddbSCorey Minyard     dc->hotpluggable = false;
22150bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
22164f67d30bSMarc-André Lureau     device_class_set_props(dc, ipmi_sim_properties);
22178bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
22188bfffbccSCorey Minyard }
22198bfffbccSCorey Minyard 
22208bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
22218bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
22228bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
22238bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
22248bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
22258bfffbccSCorey Minyard };
22268bfffbccSCorey Minyard 
ipmi_sim_register_types(void)22278bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
22288bfffbccSCorey Minyard {
22298bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
22308bfffbccSCorey Minyard }
22318bfffbccSCorey Minyard 
22328bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2233