xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 7b0cd78bf72368b71e6ffa7a8b8f5e57a2e65b5d)
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"
33d6454270SMarkus Armbruster #include "migration/vmstate.h"
348bfffbccSCorey Minyard 
358bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
368bfffbccSCorey Minyard 
378bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
388bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
398bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
40b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
418bfffbccSCorey Minyard 
428bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
438bfffbccSCorey Minyard 
449380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG       0x02
458bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
468bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
478bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
488bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
498bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
50728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
51728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
528bfffbccSCorey Minyard 
538bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
548bfffbccSCorey Minyard 
558bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
568bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
578bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
5852ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
5952ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
6052ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
618bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
628bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
638bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
648bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
658bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
668bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
678bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
688bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
698bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
708bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
718bfffbccSCorey Minyard 
728bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
738bfffbccSCorey Minyard 
748bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
758bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
768bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
788bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
798bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
808bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
818bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
828bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
838bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
848bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
858bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
868bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
87540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO        0x10
88540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA            0x11
89540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA           0x12
908bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
918bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
928bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
948bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
958bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
968bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
978bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
988bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
998bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
1008bfffbccSCorey Minyard 
1018bfffbccSCorey Minyard 
1028bfffbccSCorey Minyard /* Same as a timespec struct. */
1038bfffbccSCorey Minyard struct ipmi_time {
1048bfffbccSCorey Minyard     long tv_sec;
1058bfffbccSCorey Minyard     long tv_nsec;
1068bfffbccSCorey Minyard };
1078bfffbccSCorey Minyard 
1088bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1098bfffbccSCorey Minyard 
1108bfffbccSCorey Minyard typedef struct IPMISel {
1118bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1128bfffbccSCorey Minyard     unsigned int next_free;
1138bfffbccSCorey Minyard     long time_offset;
1148bfffbccSCorey Minyard     uint16_t reservation;
1158bfffbccSCorey Minyard     uint8_t last_addition[4];
1168bfffbccSCorey Minyard     uint8_t last_clear[4];
1178bfffbccSCorey Minyard     uint8_t overflow;
1188bfffbccSCorey Minyard } IPMISel;
1198bfffbccSCorey Minyard 
1208bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1218bfffbccSCorey Minyard 
1228bfffbccSCorey Minyard typedef struct IPMISdr {
1238bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1248bfffbccSCorey Minyard     unsigned int next_free;
1258bfffbccSCorey Minyard     uint16_t next_rec_id;
1268bfffbccSCorey Minyard     uint16_t reservation;
1278bfffbccSCorey Minyard     uint8_t last_addition[4];
1288bfffbccSCorey Minyard     uint8_t last_clear[4];
1298bfffbccSCorey Minyard     uint8_t overflow;
1308bfffbccSCorey Minyard } IPMISdr;
1318bfffbccSCorey Minyard 
132540c07d3SCédric Le Goater typedef struct IPMIFru {
133540c07d3SCédric Le Goater     char *filename;
134540c07d3SCédric Le Goater     unsigned int nentries;
135540c07d3SCédric Le Goater     uint16_t areasize;
136540c07d3SCédric Le Goater     uint8_t *data;
137540c07d3SCédric Le Goater } IPMIFru;
138540c07d3SCédric Le Goater 
1398bfffbccSCorey Minyard typedef struct IPMISensor {
1408bfffbccSCorey Minyard     uint8_t status;
1418bfffbccSCorey Minyard     uint8_t reading;
1428bfffbccSCorey Minyard     uint16_t states_suppt;
1438bfffbccSCorey Minyard     uint16_t assert_suppt;
1448bfffbccSCorey Minyard     uint16_t deassert_suppt;
1458bfffbccSCorey Minyard     uint16_t states;
1468bfffbccSCorey Minyard     uint16_t assert_states;
1478bfffbccSCorey Minyard     uint16_t deassert_states;
1488bfffbccSCorey Minyard     uint16_t assert_enable;
1498bfffbccSCorey Minyard     uint16_t deassert_enable;
1508bfffbccSCorey Minyard     uint8_t  sensor_type;
1518bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1528bfffbccSCorey Minyard } IPMISensor;
1538bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1548bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1558bfffbccSCorey Minyard                                              !!(v))
1568bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1578bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1588bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1598bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1608bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1618bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1628bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1638bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1648bfffbccSCorey Minyard                                              (v & 0xc0))
1658bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1668bfffbccSCorey Minyard 
1678bfffbccSCorey Minyard #define MAX_SENSORS 20
1688bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1698bfffbccSCorey Minyard 
1708bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
171a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer;
1728bfffbccSCorey Minyard 
1738bfffbccSCorey Minyard #define MAX_NETFNS 64
1744f298a4bSCédric Le Goater 
1754f298a4bSCédric Le Goater typedef struct IPMICmdHandler {
1764f298a4bSCédric Le Goater     void (*cmd_handler)(IPMIBmcSim *s,
1778bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
178a580d820SCédric Le Goater                         RspBuffer *rsp);
1794f298a4bSCédric Le Goater     unsigned int cmd_len_min;
1804f298a4bSCédric Le Goater } IPMICmdHandler;
1814f298a4bSCédric Le Goater 
1828bfffbccSCorey Minyard typedef struct IPMINetfn {
1838bfffbccSCorey Minyard     unsigned int cmd_nums;
1848bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1858bfffbccSCorey Minyard } IPMINetfn;
1868bfffbccSCorey Minyard 
1878bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1888bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1898bfffbccSCorey Minyard     uint8_t len;
1908bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1918bfffbccSCorey Minyard } IPMIRcvBufEntry;
1928bfffbccSCorey Minyard 
1938bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1948bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1958bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1968bfffbccSCorey Minyard struct IPMIBmcSim {
1978bfffbccSCorey Minyard     IPMIBmc parent;
1988bfffbccSCorey Minyard 
1998bfffbccSCorey Minyard     QEMUTimer *timer;
2008bfffbccSCorey Minyard 
2018bfffbccSCorey Minyard     uint8_t bmc_global_enables;
2028bfffbccSCorey Minyard     uint8_t msg_flags;
2038bfffbccSCorey Minyard 
2048bfffbccSCorey Minyard     bool     watchdog_initialized;
2058bfffbccSCorey Minyard     uint8_t  watchdog_use;
2068bfffbccSCorey Minyard     uint8_t  watchdog_action;
2078bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
2088bfffbccSCorey Minyard     bool     watchdog_expired;
2098bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
2108bfffbccSCorey Minyard 
2118bfffbccSCorey Minyard     bool     watchdog_running;
2128bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
2138bfffbccSCorey Minyard     int64_t  watchdog_expiry;
2148bfffbccSCorey Minyard 
2158bfffbccSCorey Minyard     uint8_t device_id;
2168bfffbccSCorey Minyard     uint8_t ipmi_version;
2178bfffbccSCorey Minyard     uint8_t device_rev;
2188bfffbccSCorey Minyard     uint8_t fwrev1;
2198bfffbccSCorey Minyard     uint8_t fwrev2;
22020b23364SCorey Minyard     uint32_t mfg_id;
22120b23364SCorey Minyard     uint16_t product_id;
2228bfffbccSCorey Minyard 
223b7088392SCédric Le Goater     uint8_t restart_cause;
224b7088392SCédric Le Goater 
22552ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
226*7b0cd78bSCorey Minyard     QemuUUID uuid;
22752ba4d50SCédric Le Goater 
2288bfffbccSCorey Minyard     IPMISel sel;
2298bfffbccSCorey Minyard     IPMISdr sdr;
230540c07d3SCédric Le Goater     IPMIFru fru;
2318bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2328c6fd7f3SCédric Le Goater     char *sdr_filename;
2338bfffbccSCorey Minyard 
2348bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2358bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2368bfffbccSCorey Minyard 
2378bfffbccSCorey Minyard     /* We allow one event in the buffer */
2388bfffbccSCorey Minyard     uint8_t evtbuf[16];
2398bfffbccSCorey Minyard 
2408bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2418bfffbccSCorey Minyard };
2428bfffbccSCorey Minyard 
2438bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2448bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2458bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2468bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2478bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2488bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2498bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2508bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2518bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2528bfffbccSCorey Minyard 
2538bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2548bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2558bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2568bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2578bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2588bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2598bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2608bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2618bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2628bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2638bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2648bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2658bfffbccSCorey Minyard 
2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2678bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2688bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2698bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2708bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2718bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2728bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2738bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2748bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2758bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2768bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2778bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2788bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2798bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2808bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2818bfffbccSCorey Minyard 
282a580d820SCédric Le Goater struct RspBuffer {
283a580d820SCédric Le Goater     uint8_t buffer[MAX_IPMI_MSG_SIZE];
284a580d820SCédric Le Goater     unsigned int len;
285a580d820SCédric Le Goater };
286a580d820SCédric Le Goater 
287a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2888bfffbccSCorey Minyard 
2896acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
2906acb971aSCédric Le Goater {
2916acb971aSCédric Le Goater     rsp->buffer[2] = byte;
2926acb971aSCédric Le Goater }
2936acb971aSCédric Le Goater 
2948bfffbccSCorey Minyard /* Add a byte to the response. */
295a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
296a580d820SCédric Le Goater {
297a580d820SCédric Le Goater     if (rsp->len >= sizeof(rsp->buffer)) {
2986acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
299a580d820SCédric Le Goater         return;
300a580d820SCédric Le Goater     }
301a580d820SCédric Le Goater     rsp->buffer[rsp->len++] = byte;
302a580d820SCédric Le Goater }
303a580d820SCédric Le Goater 
304a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
305a580d820SCédric Le Goater                                        unsigned int n)
306a580d820SCédric Le Goater {
307a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
3086acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
309a580d820SCédric Le Goater         return;
310a580d820SCédric Le Goater     }
311a580d820SCédric Le Goater 
312a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
313a580d820SCédric Le Goater     rsp->len += n;
314a580d820SCédric Le Goater }
3158bfffbccSCorey Minyard 
3168bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
3178bfffbccSCorey Minyard 
3188bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
3198bfffbccSCorey Minyard {
3208bfffbccSCorey Minyard     int64_t stime;
3218bfffbccSCorey Minyard 
3228bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
3238bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
3248bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
3258bfffbccSCorey Minyard }
3268bfffbccSCorey Minyard 
3278bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3288bfffbccSCorey Minyard {
3298bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3308bfffbccSCorey Minyard }
3318bfffbccSCorey Minyard 
3328bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3338bfffbccSCorey Minyard {
3348bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3358bfffbccSCorey Minyard 
3368bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3378bfffbccSCorey Minyard }
3388bfffbccSCorey Minyard 
3398bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3408bfffbccSCorey Minyard {
3418bfffbccSCorey Minyard     unsigned int val;
3428bfffbccSCorey Minyard     struct ipmi_time now;
3438bfffbccSCorey Minyard 
3448bfffbccSCorey Minyard     ipmi_gettime(&now);
3458bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3468bfffbccSCorey Minyard     ts[0] = val & 0xff;
3478bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3488bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3498bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3508bfffbccSCorey Minyard }
3518bfffbccSCorey Minyard 
3528bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3538bfffbccSCorey Minyard {
3548bfffbccSCorey Minyard     sdr->reservation++;
3558bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3568bfffbccSCorey Minyard         sdr->reservation = 1;
3578bfffbccSCorey Minyard     }
3588bfffbccSCorey Minyard }
3598bfffbccSCorey Minyard 
360a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
361a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3628bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3638bfffbccSCorey Minyard {
364a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
365a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
366a2295f0aSCédric Le Goater 
367a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3688bfffbccSCorey Minyard         return 1;
3698bfffbccSCorey Minyard     }
3708bfffbccSCorey Minyard 
371a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3728bfffbccSCorey Minyard         return 1;
3738bfffbccSCorey Minyard     }
3748bfffbccSCorey Minyard 
3758bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3768bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3778bfffbccSCorey Minyard         return 1;
3788bfffbccSCorey Minyard     }
3798bfffbccSCorey Minyard 
380a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
381a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
382a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
383a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3848bfffbccSCorey Minyard 
3858bfffbccSCorey Minyard     if (recid) {
3868bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3878bfffbccSCorey Minyard     }
3888bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3898bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3908bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3918bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3928bfffbccSCorey Minyard     return 0;
3938bfffbccSCorey Minyard }
3948bfffbccSCorey Minyard 
3958bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3968bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3978bfffbccSCorey Minyard {
3988bfffbccSCorey Minyard     unsigned int pos = *retpos;
3998bfffbccSCorey Minyard 
4008bfffbccSCorey Minyard     while (pos < sdr->next_free) {
401a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
402a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
403a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
404a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
4058bfffbccSCorey Minyard 
4068bfffbccSCorey Minyard         if (trec == recid) {
4078bfffbccSCorey Minyard             if (nextrec) {
4088bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
4098bfffbccSCorey Minyard                     *nextrec = 0xffff;
4108bfffbccSCorey Minyard                 } else {
4118bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
4128bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
4138bfffbccSCorey Minyard                 }
4148bfffbccSCorey Minyard             }
4158bfffbccSCorey Minyard             *retpos = pos;
4168bfffbccSCorey Minyard             return 0;
4178bfffbccSCorey Minyard         }
4188bfffbccSCorey Minyard         pos = nextpos;
4198bfffbccSCorey Minyard     }
4208bfffbccSCorey Minyard     return 1;
4218bfffbccSCorey Minyard }
4228bfffbccSCorey Minyard 
4237fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
4247fabcdb9SCédric Le Goater                       const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
4257fabcdb9SCédric Le Goater 
4267fabcdb9SCédric Le Goater {
4277fabcdb9SCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
4287fabcdb9SCédric Le Goater     unsigned int pos;
4297fabcdb9SCédric Le Goater 
4307fabcdb9SCédric Le Goater     pos = 0;
4317fabcdb9SCédric Le Goater     if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
4327fabcdb9SCédric Le Goater         return -1;
4337fabcdb9SCédric Le Goater     }
4347fabcdb9SCédric Le Goater 
4357fabcdb9SCédric Le Goater     *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4367fabcdb9SCédric Le Goater     return 0;
4377fabcdb9SCédric Le Goater }
4387fabcdb9SCédric Le Goater 
4398bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4408bfffbccSCorey Minyard {
4418bfffbccSCorey Minyard     sel->reservation++;
4428bfffbccSCorey Minyard     if (sel->reservation == 0) {
4438bfffbccSCorey Minyard         sel->reservation = 1;
4448bfffbccSCorey Minyard     }
4458bfffbccSCorey Minyard }
4468bfffbccSCorey Minyard 
4478bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4488bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4498bfffbccSCorey Minyard {
4509f7d1d92SCorey Minyard     uint8_t ts[4];
4519f7d1d92SCorey Minyard 
4528bfffbccSCorey Minyard     event[0] = 0xff;
4538bfffbccSCorey Minyard     event[1] = 0xff;
4549f7d1d92SCorey Minyard     set_timestamp(ibs, ts);
4559f7d1d92SCorey Minyard     if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4569f7d1d92SCorey Minyard         memcpy(event + 3, ts, 4);
4579f7d1d92SCorey Minyard     }
4588bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4598bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4608bfffbccSCorey Minyard         return 1;
4618bfffbccSCorey Minyard     }
4628bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4638bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4649f7d1d92SCorey Minyard     memcpy(ibs->sel.last_addition, ts, 4);
4658bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4668bfffbccSCorey Minyard     ibs->sel.next_free++;
4678bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4688bfffbccSCorey Minyard     return 0;
4698bfffbccSCorey Minyard }
4708bfffbccSCorey Minyard 
4718bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4728bfffbccSCorey Minyard {
4738bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4748bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4758bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4768bfffbccSCorey Minyard }
4778bfffbccSCorey Minyard 
4788bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4798bfffbccSCorey Minyard {
4808bc8af69SCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) &&
4818bc8af69SCorey Minyard             (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
4828bc8af69SCorey Minyard              IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
4838bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4848bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4858bfffbccSCorey Minyard }
4868bfffbccSCorey Minyard 
487cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
488cd60d85eSCédric Le Goater {
489cd60d85eSCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
490cd60d85eSCédric Le Goater     IPMIInterface *s = ibs->parent.intf;
491cd60d85eSCédric Le Goater     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
492cd60d85eSCédric Le Goater 
493cd60d85eSCédric Le Goater     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
494cd60d85eSCédric Le Goater         return;
495cd60d85eSCédric Le Goater     }
496cd60d85eSCédric Le Goater 
497cd60d85eSCédric Le Goater     if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
498cd60d85eSCédric Le Goater         sel_add_event(ibs, evt);
499cd60d85eSCédric Le Goater     }
500cd60d85eSCédric Le Goater 
501cd60d85eSCédric Le Goater     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
502cd60d85eSCédric Le Goater         goto out;
503cd60d85eSCédric Le Goater     }
504cd60d85eSCédric Le Goater 
505cd60d85eSCédric Le Goater     memcpy(ibs->evtbuf, evt, 16);
506cd60d85eSCédric Le Goater     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
507cd60d85eSCédric Le Goater     k->set_atn(s, 1, attn_irq_enabled(ibs));
508cd60d85eSCédric Le Goater  out:
509cd60d85eSCédric Le Goater     return;
510cd60d85eSCédric Le Goater }
5118bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
5128bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
5138bfffbccSCorey Minyard {
5148bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5158bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5168bfffbccSCorey Minyard     uint8_t evt[16];
5178bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
5188bfffbccSCorey Minyard 
5198bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
5208bfffbccSCorey Minyard         return;
5218bfffbccSCorey Minyard     }
5228bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
5238bfffbccSCorey Minyard         return;
5248bfffbccSCorey Minyard     }
5258bfffbccSCorey Minyard 
5268bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
5278bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
5288bfffbccSCorey Minyard     evt[8] = 0;
5298bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
5308bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
5318bfffbccSCorey Minyard     evt[11] = sens_num;
5328bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
5338bfffbccSCorey Minyard     evt[13] = evd1;
5348bfffbccSCorey Minyard     evt[14] = evd2;
5358bfffbccSCorey Minyard     evt[15] = evd3;
5368bfffbccSCorey Minyard 
5378bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5388bfffbccSCorey Minyard         sel_add_event(ibs, evt);
5398bfffbccSCorey Minyard     }
5408bfffbccSCorey Minyard 
5418bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
542d13ada5dSCédric Le Goater         return;
5438bfffbccSCorey Minyard     }
5448bfffbccSCorey Minyard 
5458bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
5468bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5478bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
5488bfffbccSCorey Minyard }
5498bfffbccSCorey Minyard 
5508bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5518bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
5528bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
5538bfffbccSCorey Minyard {
5548bfffbccSCorey Minyard     IPMISensor *sens;
5558bfffbccSCorey Minyard     uint16_t mask;
5568bfffbccSCorey Minyard 
5578bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5588bfffbccSCorey Minyard         return;
5598bfffbccSCorey Minyard     }
5608bfffbccSCorey Minyard     if (bit >= 16) {
5618bfffbccSCorey Minyard         return;
5628bfffbccSCorey Minyard     }
5638bfffbccSCorey Minyard 
5648bfffbccSCorey Minyard     mask = (1 << bit);
5658bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5668bfffbccSCorey Minyard     if (val) {
5678bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5688bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5698bfffbccSCorey Minyard             return; /* Already asserted */
5708bfffbccSCorey Minyard         }
5718bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5728bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5738bfffbccSCorey Minyard             /* Send an event on assert */
5748bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5758bfffbccSCorey Minyard         }
5768bfffbccSCorey Minyard     } else {
5778bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5788bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5798bfffbccSCorey Minyard             return; /* Already deasserted */
5808bfffbccSCorey Minyard         }
5818bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5828bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5838bfffbccSCorey Minyard             /* Send an event on deassert */
5848bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5858bfffbccSCorey Minyard         }
5868bfffbccSCorey Minyard     }
5878bfffbccSCorey Minyard }
5888bfffbccSCorey Minyard 
5898bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5908bfffbccSCorey Minyard {
5918bfffbccSCorey Minyard     unsigned int i, pos;
5928bfffbccSCorey Minyard     IPMISensor *sens;
5938bfffbccSCorey Minyard 
5948bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5958bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5968bfffbccSCorey Minyard     }
5978bfffbccSCorey Minyard 
5988bfffbccSCorey Minyard     pos = 0;
5998bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
600a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
601a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
602a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
6038bfffbccSCorey Minyard 
6048bfffbccSCorey Minyard         if (len < 20) {
6058bfffbccSCorey Minyard             continue;
6068bfffbccSCorey Minyard         }
607a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
6088bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
6098bfffbccSCorey Minyard         }
6108bfffbccSCorey Minyard 
61173d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
6128bfffbccSCorey Minyard             continue;
6138bfffbccSCorey Minyard         }
614a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
6158bfffbccSCorey Minyard 
6168bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
617a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
618a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
619a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
620a2295f0aSCédric Le Goater         sens->deassert_suppt =
621a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
622a2295f0aSCédric Le Goater         sens->states_suppt =
623a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
624a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
625a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
6268bfffbccSCorey Minyard 
6278bfffbccSCorey Minyard         /* Enable all the events that are supported. */
6288bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
6298bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
6308bfffbccSCorey Minyard     }
6318bfffbccSCorey Minyard }
6328bfffbccSCorey Minyard 
6338bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
6348bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
6358bfffbccSCorey Minyard {
63693a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6378bfffbccSCorey Minyard         return -1;
6388bfffbccSCorey Minyard     }
6398bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6408bfffbccSCorey Minyard     return 0;
6418bfffbccSCorey Minyard }
6428bfffbccSCorey Minyard 
6434f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6444f298a4bSCédric Le Goater                                               unsigned int netfn,
6454f298a4bSCédric Le Goater                                               unsigned int cmd)
6464f298a4bSCédric Le Goater {
6474f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6484f298a4bSCédric Le Goater 
6494f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6504f298a4bSCédric Le Goater         return NULL;
6514f298a4bSCédric Le Goater     }
6524f298a4bSCédric Le Goater 
6534f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6544f298a4bSCédric Le Goater         return NULL;
6554f298a4bSCédric Le Goater     }
6564f298a4bSCédric Le Goater 
6574f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6584f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6594f298a4bSCédric Le Goater         return NULL;
6604f298a4bSCédric Le Goater     }
6614f298a4bSCédric Le Goater 
6624f298a4bSCédric Le Goater     return hdl;
6634f298a4bSCédric Le Goater }
6644f298a4bSCédric Le Goater 
6658bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6668bfffbccSCorey Minyard {
6678bfffbccSCorey Minyard     int64_t next;
6688bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6698bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6708bfffbccSCorey Minyard     } else {
6718bfffbccSCorey Minyard         /* Wait a minute */
6728bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6738bfffbccSCorey Minyard     }
6748bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6758bfffbccSCorey Minyard }
6768bfffbccSCorey Minyard 
6778bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6788bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6798bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6808bfffbccSCorey Minyard                                     uint8_t msg_id)
6818bfffbccSCorey Minyard {
6828bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6838bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6848bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6854f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
686a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6878bfffbccSCorey Minyard 
6888bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6898bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
690a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6916acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
692d13ada5dSCédric Le Goater         goto out;
693d13ada5dSCédric Le Goater     }
694d13ada5dSCédric Le Goater 
695a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
696a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
697a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6988bfffbccSCorey Minyard 
6998bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
7008bfffbccSCorey Minyard     if (cmd_len < 2) {
7016acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
7028bfffbccSCorey Minyard         goto out;
7038bfffbccSCorey Minyard     }
7048bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
7056acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
7068bfffbccSCorey Minyard         goto out;
7078bfffbccSCorey Minyard     }
7088bfffbccSCorey Minyard 
7098bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
7108bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
7116acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
7128bfffbccSCorey Minyard         goto out;
7138bfffbccSCorey Minyard     }
7148bfffbccSCorey Minyard 
7154f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
7164f298a4bSCédric Le Goater     if (!hdl) {
7176acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
7188bfffbccSCorey Minyard         goto out;
7198bfffbccSCorey Minyard     }
7208bfffbccSCorey Minyard 
7214f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
7226acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
7234f298a4bSCédric Le Goater         goto out;
7244f298a4bSCédric Le Goater     }
7254f298a4bSCédric Le Goater 
726a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
7278bfffbccSCorey Minyard 
7288bfffbccSCorey Minyard  out:
729a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
7308bfffbccSCorey Minyard 
7318bfffbccSCorey Minyard     next_timeout(ibs);
7328bfffbccSCorey Minyard }
7338bfffbccSCorey Minyard 
7348bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7358bfffbccSCorey Minyard {
7368bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7378bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7388bfffbccSCorey Minyard 
7398bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7408bfffbccSCorey Minyard         goto out;
7418bfffbccSCorey Minyard     }
7428bfffbccSCorey Minyard 
7438bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7448bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7458bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7468bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7478bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7488bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7498bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
7508bfffbccSCorey Minyard             break;
7518bfffbccSCorey Minyard 
7528bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7538bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7548bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7558bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7568bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
7578bfffbccSCorey Minyard             break;
7588bfffbccSCorey Minyard 
7598bfffbccSCorey Minyard         default:
7608bfffbccSCorey Minyard             goto do_full_expiry;
7618bfffbccSCorey Minyard         }
7628bfffbccSCorey Minyard 
7638bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7648bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7658bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7668bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7678bfffbccSCorey Minyard         goto out;
7688bfffbccSCorey Minyard     }
7698bfffbccSCorey Minyard 
7708bfffbccSCorey Minyard  do_full_expiry:
7718bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7728bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7738bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7748bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7758bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7768bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7778bfffbccSCorey Minyard         break;
7788bfffbccSCorey Minyard 
7798bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7808bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7818bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7828bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7838bfffbccSCorey Minyard         break;
7848bfffbccSCorey Minyard 
7858bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7868bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7878bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7888bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7898bfffbccSCorey Minyard         break;
7908bfffbccSCorey Minyard 
7918bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7928bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7938bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7948bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7958bfffbccSCorey Minyard         break;
7968bfffbccSCorey Minyard     }
7978bfffbccSCorey Minyard 
7988bfffbccSCorey Minyard  out:
7998bfffbccSCorey Minyard     next_timeout(ibs);
8008bfffbccSCorey Minyard }
8018bfffbccSCorey Minyard 
8028bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
8038bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
804a580d820SCédric Le Goater                                  RspBuffer *rsp)
8058bfffbccSCorey Minyard {
806a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
807a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
808a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
809a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
810a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
8118bfffbccSCorey Minyard }
8128bfffbccSCorey Minyard 
8138bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
8148bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
815a580d820SCédric Le Goater                            RspBuffer *rsp)
8168bfffbccSCorey Minyard {
817a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
818a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
819a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
820a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
8218bfffbccSCorey Minyard }
8228bfffbccSCorey Minyard 
8238bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
8248bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
825a580d820SCédric Le Goater                             RspBuffer *rsp)
8268bfffbccSCorey Minyard {
8278bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8288bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8298bfffbccSCorey Minyard 
8308bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
8318bfffbccSCorey Minyard     case 0: /* power down */
8326acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8338bfffbccSCorey Minyard         break;
8348bfffbccSCorey Minyard     case 1: /* power up */
8356acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8368bfffbccSCorey Minyard         break;
8378bfffbccSCorey Minyard     case 2: /* power cycle */
8386acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8398bfffbccSCorey Minyard         break;
8408bfffbccSCorey Minyard     case 3: /* hard reset */
8416acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8428bfffbccSCorey Minyard         break;
8438bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8446acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8458bfffbccSCorey Minyard         break;
8468bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8476acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8486acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8498bfffbccSCorey Minyard         break;
8508bfffbccSCorey Minyard     default:
8516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8528bfffbccSCorey Minyard         return;
8538bfffbccSCorey Minyard     }
854d13ada5dSCédric Le Goater }
8558bfffbccSCorey Minyard 
856b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
857b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
858a580d820SCédric Le Goater                            RspBuffer *rsp)
859a580d820SCédric Le Goater 
860b7088392SCédric Le Goater {
861a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
862a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
863b7088392SCédric Le Goater }
864b7088392SCédric Le Goater 
8658bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8668bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
867a580d820SCédric Le Goater                           RspBuffer *rsp)
8688bfffbccSCorey Minyard {
869a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
870a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
871a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
872a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
873a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
874a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
87520b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
87620b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
87720b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
87820b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->product_id & 0xff);
87920b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8808bfffbccSCorey Minyard }
8818bfffbccSCorey Minyard 
8828bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8838bfffbccSCorey Minyard {
8848bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8858bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8868bfffbccSCorey Minyard     bool irqs_on;
8878bfffbccSCorey Minyard 
8888bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8898bfffbccSCorey Minyard 
8908bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8918bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8928bfffbccSCorey Minyard 
8938bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8948bfffbccSCorey Minyard }
8958bfffbccSCorey Minyard 
8968bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8978bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
898a580d820SCédric Le Goater                        RspBuffer *rsp)
8998bfffbccSCorey Minyard {
9008bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9018bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9028bfffbccSCorey Minyard 
9038bfffbccSCorey Minyard     /* Disable all interrupts */
9048bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
9058bfffbccSCorey Minyard 
9068bfffbccSCorey Minyard     if (k->reset) {
9078bfffbccSCorey Minyard         k->reset(s, true);
9088bfffbccSCorey Minyard     }
9098bfffbccSCorey Minyard }
9108bfffbccSCorey Minyard 
9118bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
9128bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
913a580d820SCédric Le Goater                        RspBuffer *rsp)
9148bfffbccSCorey Minyard {
9158bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9168bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9178bfffbccSCorey Minyard 
9188bfffbccSCorey Minyard     if (k->reset) {
9198bfffbccSCorey Minyard         k->reset(s, false);
9208bfffbccSCorey Minyard     }
9218bfffbccSCorey Minyard }
92252ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
92352ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
924a580d820SCédric Le Goater                                  RspBuffer *rsp)
92552ba4d50SCédric Le Goater {
92652ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
92752ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
92852ba4d50SCédric Le Goater }
92952ba4d50SCédric Le Goater 
93052ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
93152ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
932a580d820SCédric Le Goater                                  RspBuffer *rsp)
93352ba4d50SCédric Le Goater {
934a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
935a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
93652ba4d50SCédric Le Goater }
93752ba4d50SCédric Le Goater 
93852ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
93952ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
940a580d820SCédric Le Goater                             RspBuffer *rsp)
94152ba4d50SCédric Le Goater {
94252ba4d50SCédric Le Goater     unsigned int i;
94352ba4d50SCédric Le Goater 
944*7b0cd78bSCorey Minyard     /* An uninitialized uuid is all zeros, use that to know if it is set. */
94552ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
946*7b0cd78bSCorey Minyard         if (ibs->uuid.data[i]) {
947*7b0cd78bSCorey Minyard             goto uuid_set;
948*7b0cd78bSCorey Minyard         }
949*7b0cd78bSCorey Minyard     }
950*7b0cd78bSCorey Minyard     /* No uuid is set, return an error. */
951*7b0cd78bSCorey Minyard     rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
952*7b0cd78bSCorey Minyard     return;
953*7b0cd78bSCorey Minyard 
954*7b0cd78bSCorey Minyard  uuid_set:
955*7b0cd78bSCorey Minyard     for (i = 0; i < 16; i++) {
956*7b0cd78bSCorey Minyard         rsp_buffer_push(rsp, ibs->uuid.data[i]);
95752ba4d50SCédric Le Goater     }
95852ba4d50SCédric Le Goater }
9598bfffbccSCorey Minyard 
9608bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9618bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
962a580d820SCédric Le Goater                                    RspBuffer *rsp)
9638bfffbccSCorey Minyard {
9648bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
9658bfffbccSCorey Minyard }
9668bfffbccSCorey Minyard 
9678bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9688bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
969a580d820SCédric Le Goater                                    RspBuffer *rsp)
9708bfffbccSCorey Minyard {
971a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9728bfffbccSCorey Minyard }
9738bfffbccSCorey Minyard 
9748bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9758bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
976a580d820SCédric Le Goater                           RspBuffer *rsp)
9778bfffbccSCorey Minyard {
9788bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9798bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9808bfffbccSCorey Minyard 
9818bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9828bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9838bfffbccSCorey Minyard }
9848bfffbccSCorey Minyard 
9858bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9868bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
987a580d820SCédric Le Goater                           RspBuffer *rsp)
9888bfffbccSCorey Minyard {
989a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9908bfffbccSCorey Minyard }
9918bfffbccSCorey Minyard 
9928bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9938bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
994a580d820SCédric Le Goater                              RspBuffer *rsp)
9958bfffbccSCorey Minyard {
9968bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9978bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9988bfffbccSCorey Minyard     unsigned int i;
9998bfffbccSCorey Minyard 
10008bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
10016acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1002d13ada5dSCédric Le Goater         return;
10038bfffbccSCorey Minyard     }
10048bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
1005a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
10068bfffbccSCorey Minyard     }
10078bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
10088bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10098bfffbccSCorey Minyard }
10108bfffbccSCorey Minyard 
10118bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
10128bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1013a580d820SCédric Le Goater                     RspBuffer *rsp)
10148bfffbccSCorey Minyard {
10158bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10168bfffbccSCorey Minyard 
10178bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10186acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
10198bfffbccSCorey Minyard         goto out;
10208bfffbccSCorey Minyard     }
1021a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
10228bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
1023a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
10248bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
10258bfffbccSCorey Minyard     g_free(msg);
10268bfffbccSCorey Minyard 
10278bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10288bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
10298bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10308bfffbccSCorey Minyard 
10318bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10328bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10338bfffbccSCorey Minyard     }
10348bfffbccSCorey Minyard 
10358bfffbccSCorey Minyard out:
10368bfffbccSCorey Minyard     return;
10378bfffbccSCorey Minyard }
10388bfffbccSCorey Minyard 
10398bfffbccSCorey Minyard static unsigned char
10408bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10418bfffbccSCorey Minyard {
10428bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10438bfffbccSCorey Minyard             csum += *data;
10448bfffbccSCorey Minyard     }
10458bfffbccSCorey Minyard 
10468bfffbccSCorey Minyard     return -csum;
10478bfffbccSCorey Minyard }
10488bfffbccSCorey Minyard 
10498bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10508bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1051a580d820SCédric Le Goater                      RspBuffer *rsp)
10528bfffbccSCorey Minyard {
10538bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10548bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10558bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10568bfffbccSCorey Minyard     uint8_t *buf;
10578bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10588bfffbccSCorey Minyard 
10598bfffbccSCorey Minyard     if (cmd[2] != 0) {
10608bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
10616acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1062d13ada5dSCédric Le Goater         return;
10638bfffbccSCorey Minyard     }
10648bfffbccSCorey Minyard 
10654f298a4bSCédric Le Goater     if (cmd_len < 10) {
10666acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10674f298a4bSCédric Le Goater         return;
10684f298a4bSCédric Le Goater     }
10694f298a4bSCédric Le Goater 
10708bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10718bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10726acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1073d13ada5dSCédric Le Goater         return;
10748bfffbccSCorey Minyard     }
10758bfffbccSCorey Minyard 
10768bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10778bfffbccSCorey Minyard     cmd_len -= 3;
10788bfffbccSCorey Minyard 
10798bfffbccSCorey Minyard     /*
10808bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10818bfffbccSCorey Minyard      * be returned in the response.
10828bfffbccSCorey Minyard      */
10838bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10848bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1085d13ada5dSCédric Le Goater         return; /* No response */
10868bfffbccSCorey Minyard     }
10878bfffbccSCorey Minyard 
10888bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10898bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10908bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10918bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10928bfffbccSCorey Minyard 
10938bfffbccSCorey Minyard     if (rqLun != 2) {
10948bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1095d13ada5dSCédric Le Goater         return;
10968bfffbccSCorey Minyard     }
10978bfffbccSCorey Minyard 
10988bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10998bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
11008bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
11018bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
11028bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
11038bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
11048bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
11058bfffbccSCorey Minyard     msg->len = 6;
11068bfffbccSCorey Minyard 
11078bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
11088bfffbccSCorey Minyard         /* Not a command we handle. */
11098bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
11108bfffbccSCorey Minyard         goto end_msg;
11118bfffbccSCorey Minyard     }
11128bfffbccSCorey Minyard 
11138bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
11148bfffbccSCorey Minyard     buf[0] = 0;
11158bfffbccSCorey Minyard     buf[1] = 0;
11168bfffbccSCorey Minyard     buf[2] = 0;
11178bfffbccSCorey Minyard     buf[3] = 0;
11188bfffbccSCorey Minyard     buf[4] = 0x51;
11198bfffbccSCorey Minyard     buf[5] = 0;
11208bfffbccSCorey Minyard     buf[6] = 0;
11218bfffbccSCorey Minyard     buf[7] = 0;
11228bfffbccSCorey Minyard     buf[8] = 0;
11238bfffbccSCorey Minyard     buf[9] = 0;
11248bfffbccSCorey Minyard     buf[10] = 0;
11258bfffbccSCorey Minyard     msg->len += 11;
11268bfffbccSCorey Minyard 
11278bfffbccSCorey Minyard  end_msg:
11288bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
11298bfffbccSCorey Minyard     msg->len++;
11308bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
11318bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
11328bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
11338bfffbccSCorey Minyard }
11348bfffbccSCorey Minyard 
11358bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11368bfffbccSCorey Minyard {
11378bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11388bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11398bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11408bfffbccSCorey Minyard         return;
11418bfffbccSCorey Minyard     }
11428bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11438bfffbccSCorey Minyard 
11448bfffbccSCorey Minyard 
11458bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11468bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11478bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11488bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11498bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11508bfffbccSCorey Minyard     }
11518bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11528bfffbccSCorey Minyard }
11538bfffbccSCorey Minyard 
11548bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11558bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1156a580d820SCédric Le Goater                                  RspBuffer *rsp)
11578bfffbccSCorey Minyard {
11588bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11596acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1160d13ada5dSCédric Le Goater         return;
11618bfffbccSCorey Minyard     }
11628bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11638bfffbccSCorey Minyard }
11648bfffbccSCorey Minyard 
11658bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11668bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1167a580d820SCédric Le Goater                                RspBuffer *rsp)
11688bfffbccSCorey Minyard {
11698bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11708bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11718bfffbccSCorey Minyard     unsigned int val;
11728bfffbccSCorey Minyard 
11738bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11748bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11756acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1176d13ada5dSCédric Le Goater         return;
11778bfffbccSCorey Minyard     }
11788bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11798bfffbccSCorey Minyard     switch (val) {
11808bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11818bfffbccSCorey Minyard         break;
11828bfffbccSCorey Minyard 
11838bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11858bfffbccSCorey Minyard         break;
11868bfffbccSCorey Minyard 
11878bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11898bfffbccSCorey Minyard         break;
11908bfffbccSCorey Minyard 
11918bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11926acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11938bfffbccSCorey Minyard         break;
11948bfffbccSCorey Minyard 
11958bfffbccSCorey Minyard     default:
11966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11978bfffbccSCorey Minyard     }
1198a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11996acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1200d13ada5dSCédric Le Goater         return;
12018bfffbccSCorey Minyard     }
12028bfffbccSCorey Minyard 
12038bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
12048bfffbccSCorey Minyard     switch (val) {
12058bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
12068bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
12078bfffbccSCorey Minyard         break;
12088bfffbccSCorey Minyard 
12098bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
12106af94767SCorey Minyard         if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
12118bfffbccSCorey Minyard             /* NMI not supported. */
12126acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1213d13ada5dSCédric Le Goater             return;
12148bfffbccSCorey Minyard         }
121537eebb86SCorey Minyard         break;
121637eebb86SCorey Minyard 
12178bfffbccSCorey Minyard     default:
12188bfffbccSCorey Minyard         /* We don't support PRE_SMI */
12196acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1220d13ada5dSCédric Le Goater         return;
12218bfffbccSCorey Minyard     }
12228bfffbccSCorey Minyard 
12238bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
12248bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
12258bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
12268bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
12278bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
12288bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
12298bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
12308bfffbccSCorey Minyard         do_watchdog_reset(ibs);
12318bfffbccSCorey Minyard     } else {
12328bfffbccSCorey Minyard         ibs->watchdog_running = 0;
12338bfffbccSCorey Minyard     }
12348bfffbccSCorey Minyard }
12358bfffbccSCorey Minyard 
12368bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12378bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1238a580d820SCédric Le Goater                                RspBuffer *rsp)
12398bfffbccSCorey Minyard {
1240a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1241a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1242a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1243a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
1244fb45770bSCorey Minyard     rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1245fb45770bSCorey Minyard     rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12468bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12478bfffbccSCorey Minyard         long timeout;
12488bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12498bfffbccSCorey Minyard                    / 100000000);
1250a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1251a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12528bfffbccSCorey Minyard     } else {
1253a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1254a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12558bfffbccSCorey Minyard     }
12568bfffbccSCorey Minyard }
12578bfffbccSCorey Minyard 
12588bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12598bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1260a580d820SCédric Le Goater                              RspBuffer *rsp)
12618bfffbccSCorey Minyard {
12628bfffbccSCorey Minyard     unsigned int i;
12638bfffbccSCorey Minyard 
1264a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1265a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1266a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1267a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1268a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
12698bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1270a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
12718bfffbccSCorey Minyard     }
12728bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1273a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
12748bfffbccSCorey Minyard     }
12758bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1276a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12778bfffbccSCorey Minyard }
12788bfffbccSCorey Minyard 
12798bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12808bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1281a580d820SCédric Le Goater                             RspBuffer *rsp)
12828bfffbccSCorey Minyard {
1283a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1284a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12858bfffbccSCorey Minyard }
12868bfffbccSCorey Minyard 
12878bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12888bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1289a580d820SCédric Le Goater                     RspBuffer *rsp)
12908bfffbccSCorey Minyard {
12918bfffbccSCorey Minyard     unsigned int pos;
12928bfffbccSCorey Minyard     uint16_t nextrec;
1293a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12948bfffbccSCorey Minyard 
12958bfffbccSCorey Minyard     if (cmd[6]) {
12967f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12976acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12987f996411SCédric Le Goater             return;
12998bfffbccSCorey Minyard         }
13007f996411SCédric Le Goater     }
13017f996411SCédric Le Goater 
13028bfffbccSCorey Minyard     pos = 0;
13038bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
13048bfffbccSCorey Minyard                        &pos, &nextrec)) {
13056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1306d13ada5dSCédric Le Goater         return;
13078bfffbccSCorey Minyard     }
1308a2295f0aSCédric Le Goater 
1309a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1310a2295f0aSCédric Le Goater 
1311a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
13126acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1313d13ada5dSCédric Le Goater         return;
13148bfffbccSCorey Minyard     }
13158bfffbccSCorey Minyard 
1316a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1317a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
13188bfffbccSCorey Minyard 
13198bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1320a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
13218bfffbccSCorey Minyard     }
13228bfffbccSCorey Minyard 
1323a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13246acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1325d13ada5dSCédric Le Goater         return;
13268bfffbccSCorey Minyard     }
1327a580d820SCédric Le Goater 
1328a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13298bfffbccSCorey Minyard }
13308bfffbccSCorey Minyard 
13318bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13328bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1333a580d820SCédric Le Goater                     RspBuffer *rsp)
13348bfffbccSCorey Minyard {
13358bfffbccSCorey Minyard     uint16_t recid;
1336a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13378bfffbccSCorey Minyard 
1338a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1340d13ada5dSCédric Le Goater         return;
13418bfffbccSCorey Minyard     }
1342a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1343a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13448bfffbccSCorey Minyard }
13458bfffbccSCorey Minyard 
13468bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13478bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1348a580d820SCédric Le Goater                           RspBuffer *rsp)
13498bfffbccSCorey Minyard {
13507f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13527f996411SCédric Le Goater         return;
13537f996411SCédric Le Goater     }
13547f996411SCédric Le Goater 
13558bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13566acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1357d13ada5dSCédric Le Goater         return;
13588bfffbccSCorey Minyard     }
13598bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13608bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13618bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
13628bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1363a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13648bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
13658bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1366a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
13678bfffbccSCorey Minyard     } else {
13686acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
13698bfffbccSCorey Minyard         return;
13708bfffbccSCorey Minyard     }
1371d13ada5dSCédric Le Goater }
13728bfffbccSCorey Minyard 
13738bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
13748bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1375a580d820SCédric Le Goater                          RspBuffer *rsp)
13768bfffbccSCorey Minyard {
13778bfffbccSCorey Minyard     unsigned int i, val;
13788bfffbccSCorey Minyard 
1379a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1380a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1381a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13828bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1383a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1384a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13858bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1386a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13878bfffbccSCorey Minyard     }
13888bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1389a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13908bfffbccSCorey Minyard     }
13918bfffbccSCorey Minyard     /* Only support Reserve SEL */
1392a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13938bfffbccSCorey Minyard }
13948bfffbccSCorey Minyard 
1395540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1396540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1397540c07d3SCédric Le Goater                          RspBuffer *rsp)
1398540c07d3SCédric Le Goater {
1399540c07d3SCédric Le Goater     uint8_t fruid;
1400540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1401540c07d3SCédric Le Goater 
1402540c07d3SCédric Le Goater     fruid = cmd[2];
1403540c07d3SCédric Le Goater 
1404540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1405540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1406540c07d3SCédric Le Goater         return;
1407540c07d3SCédric Le Goater     }
1408540c07d3SCédric Le Goater 
1409540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1410540c07d3SCédric Le Goater 
1411540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1412540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1413540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1414540c07d3SCédric Le Goater }
1415540c07d3SCédric Le Goater 
1416540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1417540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1418540c07d3SCédric Le Goater                          RspBuffer *rsp)
1419540c07d3SCédric Le Goater {
1420540c07d3SCédric Le Goater     uint8_t fruid;
1421540c07d3SCédric Le Goater     uint16_t offset;
1422540c07d3SCédric Le Goater     int i;
1423540c07d3SCédric Le Goater     uint8_t *fru_entry;
1424540c07d3SCédric Le Goater     unsigned int count;
1425540c07d3SCédric Le Goater 
1426540c07d3SCédric Le Goater     fruid = cmd[2];
1427540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1428540c07d3SCédric Le Goater 
1429540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1430540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1431540c07d3SCédric Le Goater         return;
1432540c07d3SCédric Le Goater     }
1433540c07d3SCédric Le Goater 
1434540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1435540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1436540c07d3SCédric Le Goater         return;
1437540c07d3SCédric Le Goater     }
1438540c07d3SCédric Le Goater 
1439540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1440540c07d3SCédric Le Goater 
1441540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1442540c07d3SCédric Le Goater 
1443540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1444540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1445540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1446540c07d3SCédric Le Goater     }
1447540c07d3SCédric Le Goater }
1448540c07d3SCédric Le Goater 
1449540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1450540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1451540c07d3SCédric Le Goater                          RspBuffer *rsp)
1452540c07d3SCédric Le Goater {
1453540c07d3SCédric Le Goater     uint8_t fruid;
1454540c07d3SCédric Le Goater     uint16_t offset;
1455540c07d3SCédric Le Goater     uint8_t *fru_entry;
1456540c07d3SCédric Le Goater     unsigned int count;
1457540c07d3SCédric Le Goater 
1458540c07d3SCédric Le Goater     fruid = cmd[2];
1459540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1460540c07d3SCédric Le Goater 
1461540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1462540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1463540c07d3SCédric Le Goater         return;
1464540c07d3SCédric Le Goater     }
1465540c07d3SCédric Le Goater 
1466540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1467540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1468540c07d3SCédric Le Goater         return;
1469540c07d3SCédric Le Goater     }
1470540c07d3SCédric Le Goater 
1471540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1472540c07d3SCédric Le Goater 
1473540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1474540c07d3SCédric Le Goater 
1475540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1476540c07d3SCédric Le Goater 
1477540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1478540c07d3SCédric Le Goater }
1479540c07d3SCédric Le Goater 
14808bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
14818bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1482a580d820SCédric Le Goater                         RspBuffer *rsp)
14838bfffbccSCorey Minyard {
1484a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1485a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
14868bfffbccSCorey Minyard }
14878bfffbccSCorey Minyard 
14888bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
14898bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1490a580d820SCédric Le Goater                           RspBuffer *rsp)
14918bfffbccSCorey Minyard {
14928bfffbccSCorey Minyard     unsigned int val;
14938bfffbccSCorey Minyard 
14948bfffbccSCorey Minyard     if (cmd[6]) {
14957f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
14966acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
14977f996411SCédric Le Goater             return;
14987f996411SCédric Le Goater         }
14998bfffbccSCorey Minyard     }
15008bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
15016acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1502d13ada5dSCédric Le Goater         return;
15038bfffbccSCorey Minyard     }
15048bfffbccSCorey Minyard     if (cmd[6] > 15) {
15056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1506d13ada5dSCédric Le Goater         return;
15078bfffbccSCorey Minyard     }
15088bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
15098bfffbccSCorey Minyard         cmd[7] = 16;
15108bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
15116acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1512d13ada5dSCédric Le Goater         return;
15138bfffbccSCorey Minyard     } else {
15148bfffbccSCorey Minyard         cmd[7] += cmd[6];
15158bfffbccSCorey Minyard     }
15168bfffbccSCorey Minyard 
15178bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
15188bfffbccSCorey Minyard     if (val == 0xffff) {
15198bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
15208bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
15216acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1522d13ada5dSCédric Le Goater         return;
15238bfffbccSCorey Minyard     }
15248bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1525a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1526a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
15278bfffbccSCorey Minyard     } else {
1528a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1529a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15308bfffbccSCorey Minyard     }
15318bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1532a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15338bfffbccSCorey Minyard     }
15348bfffbccSCorey Minyard }
15358bfffbccSCorey Minyard 
15368bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15378bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1538a580d820SCédric Le Goater                           RspBuffer *rsp)
15398bfffbccSCorey Minyard {
15408bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15416acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1542d13ada5dSCédric Le Goater         return;
15438bfffbccSCorey Minyard     }
15448bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1545a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1546a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15478bfffbccSCorey Minyard }
15488bfffbccSCorey Minyard 
15498bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15508bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1551a580d820SCédric Le Goater                       RspBuffer *rsp)
15528bfffbccSCorey Minyard {
15537f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15546acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15557f996411SCédric Le Goater         return;
15567f996411SCédric Le Goater     }
15577f996411SCédric Le Goater 
15588bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15596acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1560d13ada5dSCédric Le Goater         return;
15618bfffbccSCorey Minyard     }
15628bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
15638bfffbccSCorey Minyard         ibs->sel.next_free = 0;
15648bfffbccSCorey Minyard         ibs->sel.overflow = 0;
15658bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1566a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15678bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
15688bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1569a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
15708bfffbccSCorey Minyard     } else {
15716acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
15728bfffbccSCorey Minyard         return;
15738bfffbccSCorey Minyard     }
1574d13ada5dSCédric Le Goater }
15758bfffbccSCorey Minyard 
15768bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
15778bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1578a580d820SCédric Le Goater                          RspBuffer *rsp)
15798bfffbccSCorey Minyard {
15808bfffbccSCorey Minyard     uint32_t val;
15818bfffbccSCorey Minyard     struct ipmi_time now;
15828bfffbccSCorey Minyard 
15838bfffbccSCorey Minyard     ipmi_gettime(&now);
15848bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1585a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1586a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1587a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1588a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
15898bfffbccSCorey Minyard }
15908bfffbccSCorey Minyard 
15918bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
15928bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1593a580d820SCédric Le Goater                          RspBuffer *rsp)
15948bfffbccSCorey Minyard {
15958bfffbccSCorey Minyard     uint32_t val;
15968bfffbccSCorey Minyard     struct ipmi_time now;
15978bfffbccSCorey Minyard 
15988bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
15998bfffbccSCorey Minyard     ipmi_gettime(&now);
16008bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
16018bfffbccSCorey Minyard }
16028bfffbccSCorey Minyard 
16039380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
16049380d2edSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
16059380d2edSCorey Minyard                                RspBuffer *rsp)
16069380d2edSCorey Minyard {
16079380d2edSCorey Minyard     uint8_t event[16];
16089380d2edSCorey Minyard 
16099380d2edSCorey Minyard     event[2] = 2; /* System event record */
16109380d2edSCorey Minyard     event[7] = cmd[2]; /* Generator ID */
16119380d2edSCorey Minyard     event[8] = 0;
16129380d2edSCorey Minyard     event[9] = cmd[3]; /* EvMRev */
16139380d2edSCorey Minyard     event[10] = cmd[4]; /* Sensor type */
16149380d2edSCorey Minyard     event[11] = cmd[5]; /* Sensor number */
16159380d2edSCorey Minyard     event[12] = cmd[6]; /* Event dir / Event type */
16169380d2edSCorey Minyard     event[13] = cmd[7]; /* Event data 1 */
16179380d2edSCorey Minyard     event[14] = cmd[8]; /* Event data 2 */
16189380d2edSCorey Minyard     event[15] = cmd[9]; /* Event data 3 */
16199380d2edSCorey Minyard 
16209380d2edSCorey Minyard     if (sel_add_event(ibs, event)) {
16219380d2edSCorey Minyard         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
16229380d2edSCorey Minyard     }
16239380d2edSCorey Minyard }
16249380d2edSCorey Minyard 
16258bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
16268bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1627a580d820SCédric Le Goater                                   RspBuffer *rsp)
16288bfffbccSCorey Minyard {
16298bfffbccSCorey Minyard     IPMISensor *sens;
16308bfffbccSCorey Minyard 
163173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16328bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16336acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1634d13ada5dSCédric Le Goater         return;
16358bfffbccSCorey Minyard     }
16368bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16378bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
16388bfffbccSCorey Minyard     case 0: /* Do not change */
16398bfffbccSCorey Minyard         break;
16408bfffbccSCorey Minyard     case 1: /* Enable bits */
16418bfffbccSCorey Minyard         if (cmd_len > 4) {
16428bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
16438bfffbccSCorey Minyard         }
16448bfffbccSCorey Minyard         if (cmd_len > 5) {
16458bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16468bfffbccSCorey Minyard         }
16478bfffbccSCorey Minyard         if (cmd_len > 6) {
16488bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16498bfffbccSCorey Minyard         }
16508bfffbccSCorey Minyard         if (cmd_len > 7) {
16518bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16528bfffbccSCorey Minyard         }
16538bfffbccSCorey Minyard         break;
16548bfffbccSCorey Minyard     case 2: /* Disable bits */
16558bfffbccSCorey Minyard         if (cmd_len > 4) {
16568bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16578bfffbccSCorey Minyard         }
16588bfffbccSCorey Minyard         if (cmd_len > 5) {
16598bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16608bfffbccSCorey Minyard         }
16618bfffbccSCorey Minyard         if (cmd_len > 6) {
16628bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
16638bfffbccSCorey Minyard         }
16648bfffbccSCorey Minyard         if (cmd_len > 7) {
16658bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
16668bfffbccSCorey Minyard         }
16678bfffbccSCorey Minyard         break;
16688bfffbccSCorey Minyard     case 3:
16696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1670d13ada5dSCédric Le Goater         return;
16718bfffbccSCorey Minyard     }
16728bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
16738bfffbccSCorey Minyard }
16748bfffbccSCorey Minyard 
16758bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
16768bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1677a580d820SCédric Le Goater                                   RspBuffer *rsp)
16788bfffbccSCorey Minyard {
16798bfffbccSCorey Minyard     IPMISensor *sens;
16808bfffbccSCorey Minyard 
168173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16828bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16836acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1684d13ada5dSCédric Le Goater         return;
16858bfffbccSCorey Minyard     }
16868bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1687a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1688a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1689a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1690a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1691a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
16928bfffbccSCorey Minyard }
16938bfffbccSCorey Minyard 
16948bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
16958bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1696a580d820SCédric Le Goater                               RspBuffer *rsp)
16978bfffbccSCorey Minyard {
16988bfffbccSCorey Minyard     IPMISensor *sens;
16998bfffbccSCorey Minyard 
170073d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17018bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17026acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1703d13ada5dSCédric Le Goater         return;
17048bfffbccSCorey Minyard     }
17058bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
17068bfffbccSCorey Minyard 
17078bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
17088bfffbccSCorey Minyard         /* Just clear everything */
17098bfffbccSCorey Minyard         sens->states = 0;
17108bfffbccSCorey Minyard         return;
17118bfffbccSCorey Minyard     }
1712d13ada5dSCédric Le Goater }
17138bfffbccSCorey Minyard 
17148bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
17158bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1716a580d820SCédric Le Goater                                   RspBuffer *rsp)
17178bfffbccSCorey Minyard {
17188bfffbccSCorey Minyard     IPMISensor *sens;
17198bfffbccSCorey Minyard 
172073d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17218bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17226acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1723d13ada5dSCédric Le Goater         return;
17248bfffbccSCorey Minyard     }
17258bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1726a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1727a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1728a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1729a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1730a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1731a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
17328bfffbccSCorey Minyard }
17338bfffbccSCorey Minyard 
17348bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
17358bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1736a580d820SCédric Le Goater                                RspBuffer *rsp)
17378bfffbccSCorey Minyard {
17388bfffbccSCorey Minyard     IPMISensor *sens;
17398bfffbccSCorey Minyard 
174073d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17418bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17426acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1743d13ada5dSCédric Le Goater         return;
17448bfffbccSCorey Minyard     }
17458bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1746a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1747a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1748a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17498bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1750a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17518bfffbccSCorey Minyard     }
17528bfffbccSCorey Minyard }
17538bfffbccSCorey Minyard 
1754728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1755728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1756a580d820SCédric Le Goater                             RspBuffer *rsp)
1757728710e1SCédric Le Goater {
1758728710e1SCédric Le Goater     IPMISensor *sens;
1759728710e1SCédric Le Goater 
1760728710e1SCédric Le Goater 
176173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1762728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17636acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1764728710e1SCédric Le Goater         return;
1765728710e1SCédric Le Goater     }
1766728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1767728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1768728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1769728710e1SCédric Le Goater }
1770728710e1SCédric Le Goater 
1771728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1772728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1773a580d820SCédric Le Goater                             RspBuffer *rsp)
1774728710e1SCédric Le Goater {
1775728710e1SCédric Le Goater     IPMISensor *sens;
1776728710e1SCédric Le Goater 
1777728710e1SCédric Le Goater 
177873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1779728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17806acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1781728710e1SCédric Le Goater         return;
1782728710e1SCédric Le Goater     }
1783728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1784a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1785a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1786728710e1SCédric Le Goater }
1787728710e1SCédric Le Goater 
1788728710e1SCédric Le Goater 
178962a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
17904f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
17914f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
17924f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
17934f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
17948bfffbccSCorey Minyard };
17958bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
179662a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
17978bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
17988bfffbccSCorey Minyard };
17998bfffbccSCorey Minyard 
180062a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
18019380d2edSCorey Minyard     [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
18024f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
18034f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
18044f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
18054f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
18064f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
18074f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
18084f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
18098bfffbccSCorey Minyard };
18108bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
181162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
18128bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
18138bfffbccSCorey Minyard };
18148bfffbccSCorey Minyard 
181562a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
18164f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
18174f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
18184f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
18194f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
18204f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
18214f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
18224f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
18234f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
18244f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
18254f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
18264f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
18274f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
18284f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
18294f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
18304f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
18314f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
18328bfffbccSCorey Minyard };
18338bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
183462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
18358bfffbccSCorey Minyard     .cmd_handlers = app_cmds
18368bfffbccSCorey Minyard };
18378bfffbccSCorey Minyard 
183862a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
1839540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
1840540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
1841540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
18424f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
18434f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
18444f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
18454f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
18464f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
18474f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
18484f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
18494f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
18504f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
18514f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
18527f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
18537f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
18548bfffbccSCorey Minyard };
18558bfffbccSCorey Minyard 
18568bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
185762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
18588bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
18598bfffbccSCorey Minyard };
18608bfffbccSCorey Minyard 
18618bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
18628bfffbccSCorey Minyard {
18638bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
18648bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
18658bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
18668bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
18678bfffbccSCorey Minyard }
18688bfffbccSCorey Minyard 
18695167560bSCédric Le Goater static uint8_t init_sdrs[] = {
18708bfffbccSCorey Minyard     /* Watchdog device */
18718bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
18728bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
18738bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18748bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
18758bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
18768bfffbccSCorey Minyard };
18778bfffbccSCorey Minyard 
18784fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
18794fa9f08eSCédric Le Goater {
18804fa9f08eSCédric Le Goater     unsigned int i;
18814fa9f08eSCédric Le Goater     int len;
18825167560bSCédric Le Goater     size_t sdrs_size;
18835167560bSCédric Le Goater     uint8_t *sdrs;
188452fc01d9SCédric Le Goater 
18855167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
18865167560bSCédric Le Goater     sdrs = init_sdrs;
18878c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
18888c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
18898c6fd7f3SCédric Le Goater                              NULL)) {
18908c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
18918c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
18928c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
18938c6fd7f3SCédric Le Goater     }
18945167560bSCédric Le Goater 
18955167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
189652fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
189752fc01d9SCédric Le Goater 
18985167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
18994fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
19008c6fd7f3SCédric Le Goater             break;
19014fa9f08eSCédric Le Goater         }
19025167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
19034fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
19045167560bSCédric Le Goater         if (i + len > sdrs_size) {
19054fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
19068c6fd7f3SCédric Le Goater             break;
19074fa9f08eSCédric Le Goater         }
19084fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
19094fa9f08eSCédric Le Goater     }
19108c6fd7f3SCédric Le Goater 
19118c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
19128c6fd7f3SCédric Le Goater         g_free(sdrs);
19138c6fd7f3SCédric Le Goater     }
19144fa9f08eSCédric Le Goater }
19154fa9f08eSCédric Le Goater 
1916bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1917bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1918bd66bcfcSCorey Minyard     .version_id = 1,
1919bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1920bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1921bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1922bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1923bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1924bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1925bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1926bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1927bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1928bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1929bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1930bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1931bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1932bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1933bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1934bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1935bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1936bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1937bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1938bd66bcfcSCorey Minyard                        IPMIBmcSim),
1939bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1940bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1941bd66bcfcSCorey Minyard     }
1942bd66bcfcSCorey Minyard };
1943bd66bcfcSCorey Minyard 
1944540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
1945540c07d3SCédric Le Goater {
1946540c07d3SCédric Le Goater     int fsize;
1947540c07d3SCédric Le Goater     int size = 0;
1948540c07d3SCédric Le Goater 
1949540c07d3SCédric Le Goater     if (!fru->filename) {
1950540c07d3SCédric Le Goater         goto out;
1951540c07d3SCédric Le Goater     }
1952540c07d3SCédric Le Goater 
1953540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
1954540c07d3SCédric Le Goater     if (fsize > 0) {
1955540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
1956540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
1957540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
1958540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
1959540c07d3SCédric Le Goater             g_free(fru->data);
1960540c07d3SCédric Le Goater             fru->data = NULL;
1961540c07d3SCédric Le Goater         }
1962540c07d3SCédric Le Goater     }
1963540c07d3SCédric Le Goater 
1964540c07d3SCédric Le Goater out:
1965540c07d3SCédric Le Goater     if (!fru->data) {
1966540c07d3SCédric Le Goater         /* give one default FRU */
1967540c07d3SCédric Le Goater         size = fru->areasize;
1968540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
1969540c07d3SCédric Le Goater     }
1970540c07d3SCédric Le Goater 
1971540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
1972540c07d3SCédric Le Goater }
1973540c07d3SCédric Le Goater 
19740bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
19758bfffbccSCorey Minyard {
19760bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
19778bfffbccSCorey Minyard     unsigned int i;
19788bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
19798bfffbccSCorey Minyard 
19808bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
19818bfffbccSCorey Minyard 
19828bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
19838bfffbccSCorey Minyard     ibs->device_id = 0x20;
19848bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1985b7088392SCédric Le Goater     ibs->restart_cause = 0;
19868bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
19878bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
19888bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
19898bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
19908bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
19918bfffbccSCorey Minyard     }
19928bfffbccSCorey Minyard 
19934fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
19948bfffbccSCorey Minyard 
1995540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
1996540c07d3SCédric Le Goater 
199752ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
199852ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
199952ba4d50SCédric Le Goater 
20008bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
20018bfffbccSCorey Minyard     register_cmds(ibs);
20028bfffbccSCorey Minyard 
20038bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
2004bd66bcfcSCorey Minyard 
2005bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
20068bfffbccSCorey Minyard }
20078bfffbccSCorey Minyard 
20088c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = {
2009540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2010540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
20118c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
201220b23364SCorey Minyard     DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
201320b23364SCorey Minyard     DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
201420b23364SCorey Minyard     DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
201520b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
201620b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
201720b23364SCorey Minyard     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
201820b23364SCorey Minyard     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
2019*7b0cd78bSCorey Minyard     DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
20208c6fd7f3SCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
20218c6fd7f3SCédric Le Goater };
20228c6fd7f3SCédric Le Goater 
20238bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
20248bfffbccSCorey Minyard {
20250bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
20268bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
20278bfffbccSCorey Minyard 
202866abfddbSCorey Minyard     dc->hotpluggable = false;
20290bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
20308c6fd7f3SCédric Le Goater     dc->props = ipmi_sim_properties;
20318bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
20328bfffbccSCorey Minyard }
20338bfffbccSCorey Minyard 
20348bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
20358bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
20368bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
20378bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
20388bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
20398bfffbccSCorey Minyard };
20408bfffbccSCorey Minyard 
20418bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
20428bfffbccSCorey Minyard {
20438bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
20448bfffbccSCorey Minyard }
20458bfffbccSCorey Minyard 
20468bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2047