xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 7cfa06a2f1db6fef2be7f645697dbc6c4006324a)
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"
268bfffbccSCorey Minyard #include "qemu/timer.h"
278bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
288bfffbccSCorey Minyard #include "qemu/error-report.h"
298bfffbccSCorey Minyard 
308bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
318bfffbccSCorey Minyard 
328bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
338bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
348bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
358bfffbccSCorey Minyard 
368bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
378bfffbccSCorey Minyard 
388bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
398bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
408bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
418bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
438bfffbccSCorey Minyard 
448bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
458bfffbccSCorey Minyard 
468bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
478bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
488bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
498bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
508bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
518bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
528bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
538bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
548bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
558bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
568bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
578bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
588bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
598bfffbccSCorey Minyard 
608bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
618bfffbccSCorey Minyard 
628bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
638bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
648bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
658bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
668bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
678bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
688bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
698bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
718bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
728bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
738bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
748bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
758bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
768bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
778bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
788bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
798bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
808bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
818bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
828bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
848bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
858bfffbccSCorey Minyard 
868bfffbccSCorey Minyard 
878bfffbccSCorey Minyard /* Same as a timespec struct. */
888bfffbccSCorey Minyard struct ipmi_time {
898bfffbccSCorey Minyard     long tv_sec;
908bfffbccSCorey Minyard     long tv_nsec;
918bfffbccSCorey Minyard };
928bfffbccSCorey Minyard 
938bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
948bfffbccSCorey Minyard 
958bfffbccSCorey Minyard typedef struct IPMISel {
968bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
978bfffbccSCorey Minyard     unsigned int next_free;
988bfffbccSCorey Minyard     long time_offset;
998bfffbccSCorey Minyard     uint16_t reservation;
1008bfffbccSCorey Minyard     uint8_t last_addition[4];
1018bfffbccSCorey Minyard     uint8_t last_clear[4];
1028bfffbccSCorey Minyard     uint8_t overflow;
1038bfffbccSCorey Minyard } IPMISel;
1048bfffbccSCorey Minyard 
1058bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1068bfffbccSCorey Minyard 
1078bfffbccSCorey Minyard typedef struct IPMISdr {
1088bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1098bfffbccSCorey Minyard     unsigned int next_free;
1108bfffbccSCorey Minyard     uint16_t next_rec_id;
1118bfffbccSCorey Minyard     uint16_t reservation;
1128bfffbccSCorey Minyard     uint8_t last_addition[4];
1138bfffbccSCorey Minyard     uint8_t last_clear[4];
1148bfffbccSCorey Minyard     uint8_t overflow;
1158bfffbccSCorey Minyard } IPMISdr;
1168bfffbccSCorey Minyard 
1178bfffbccSCorey Minyard typedef struct IPMISensor {
1188bfffbccSCorey Minyard     uint8_t status;
1198bfffbccSCorey Minyard     uint8_t reading;
1208bfffbccSCorey Minyard     uint16_t states_suppt;
1218bfffbccSCorey Minyard     uint16_t assert_suppt;
1228bfffbccSCorey Minyard     uint16_t deassert_suppt;
1238bfffbccSCorey Minyard     uint16_t states;
1248bfffbccSCorey Minyard     uint16_t assert_states;
1258bfffbccSCorey Minyard     uint16_t deassert_states;
1268bfffbccSCorey Minyard     uint16_t assert_enable;
1278bfffbccSCorey Minyard     uint16_t deassert_enable;
1288bfffbccSCorey Minyard     uint8_t  sensor_type;
1298bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1308bfffbccSCorey Minyard } IPMISensor;
1318bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1328bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1338bfffbccSCorey Minyard                                              !!(v))
1348bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1358bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1368bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1378bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1388bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1398bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1408bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1418bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1428bfffbccSCorey Minyard                                              (v & 0xc0))
1438bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1448bfffbccSCorey Minyard 
1458bfffbccSCorey Minyard #define MAX_SENSORS 20
1468bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1478bfffbccSCorey Minyard 
1488bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
1498bfffbccSCorey Minyard 
1508bfffbccSCorey Minyard #define MAX_NETFNS 64
1518bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s,
1528bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1538bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
1548bfffbccSCorey Minyard                                unsigned int max_rsp_len);
1558bfffbccSCorey Minyard typedef struct IPMINetfn {
1568bfffbccSCorey Minyard     unsigned int cmd_nums;
1578bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1588bfffbccSCorey Minyard } IPMINetfn;
1598bfffbccSCorey Minyard 
1608bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1618bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1628bfffbccSCorey Minyard     uint8_t len;
1638bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1648bfffbccSCorey Minyard } IPMIRcvBufEntry;
1658bfffbccSCorey Minyard 
1668bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1678bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1688bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1698bfffbccSCorey Minyard struct IPMIBmcSim {
1708bfffbccSCorey Minyard     IPMIBmc parent;
1718bfffbccSCorey Minyard 
1728bfffbccSCorey Minyard     QEMUTimer *timer;
1738bfffbccSCorey Minyard 
1748bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1758bfffbccSCorey Minyard     uint8_t msg_flags;
1768bfffbccSCorey Minyard 
1778bfffbccSCorey Minyard     bool     watchdog_initialized;
1788bfffbccSCorey Minyard     uint8_t  watchdog_use;
1798bfffbccSCorey Minyard     uint8_t  watchdog_action;
1808bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1818bfffbccSCorey Minyard     bool     watchdog_expired;
1828bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1838bfffbccSCorey Minyard 
1848bfffbccSCorey Minyard     bool     watchdog_running;
1858bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1868bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1878bfffbccSCorey Minyard 
1888bfffbccSCorey Minyard     uint8_t device_id;
1898bfffbccSCorey Minyard     uint8_t ipmi_version;
1908bfffbccSCorey Minyard     uint8_t device_rev;
1918bfffbccSCorey Minyard     uint8_t fwrev1;
1928bfffbccSCorey Minyard     uint8_t fwrev2;
1938bfffbccSCorey Minyard     uint8_t mfg_id[3];
1948bfffbccSCorey Minyard     uint8_t product_id[2];
1958bfffbccSCorey Minyard 
1968bfffbccSCorey Minyard     IPMISel sel;
1978bfffbccSCorey Minyard     IPMISdr sdr;
1988bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
1998bfffbccSCorey Minyard 
2008bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2018bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2028bfffbccSCorey Minyard 
2038bfffbccSCorey Minyard     QemuMutex lock;
2048bfffbccSCorey Minyard     /* We allow one event in the buffer */
2058bfffbccSCorey Minyard     uint8_t evtbuf[16];
2068bfffbccSCorey Minyard 
2078bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2088bfffbccSCorey Minyard };
2098bfffbccSCorey Minyard 
2108bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2118bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2128bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2138bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2148bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2158bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2168bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2178bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2188bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2198bfffbccSCorey Minyard 
2208bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2218bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2228bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2238bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2248bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2258bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2268bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2278bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2288bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2298bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2308bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2318bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2328bfffbccSCorey Minyard 
2338bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2348bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2358bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2368bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2378bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2388bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2398bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2408bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2418bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2428bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2438bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2448bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2458bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2468bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2478bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2488bfffbccSCorey Minyard 
2498bfffbccSCorey Minyard 
2508bfffbccSCorey Minyard /* Add a byte to the response. */
2518bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \
2528bfffbccSCorey Minyard     do {                                                   \
2538bfffbccSCorey Minyard         if (*rsp_len >= max_rsp_len) {                     \
2548bfffbccSCorey Minyard             rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;       \
255d13ada5dSCédric Le Goater             return;                                        \
2568bfffbccSCorey Minyard         }                                                  \
2578bfffbccSCorey Minyard         rsp[(*rsp_len)++] = (b);                           \
2588bfffbccSCorey Minyard     } while (0)
2598bfffbccSCorey Minyard 
2608bfffbccSCorey Minyard /* Verify that the received command is a certain length. */
2618bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \
2628bfffbccSCorey Minyard     if (cmd_len < l) {                                     \
2638bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;      \
264d13ada5dSCédric Le Goater         return; \
2658bfffbccSCorey Minyard     }
2668bfffbccSCorey Minyard 
2678bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */
2688bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \
2698bfffbccSCorey Minyard     do {                                                   \
2708bfffbccSCorey Minyard         if ((cmd[off] | (cmd[off + 1] << 8)) != r) {       \
2718bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_RESERVATION;          \
272d13ada5dSCédric Le Goater             return;                                        \
2738bfffbccSCorey Minyard         }                                                  \
2748bfffbccSCorey Minyard     } while (0)
2758bfffbccSCorey Minyard 
2768bfffbccSCorey Minyard 
2778bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2788bfffbccSCorey Minyard 
2798bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2808bfffbccSCorey Minyard {
2818bfffbccSCorey Minyard     int64_t stime;
2828bfffbccSCorey Minyard 
2838bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2848bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
2858bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
2868bfffbccSCorey Minyard }
2878bfffbccSCorey Minyard 
2888bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2898bfffbccSCorey Minyard {
2908bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2918bfffbccSCorey Minyard }
2928bfffbccSCorey Minyard 
2938bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2948bfffbccSCorey Minyard {
2958bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
2968bfffbccSCorey Minyard 
2978bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
2988bfffbccSCorey Minyard }
2998bfffbccSCorey Minyard 
3008bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3018bfffbccSCorey Minyard {
3028bfffbccSCorey Minyard     unsigned int val;
3038bfffbccSCorey Minyard     struct ipmi_time now;
3048bfffbccSCorey Minyard 
3058bfffbccSCorey Minyard     ipmi_gettime(&now);
3068bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3078bfffbccSCorey Minyard     ts[0] = val & 0xff;
3088bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3098bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3108bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3118bfffbccSCorey Minyard }
3128bfffbccSCorey Minyard 
3138bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3148bfffbccSCorey Minyard {
3158bfffbccSCorey Minyard     sdr->reservation++;
3168bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3178bfffbccSCorey Minyard         sdr->reservation = 1;
3188bfffbccSCorey Minyard     }
3198bfffbccSCorey Minyard }
3208bfffbccSCorey Minyard 
3218bfffbccSCorey Minyard static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry,
3228bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3238bfffbccSCorey Minyard {
3248bfffbccSCorey Minyard     if ((len < 5) || (len > 255)) {
3258bfffbccSCorey Minyard         return 1;
3268bfffbccSCorey Minyard     }
3278bfffbccSCorey Minyard 
3288bfffbccSCorey Minyard     if (entry[4] != len - 5) {
3298bfffbccSCorey Minyard         return 1;
3308bfffbccSCorey Minyard     }
3318bfffbccSCorey Minyard 
3328bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3338bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3348bfffbccSCorey Minyard         return 1;
3358bfffbccSCorey Minyard     }
3368bfffbccSCorey Minyard 
3378bfffbccSCorey Minyard     memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len);
3388bfffbccSCorey Minyard     ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff;
3398bfffbccSCorey Minyard     ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
3408bfffbccSCorey Minyard     ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */
3418bfffbccSCorey Minyard 
3428bfffbccSCorey Minyard     if (recid) {
3438bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3448bfffbccSCorey Minyard     }
3458bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3468bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3478bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3488bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3498bfffbccSCorey Minyard     return 0;
3508bfffbccSCorey Minyard }
3518bfffbccSCorey Minyard 
3528bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3538bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3548bfffbccSCorey Minyard {
3558bfffbccSCorey Minyard     unsigned int pos = *retpos;
3568bfffbccSCorey Minyard 
3578bfffbccSCorey Minyard     while (pos < sdr->next_free) {
3588bfffbccSCorey Minyard         uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8);
3598bfffbccSCorey Minyard         unsigned int nextpos = pos + sdr->sdr[pos + 4];
3608bfffbccSCorey Minyard 
3618bfffbccSCorey Minyard         if (trec == recid) {
3628bfffbccSCorey Minyard             if (nextrec) {
3638bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3648bfffbccSCorey Minyard                     *nextrec = 0xffff;
3658bfffbccSCorey Minyard                 } else {
3668bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3678bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3688bfffbccSCorey Minyard                 }
3698bfffbccSCorey Minyard             }
3708bfffbccSCorey Minyard             *retpos = pos;
3718bfffbccSCorey Minyard             return 0;
3728bfffbccSCorey Minyard         }
3738bfffbccSCorey Minyard         pos = nextpos;
3748bfffbccSCorey Minyard     }
3758bfffbccSCorey Minyard     return 1;
3768bfffbccSCorey Minyard }
3778bfffbccSCorey Minyard 
3788bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
3798bfffbccSCorey Minyard {
3808bfffbccSCorey Minyard     sel->reservation++;
3818bfffbccSCorey Minyard     if (sel->reservation == 0) {
3828bfffbccSCorey Minyard         sel->reservation = 1;
3838bfffbccSCorey Minyard     }
3848bfffbccSCorey Minyard }
3858bfffbccSCorey Minyard 
3868bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
3878bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
3888bfffbccSCorey Minyard {
3898bfffbccSCorey Minyard     event[0] = 0xff;
3908bfffbccSCorey Minyard     event[1] = 0xff;
3918bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
3928bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
3938bfffbccSCorey Minyard         ibs->sel.overflow = 1;
3948bfffbccSCorey Minyard         return 1;
3958bfffbccSCorey Minyard     }
3968bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
3978bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
3988bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
3998bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4008bfffbccSCorey Minyard     ibs->sel.next_free++;
4018bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4028bfffbccSCorey Minyard     return 0;
4038bfffbccSCorey Minyard }
4048bfffbccSCorey Minyard 
4058bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4068bfffbccSCorey Minyard {
4078bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4088bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4098bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4108bfffbccSCorey Minyard }
4118bfffbccSCorey Minyard 
4128bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4138bfffbccSCorey Minyard {
4148bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4158bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4168bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4178bfffbccSCorey Minyard }
4188bfffbccSCorey Minyard 
4198bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4208bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4218bfffbccSCorey Minyard {
4228bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4238bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4248bfffbccSCorey Minyard     uint8_t evt[16];
4258bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4268bfffbccSCorey Minyard 
4278bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4288bfffbccSCorey Minyard         return;
4298bfffbccSCorey Minyard     }
4308bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4318bfffbccSCorey Minyard         return;
4328bfffbccSCorey Minyard     }
4338bfffbccSCorey Minyard 
4348bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4358bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4368bfffbccSCorey Minyard     evt[8] = 0;
4378bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4388bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4398bfffbccSCorey Minyard     evt[11] = sens_num;
4408bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4418bfffbccSCorey Minyard     evt[13] = evd1;
4428bfffbccSCorey Minyard     evt[14] = evd2;
4438bfffbccSCorey Minyard     evt[15] = evd3;
4448bfffbccSCorey Minyard 
4458bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4468bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4478bfffbccSCorey Minyard     }
4488bfffbccSCorey Minyard 
4498bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
450d13ada5dSCédric Le Goater         return;
4518bfffbccSCorey Minyard     }
4528bfffbccSCorey Minyard 
4538bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4548bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4558bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4568bfffbccSCorey Minyard }
4578bfffbccSCorey Minyard 
4588bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4598bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4608bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4618bfffbccSCorey Minyard {
4628bfffbccSCorey Minyard     IPMISensor *sens;
4638bfffbccSCorey Minyard     uint16_t mask;
4648bfffbccSCorey Minyard 
4658bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4668bfffbccSCorey Minyard         return;
4678bfffbccSCorey Minyard     }
4688bfffbccSCorey Minyard     if (bit >= 16) {
4698bfffbccSCorey Minyard         return;
4708bfffbccSCorey Minyard     }
4718bfffbccSCorey Minyard 
4728bfffbccSCorey Minyard     mask = (1 << bit);
4738bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
4748bfffbccSCorey Minyard     if (val) {
4758bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
4768bfffbccSCorey Minyard         if (sens->assert_states & mask) {
4778bfffbccSCorey Minyard             return; /* Already asserted */
4788bfffbccSCorey Minyard         }
4798bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
4808bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
4818bfffbccSCorey Minyard             /* Send an event on assert */
4828bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
4838bfffbccSCorey Minyard         }
4848bfffbccSCorey Minyard     } else {
4858bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
4868bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
4878bfffbccSCorey Minyard             return; /* Already deasserted */
4888bfffbccSCorey Minyard         }
4898bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
4908bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
4918bfffbccSCorey Minyard             /* Send an event on deassert */
4928bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
4938bfffbccSCorey Minyard         }
4948bfffbccSCorey Minyard     }
4958bfffbccSCorey Minyard }
4968bfffbccSCorey Minyard 
4978bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
4988bfffbccSCorey Minyard {
4998bfffbccSCorey Minyard     unsigned int i, pos;
5008bfffbccSCorey Minyard     IPMISensor *sens;
5018bfffbccSCorey Minyard 
5028bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5038bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5048bfffbccSCorey Minyard     }
5058bfffbccSCorey Minyard 
5068bfffbccSCorey Minyard     pos = 0;
5078bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
5088bfffbccSCorey Minyard         uint8_t *sdr = s->sdr.sdr + pos;
5098bfffbccSCorey Minyard         unsigned int len = sdr[4];
5108bfffbccSCorey Minyard 
5118bfffbccSCorey Minyard         if (len < 20) {
5128bfffbccSCorey Minyard             continue;
5138bfffbccSCorey Minyard         }
5148bfffbccSCorey Minyard         if ((sdr[3] < 1) || (sdr[3] > 2)) {
5158bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5168bfffbccSCorey Minyard         }
5178bfffbccSCorey Minyard 
5188bfffbccSCorey Minyard         if (sdr[7] > MAX_SENSORS) {
5198bfffbccSCorey Minyard             continue;
5208bfffbccSCorey Minyard         }
5218bfffbccSCorey Minyard         sens = s->sensors + sdr[7];
5228bfffbccSCorey Minyard 
5238bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
5248bfffbccSCorey Minyard         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1);
5258bfffbccSCorey Minyard         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1);
5268bfffbccSCorey Minyard         sens->assert_suppt = sdr[14] | (sdr[15] << 8);
5278bfffbccSCorey Minyard         sens->deassert_suppt = sdr[16] | (sdr[17] << 8);
5288bfffbccSCorey Minyard         sens->states_suppt = sdr[18] | (sdr[19] << 8);
5298bfffbccSCorey Minyard         sens->sensor_type = sdr[12];
5308bfffbccSCorey Minyard         sens->evt_reading_type_code = sdr[13] & 0x7f;
5318bfffbccSCorey Minyard 
5328bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5338bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5348bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5358bfffbccSCorey Minyard     }
5368bfffbccSCorey Minyard }
5378bfffbccSCorey Minyard 
5388bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5398bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5408bfffbccSCorey Minyard {
5418bfffbccSCorey Minyard     if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) {
5428bfffbccSCorey Minyard         return -1;
5438bfffbccSCorey Minyard     }
5448bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5458bfffbccSCorey Minyard     return 0;
5468bfffbccSCorey Minyard }
5478bfffbccSCorey Minyard 
5488bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
5498bfffbccSCorey Minyard {
5508bfffbccSCorey Minyard     int64_t next;
5518bfffbccSCorey Minyard     if (ibs->watchdog_running) {
5528bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
5538bfffbccSCorey Minyard     } else {
5548bfffbccSCorey Minyard         /* Wait a minute */
5558bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
5568bfffbccSCorey Minyard     }
5578bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
5588bfffbccSCorey Minyard }
5598bfffbccSCorey Minyard 
5608bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
5618bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
5628bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
5638bfffbccSCorey Minyard                                     uint8_t msg_id)
5648bfffbccSCorey Minyard {
5658bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
5668bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5678bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5688bfffbccSCorey Minyard     unsigned int netfn;
5698bfffbccSCorey Minyard     uint8_t rsp[MAX_IPMI_MSG_SIZE];
5708bfffbccSCorey Minyard     unsigned int rsp_len_holder = 0;
5718bfffbccSCorey Minyard     unsigned int *rsp_len = &rsp_len_holder;
5728bfffbccSCorey Minyard     unsigned int max_rsp_len = sizeof(rsp);
5738bfffbccSCorey Minyard 
5748bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
5758bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
576d13ada5dSCédric Le Goater     if (max_rsp_len < 3) {
577d13ada5dSCédric Le Goater         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
578d13ada5dSCédric Le Goater         goto out;
579d13ada5dSCédric Le Goater     }
580d13ada5dSCédric Le Goater 
5818bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
5828bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[1]);
5838bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0); /* Assume success */
5848bfffbccSCorey Minyard 
5858bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
5868bfffbccSCorey Minyard     if (cmd_len < 2) {
5878bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
5888bfffbccSCorey Minyard         goto out;
5898bfffbccSCorey Minyard     }
5908bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
5918bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
5928bfffbccSCorey Minyard         goto out;
5938bfffbccSCorey Minyard     }
5948bfffbccSCorey Minyard 
5958bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
5968bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
5978bfffbccSCorey Minyard         rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
5988bfffbccSCorey Minyard         goto out;
5998bfffbccSCorey Minyard     }
6008bfffbccSCorey Minyard 
6018bfffbccSCorey Minyard     netfn = cmd[0] >> 2;
6028bfffbccSCorey Minyard 
6038bfffbccSCorey Minyard     /* Odd netfns are not valid, make sure the command is registered */
6048bfffbccSCorey Minyard     if ((netfn & 1) || !ibs->netfns[netfn / 2] ||
6058bfffbccSCorey Minyard                         (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) ||
6068bfffbccSCorey Minyard                         (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) {
6078bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_CMD;
6088bfffbccSCorey Minyard         goto out;
6098bfffbccSCorey Minyard     }
6108bfffbccSCorey Minyard 
6118bfffbccSCorey Minyard     ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len,
6128bfffbccSCorey Minyard                                                 max_rsp_len);
6138bfffbccSCorey Minyard 
6148bfffbccSCorey Minyard  out:
6158bfffbccSCorey Minyard     k->handle_rsp(s, msg_id, rsp, *rsp_len);
6168bfffbccSCorey Minyard 
6178bfffbccSCorey Minyard     next_timeout(ibs);
6188bfffbccSCorey Minyard }
6198bfffbccSCorey Minyard 
6208bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6218bfffbccSCorey Minyard {
6228bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6238bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6248bfffbccSCorey Minyard 
6258bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6268bfffbccSCorey Minyard         goto out;
6278bfffbccSCorey Minyard     }
6288bfffbccSCorey Minyard 
6298bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6308bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6318bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6328bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6338bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6348bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6358bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6368bfffbccSCorey Minyard             break;
6378bfffbccSCorey Minyard 
6388bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6398bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6408bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6418bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6428bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6438bfffbccSCorey Minyard             break;
6448bfffbccSCorey Minyard 
6458bfffbccSCorey Minyard         default:
6468bfffbccSCorey Minyard             goto do_full_expiry;
6478bfffbccSCorey Minyard         }
6488bfffbccSCorey Minyard 
6498bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
6508bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
6518bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
6528bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
6538bfffbccSCorey Minyard         goto out;
6548bfffbccSCorey Minyard     }
6558bfffbccSCorey Minyard 
6568bfffbccSCorey Minyard  do_full_expiry:
6578bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
6588bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
6598bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
6608bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
6618bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
6628bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
6638bfffbccSCorey Minyard         break;
6648bfffbccSCorey Minyard 
6658bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
6668bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
6678bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
6688bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
6698bfffbccSCorey Minyard         break;
6708bfffbccSCorey Minyard 
6718bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
6728bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6738bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
6748bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
6758bfffbccSCorey Minyard         break;
6768bfffbccSCorey Minyard 
6778bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
6788bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6798bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
6808bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
6818bfffbccSCorey Minyard         break;
6828bfffbccSCorey Minyard     }
6838bfffbccSCorey Minyard 
6848bfffbccSCorey Minyard  out:
6858bfffbccSCorey Minyard     next_timeout(ibs);
6868bfffbccSCorey Minyard }
6878bfffbccSCorey Minyard 
6888bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
6898bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
6908bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
6918bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
6928bfffbccSCorey Minyard {
6938bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
6948bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
6958bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
6968bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
6978bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
6988bfffbccSCorey Minyard }
6998bfffbccSCorey Minyard 
7008bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7018bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
7028bfffbccSCorey Minyard                            uint8_t *rsp, unsigned int *rsp_len,
7038bfffbccSCorey Minyard                            unsigned int max_rsp_len)
7048bfffbccSCorey Minyard {
7058bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */
7068bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7078bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7088bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7098bfffbccSCorey Minyard }
7108bfffbccSCorey Minyard 
7118bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7128bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
7138bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
7148bfffbccSCorey Minyard                             unsigned int max_rsp_len)
7158bfffbccSCorey Minyard {
7168bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7178bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7188bfffbccSCorey Minyard 
7198bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
7208bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7218bfffbccSCorey Minyard     case 0: /* power down */
7228bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7238bfffbccSCorey Minyard         break;
7248bfffbccSCorey Minyard     case 1: /* power up */
7258bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
7268bfffbccSCorey Minyard         break;
7278bfffbccSCorey Minyard     case 2: /* power cycle */
7288bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7298bfffbccSCorey Minyard         break;
7308bfffbccSCorey Minyard     case 3: /* hard reset */
7318bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7328bfffbccSCorey Minyard         break;
7338bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
7348bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
7358bfffbccSCorey Minyard         break;
7368bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
7378bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s,
7388bfffbccSCorey Minyard                              IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
7398bfffbccSCorey Minyard         break;
7408bfffbccSCorey Minyard     default:
7418bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
7428bfffbccSCorey Minyard         return;
7438bfffbccSCorey Minyard     }
744d13ada5dSCédric Le Goater }
7458bfffbccSCorey Minyard 
7468bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
7478bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
7488bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
7498bfffbccSCorey Minyard                           unsigned int max_rsp_len)
7508bfffbccSCorey Minyard {
7518bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_id);
7528bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf);
7538bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f);
7548bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev2);
7558bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->ipmi_version);
7568bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */
7578bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[0]);
7588bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[1]);
7598bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
7608bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[0]);
7618bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[1]);
7628bfffbccSCorey Minyard }
7638bfffbccSCorey Minyard 
7648bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
7658bfffbccSCorey Minyard {
7668bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7678bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7688bfffbccSCorey Minyard     bool irqs_on;
7698bfffbccSCorey Minyard 
7708bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
7718bfffbccSCorey Minyard 
7728bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
7738bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
7748bfffbccSCorey Minyard 
7758bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
7768bfffbccSCorey Minyard }
7778bfffbccSCorey Minyard 
7788bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
7798bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
7808bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
7818bfffbccSCorey Minyard                        unsigned int max_rsp_len)
7828bfffbccSCorey Minyard {
7838bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7848bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7858bfffbccSCorey Minyard 
7868bfffbccSCorey Minyard     /* Disable all interrupts */
7878bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
7888bfffbccSCorey Minyard 
7898bfffbccSCorey Minyard     if (k->reset) {
7908bfffbccSCorey Minyard         k->reset(s, true);
7918bfffbccSCorey Minyard     }
7928bfffbccSCorey Minyard }
7938bfffbccSCorey Minyard 
7948bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
7958bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
7968bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
7978bfffbccSCorey Minyard                        unsigned int max_rsp_len)
7988bfffbccSCorey Minyard {
7998bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8008bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8018bfffbccSCorey Minyard 
8028bfffbccSCorey Minyard     if (k->reset) {
8038bfffbccSCorey Minyard         k->reset(s, false);
8048bfffbccSCorey Minyard     }
8058bfffbccSCorey Minyard }
8068bfffbccSCorey Minyard 
8078bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
8088bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8098bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8108bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8118bfffbccSCorey Minyard {
8128bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8138bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8148bfffbccSCorey Minyard }
8158bfffbccSCorey Minyard 
8168bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8178bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8188bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8198bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8208bfffbccSCorey Minyard {
8218bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
8228bfffbccSCorey Minyard }
8238bfffbccSCorey Minyard 
8248bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
8258bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8268bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8278bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8288bfffbccSCorey Minyard {
8298bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8308bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8318bfffbccSCorey Minyard 
8328bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8338bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
8348bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8358bfffbccSCorey Minyard }
8368bfffbccSCorey Minyard 
8378bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
8388bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8398bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8408bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8418bfffbccSCorey Minyard {
8428bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->msg_flags);
8438bfffbccSCorey Minyard }
8448bfffbccSCorey Minyard 
8458bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
8468bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
8478bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
8488bfffbccSCorey Minyard                             unsigned int max_rsp_len)
8498bfffbccSCorey Minyard {
8508bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8518bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8528bfffbccSCorey Minyard     unsigned int i;
8538bfffbccSCorey Minyard 
8548bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
8558bfffbccSCorey Minyard         rsp[2] = 0x80;
856d13ada5dSCédric Le Goater         return;
8578bfffbccSCorey Minyard     }
8588bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
8598bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
8608bfffbccSCorey Minyard     }
8618bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
8628bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8638bfffbccSCorey Minyard }
8648bfffbccSCorey Minyard 
8658bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
8668bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
8678bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
8688bfffbccSCorey Minyard                     unsigned int max_rsp_len)
8698bfffbccSCorey Minyard {
8708bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
8718bfffbccSCorey Minyard 
8728bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
8738bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
8748bfffbccSCorey Minyard         rsp[2] = 0x80; /* Queue empty */
8758bfffbccSCorey Minyard         goto out;
8768bfffbccSCorey Minyard     }
8778bfffbccSCorey Minyard     rsp[3] = 0; /* Channel 0 */
8788bfffbccSCorey Minyard     *rsp_len += 1;
8798bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
8808bfffbccSCorey Minyard     memcpy(rsp + 4, msg->buf, msg->len);
8818bfffbccSCorey Minyard     *rsp_len += msg->len;
8828bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
8838bfffbccSCorey Minyard     g_free(msg);
8848bfffbccSCorey Minyard 
8858bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
8868bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
8878bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8888bfffbccSCorey Minyard 
8898bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
8908bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8918bfffbccSCorey Minyard     }
8928bfffbccSCorey Minyard 
8938bfffbccSCorey Minyard out:
8948bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
8958bfffbccSCorey Minyard     return;
8968bfffbccSCorey Minyard }
8978bfffbccSCorey Minyard 
8988bfffbccSCorey Minyard static unsigned char
8998bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9008bfffbccSCorey Minyard {
9018bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9028bfffbccSCorey Minyard             csum += *data;
9038bfffbccSCorey Minyard     }
9048bfffbccSCorey Minyard 
9058bfffbccSCorey Minyard     return -csum;
9068bfffbccSCorey Minyard }
9078bfffbccSCorey Minyard 
9088bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9098bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
9108bfffbccSCorey Minyard                      uint8_t *rsp, unsigned int *rsp_len,
9118bfffbccSCorey Minyard                      unsigned int max_rsp_len)
9128bfffbccSCorey Minyard {
9138bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9148bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9158bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9168bfffbccSCorey Minyard     uint8_t *buf;
9178bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9188bfffbccSCorey Minyard 
9198bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
9208bfffbccSCorey Minyard 
9218bfffbccSCorey Minyard     if (cmd[2] != 0) {
9228bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
9238bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
924d13ada5dSCédric Le Goater         return;
9258bfffbccSCorey Minyard     }
9268bfffbccSCorey Minyard 
9278bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(10);
9288bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9298bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
9308bfffbccSCorey Minyard         rsp[2] = 0x83; /* NAK on write */
931d13ada5dSCédric Le Goater         return;
9328bfffbccSCorey Minyard     }
9338bfffbccSCorey Minyard 
9348bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
9358bfffbccSCorey Minyard     cmd_len -= 3;
9368bfffbccSCorey Minyard 
9378bfffbccSCorey Minyard     /*
9388bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
9398bfffbccSCorey Minyard      * be returned in the response.
9408bfffbccSCorey Minyard      */
9418bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
9428bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
943d13ada5dSCédric Le Goater         return; /* No response */
9448bfffbccSCorey Minyard     }
9458bfffbccSCorey Minyard 
9468bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
9478bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
9488bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
9498bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
9508bfffbccSCorey Minyard 
9518bfffbccSCorey Minyard     if (rqLun != 2) {
9528bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
953d13ada5dSCédric Le Goater         return;
9548bfffbccSCorey Minyard     }
9558bfffbccSCorey Minyard 
9568bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
9578bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
9588bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
9598bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
9608bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
9618bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
9628bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
9638bfffbccSCorey Minyard     msg->len = 6;
9648bfffbccSCorey Minyard 
9658bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
9668bfffbccSCorey Minyard         /* Not a command we handle. */
9678bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
9688bfffbccSCorey Minyard         goto end_msg;
9698bfffbccSCorey Minyard     }
9708bfffbccSCorey Minyard 
9718bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
9728bfffbccSCorey Minyard     buf[0] = 0;
9738bfffbccSCorey Minyard     buf[1] = 0;
9748bfffbccSCorey Minyard     buf[2] = 0;
9758bfffbccSCorey Minyard     buf[3] = 0;
9768bfffbccSCorey Minyard     buf[4] = 0x51;
9778bfffbccSCorey Minyard     buf[5] = 0;
9788bfffbccSCorey Minyard     buf[6] = 0;
9798bfffbccSCorey Minyard     buf[7] = 0;
9808bfffbccSCorey Minyard     buf[8] = 0;
9818bfffbccSCorey Minyard     buf[9] = 0;
9828bfffbccSCorey Minyard     buf[10] = 0;
9838bfffbccSCorey Minyard     msg->len += 11;
9848bfffbccSCorey Minyard 
9858bfffbccSCorey Minyard  end_msg:
9868bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
9878bfffbccSCorey Minyard     msg->len++;
9888bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
9898bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
9908bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9918bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
9928bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
9938bfffbccSCorey Minyard }
9948bfffbccSCorey Minyard 
9958bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
9968bfffbccSCorey Minyard {
9978bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
9988bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
9998bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10008bfffbccSCorey Minyard         return;
10018bfffbccSCorey Minyard     }
10028bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10038bfffbccSCorey Minyard 
10048bfffbccSCorey Minyard 
10058bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10068bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10078bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10088bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10098bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10108bfffbccSCorey Minyard     }
10118bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10128bfffbccSCorey Minyard }
10138bfffbccSCorey Minyard 
10148bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10158bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
10168bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
10178bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
10188bfffbccSCorey Minyard {
10198bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
10208bfffbccSCorey Minyard         rsp[2] = 0x80;
1021d13ada5dSCédric Le Goater         return;
10228bfffbccSCorey Minyard     }
10238bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10248bfffbccSCorey Minyard }
10258bfffbccSCorey Minyard 
10268bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10278bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
10288bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
10298bfffbccSCorey Minyard                                unsigned int max_rsp_len)
10308bfffbccSCorey Minyard {
10318bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10328bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10338bfffbccSCorey Minyard     unsigned int val;
10348bfffbccSCorey Minyard 
10358bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
10368bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
10378bfffbccSCorey Minyard     if (val == 0 || val > 5) {
10388bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1039d13ada5dSCédric Le Goater         return;
10408bfffbccSCorey Minyard     }
10418bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
10428bfffbccSCorey Minyard     switch (val) {
10438bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
10448bfffbccSCorey Minyard         break;
10458bfffbccSCorey Minyard 
10468bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
10478bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
10488bfffbccSCorey Minyard         break;
10498bfffbccSCorey Minyard 
10508bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
10518bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
10528bfffbccSCorey Minyard         break;
10538bfffbccSCorey Minyard 
10548bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
10558bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
10568bfffbccSCorey Minyard         break;
10578bfffbccSCorey Minyard 
10588bfffbccSCorey Minyard     default:
10598bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
10608bfffbccSCorey Minyard     }
10618bfffbccSCorey Minyard     if (rsp[2]) {
10628bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1063d13ada5dSCédric Le Goater         return;
10648bfffbccSCorey Minyard     }
10658bfffbccSCorey Minyard 
10668bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
10678bfffbccSCorey Minyard     switch (val) {
10688bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
10698bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
10708bfffbccSCorey Minyard         break;
10718bfffbccSCorey Minyard 
10728bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
10738bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
10748bfffbccSCorey Minyard             /* NMI not supported. */
10758bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1076d13ada5dSCédric Le Goater             return;
10778bfffbccSCorey Minyard         }
10788bfffbccSCorey Minyard     default:
10798bfffbccSCorey Minyard         /* We don't support PRE_SMI */
10808bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1081d13ada5dSCédric Le Goater         return;
10828bfffbccSCorey Minyard     }
10838bfffbccSCorey Minyard 
10848bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
10858bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
10868bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
10878bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
10888bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
10898bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
10908bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
10918bfffbccSCorey Minyard         do_watchdog_reset(ibs);
10928bfffbccSCorey Minyard     } else {
10938bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10948bfffbccSCorey Minyard     }
10958bfffbccSCorey Minyard }
10968bfffbccSCorey Minyard 
10978bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
10988bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
10998bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
11008bfffbccSCorey Minyard                                unsigned int max_rsp_len)
11018bfffbccSCorey Minyard {
11028bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_use);
11038bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_action);
11048bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout);
11058bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_expired);
11068bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11078bfffbccSCorey Minyard         long timeout;
11088bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11098bfffbccSCorey Minyard                    / 100000000);
11108bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(timeout & 0xff);
11118bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff);
11128bfffbccSCorey Minyard     } else {
11138bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11148bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11158bfffbccSCorey Minyard     }
11168bfffbccSCorey Minyard }
11178bfffbccSCorey Minyard 
11188bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11198bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
11208bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
11218bfffbccSCorey Minyard                              unsigned int max_rsp_len)
11228bfffbccSCorey Minyard {
11238bfffbccSCorey Minyard     unsigned int i;
11248bfffbccSCorey Minyard 
11258bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */
11268bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff);
11278bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff);
11288bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
11298bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11308bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11318bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]);
11328bfffbccSCorey Minyard     }
11338bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11348bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]);
11358bfffbccSCorey Minyard     }
11368bfffbccSCorey Minyard     /* Only modal support, reserve supported */
11378bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
11388bfffbccSCorey Minyard }
11398bfffbccSCorey Minyard 
11408bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
11418bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
11428bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
11438bfffbccSCorey Minyard                             unsigned int max_rsp_len)
11448bfffbccSCorey Minyard {
11458bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
11468bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
11478bfffbccSCorey Minyard }
11488bfffbccSCorey Minyard 
11498bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
11508bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
11518bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
11528bfffbccSCorey Minyard                     unsigned int max_rsp_len)
11538bfffbccSCorey Minyard {
11548bfffbccSCorey Minyard     unsigned int pos;
11558bfffbccSCorey Minyard     uint16_t nextrec;
11568bfffbccSCorey Minyard 
11578bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
11588bfffbccSCorey Minyard     if (cmd[6]) {
11598bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
11608bfffbccSCorey Minyard     }
11618bfffbccSCorey Minyard     pos = 0;
11628bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
11638bfffbccSCorey Minyard                        &pos, &nextrec)) {
11648bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1165d13ada5dSCédric Le Goater         return;
11668bfffbccSCorey Minyard     }
11678bfffbccSCorey Minyard     if (cmd[6] > (ibs->sdr.sdr[pos + 4])) {
11688bfffbccSCorey Minyard         rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1169d13ada5dSCédric Le Goater         return;
11708bfffbccSCorey Minyard     }
11718bfffbccSCorey Minyard 
11728bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(nextrec & 0xff);
11738bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
11748bfffbccSCorey Minyard 
11758bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
11768bfffbccSCorey Minyard         cmd[7] = ibs->sdr.sdr[pos + 4] - cmd[6];
11778bfffbccSCorey Minyard     }
11788bfffbccSCorey Minyard 
11798bfffbccSCorey Minyard     if ((cmd[7] + *rsp_len) > max_rsp_len) {
11808bfffbccSCorey Minyard         rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1181d13ada5dSCédric Le Goater         return;
11828bfffbccSCorey Minyard     }
11838bfffbccSCorey Minyard     memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
11848bfffbccSCorey Minyard     *rsp_len += cmd[7];
11858bfffbccSCorey Minyard }
11868bfffbccSCorey Minyard 
11878bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
11888bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
11898bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
11908bfffbccSCorey Minyard                     unsigned int max_rsp_len)
11918bfffbccSCorey Minyard {
11928bfffbccSCorey Minyard     uint16_t recid;
11938bfffbccSCorey Minyard 
11948bfffbccSCorey Minyard     if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) {
11958bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1196d13ada5dSCédric Le Goater         return;
11978bfffbccSCorey Minyard     }
11988bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(recid & 0xff);
11998bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
12008bfffbccSCorey Minyard }
12018bfffbccSCorey Minyard 
12028bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12038bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12048bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12058bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12068bfffbccSCorey Minyard {
12078bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12088bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
12098bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
12108bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1211d13ada5dSCédric Le Goater         return;
12128bfffbccSCorey Minyard     }
12138bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12148bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12158bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12168bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
12178bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12188bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12198bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
12208bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12218bfffbccSCorey Minyard     } else {
12228bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
12238bfffbccSCorey Minyard         return;
12248bfffbccSCorey Minyard     }
1225d13ada5dSCédric Le Goater }
12268bfffbccSCorey Minyard 
12278bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
12288bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
12298bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
12308bfffbccSCorey Minyard                          unsigned int max_rsp_len)
12318bfffbccSCorey Minyard {
12328bfffbccSCorey Minyard     unsigned int i, val;
12338bfffbccSCorey Minyard 
12348bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */
12358bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff);
12368bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff);
12378bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
12388bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
12398bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
12408bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
12418bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]);
12428bfffbccSCorey Minyard     }
12438bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
12448bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]);
12458bfffbccSCorey Minyard     }
12468bfffbccSCorey Minyard     /* Only support Reserve SEL */
12478bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
12488bfffbccSCorey Minyard }
12498bfffbccSCorey Minyard 
12508bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
12518bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
12528bfffbccSCorey Minyard                         uint8_t *rsp, unsigned int *rsp_len,
12538bfffbccSCorey Minyard                         unsigned int max_rsp_len)
12548bfffbccSCorey Minyard {
12558bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
12568bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
12578bfffbccSCorey Minyard }
12588bfffbccSCorey Minyard 
12598bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
12608bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12618bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12628bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12638bfffbccSCorey Minyard {
12648bfffbccSCorey Minyard     unsigned int val;
12658bfffbccSCorey Minyard 
12668bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12678bfffbccSCorey Minyard     if (cmd[6]) {
12688bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
12698bfffbccSCorey Minyard     }
12708bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
12718bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1272d13ada5dSCédric Le Goater         return;
12738bfffbccSCorey Minyard     }
12748bfffbccSCorey Minyard     if (cmd[6] > 15) {
12758bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1276d13ada5dSCédric Le Goater         return;
12778bfffbccSCorey Minyard     }
12788bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
12798bfffbccSCorey Minyard         cmd[7] = 16;
12808bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
12818bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1282d13ada5dSCédric Le Goater         return;
12838bfffbccSCorey Minyard     } else {
12848bfffbccSCorey Minyard         cmd[7] += cmd[6];
12858bfffbccSCorey Minyard     }
12868bfffbccSCorey Minyard 
12878bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
12888bfffbccSCorey Minyard     if (val == 0xffff) {
12898bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
12908bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
12918bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1292d13ada5dSCédric Le Goater         return;
12938bfffbccSCorey Minyard     }
12948bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
12958bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
12968bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
12978bfffbccSCorey Minyard     } else {
12988bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((val + 1) & 0xff);
12998bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff);
13008bfffbccSCorey Minyard     }
13018bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
13028bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
13038bfffbccSCorey Minyard     }
13048bfffbccSCorey Minyard }
13058bfffbccSCorey Minyard 
13068bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13078bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
13088bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
13098bfffbccSCorey Minyard                           unsigned int max_rsp_len)
13108bfffbccSCorey Minyard {
13118bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(18);
13128bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
13138bfffbccSCorey Minyard         rsp[2] = IPMI_CC_OUT_OF_SPACE;
1314d13ada5dSCédric Le Goater         return;
13158bfffbccSCorey Minyard     }
13168bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
13178bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[2]);
13188bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[3]);
13198bfffbccSCorey Minyard }
13208bfffbccSCorey Minyard 
13218bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13228bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
13238bfffbccSCorey Minyard                       uint8_t *rsp, unsigned int *rsp_len,
13248bfffbccSCorey Minyard                       unsigned int max_rsp_len)
13258bfffbccSCorey Minyard {
13268bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
13278bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
13288bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13298bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1330d13ada5dSCédric Le Goater         return;
13318bfffbccSCorey Minyard     }
13328bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13338bfffbccSCorey Minyard         ibs->sel.next_free = 0;
13348bfffbccSCorey Minyard         ibs->sel.overflow = 0;
13358bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
13368bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
13378bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
13388bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
13398bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
13408bfffbccSCorey Minyard     } else {
13418bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
13428bfffbccSCorey Minyard         return;
13438bfffbccSCorey Minyard     }
1344d13ada5dSCédric Le Goater }
13458bfffbccSCorey Minyard 
13468bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
13478bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
13488bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
13498bfffbccSCorey Minyard                          unsigned int max_rsp_len)
13508bfffbccSCorey Minyard {
13518bfffbccSCorey Minyard     uint32_t val;
13528bfffbccSCorey Minyard     struct ipmi_time now;
13538bfffbccSCorey Minyard 
13548bfffbccSCorey Minyard     ipmi_gettime(&now);
13558bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
13568bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
13578bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
13588bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
13598bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
13608bfffbccSCorey Minyard }
13618bfffbccSCorey Minyard 
13628bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
13638bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
13648bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
13658bfffbccSCorey Minyard                          unsigned int max_rsp_len)
13668bfffbccSCorey Minyard {
13678bfffbccSCorey Minyard     uint32_t val;
13688bfffbccSCorey Minyard     struct ipmi_time now;
13698bfffbccSCorey Minyard 
13708bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(6);
13718bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
13728bfffbccSCorey Minyard     ipmi_gettime(&now);
13738bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
13748bfffbccSCorey Minyard }
13758bfffbccSCorey Minyard 
13768bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
13778bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
13788bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
13798bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
13808bfffbccSCorey Minyard {
13818bfffbccSCorey Minyard     IPMISensor *sens;
13828bfffbccSCorey Minyard 
13838bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
13848bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
13858bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
13868bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1387d13ada5dSCédric Le Goater         return;
13888bfffbccSCorey Minyard     }
13898bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
13908bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
13918bfffbccSCorey Minyard     case 0: /* Do not change */
13928bfffbccSCorey Minyard         break;
13938bfffbccSCorey Minyard     case 1: /* Enable bits */
13948bfffbccSCorey Minyard         if (cmd_len > 4) {
13958bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
13968bfffbccSCorey Minyard         }
13978bfffbccSCorey Minyard         if (cmd_len > 5) {
13988bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
13998bfffbccSCorey Minyard         }
14008bfffbccSCorey Minyard         if (cmd_len > 6) {
14018bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
14028bfffbccSCorey Minyard         }
14038bfffbccSCorey Minyard         if (cmd_len > 7) {
14048bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
14058bfffbccSCorey Minyard         }
14068bfffbccSCorey Minyard         break;
14078bfffbccSCorey Minyard     case 2: /* Disable bits */
14088bfffbccSCorey Minyard         if (cmd_len > 4) {
14098bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14108bfffbccSCorey Minyard         }
14118bfffbccSCorey Minyard         if (cmd_len > 5) {
14128bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14138bfffbccSCorey Minyard         }
14148bfffbccSCorey Minyard         if (cmd_len > 6) {
14158bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14168bfffbccSCorey Minyard         }
14178bfffbccSCorey Minyard         if (cmd_len > 7) {
14188bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14198bfffbccSCorey Minyard         }
14208bfffbccSCorey Minyard         break;
14218bfffbccSCorey Minyard     case 3:
14228bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1423d13ada5dSCédric Le Goater         return;
14248bfffbccSCorey Minyard     }
14258bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14268bfffbccSCorey Minyard }
14278bfffbccSCorey Minyard 
14288bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14298bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14308bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14318bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14328bfffbccSCorey Minyard {
14338bfffbccSCorey Minyard     IPMISensor *sens;
14348bfffbccSCorey Minyard 
14358bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
14368bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14378bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14388bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1439d13ada5dSCédric Le Goater         return;
14408bfffbccSCorey Minyard     }
14418bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14428bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
14438bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff);
14448bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
14458bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
14468bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
14478bfffbccSCorey Minyard }
14488bfffbccSCorey Minyard 
14498bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
14508bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
14518bfffbccSCorey Minyard                               uint8_t *rsp, unsigned int *rsp_len,
14528bfffbccSCorey Minyard                               unsigned int max_rsp_len)
14538bfffbccSCorey Minyard {
14548bfffbccSCorey Minyard     IPMISensor *sens;
14558bfffbccSCorey Minyard 
14568bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
14578bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14588bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14598bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1460d13ada5dSCédric Le Goater         return;
14618bfffbccSCorey Minyard     }
14628bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14638bfffbccSCorey Minyard 
14648bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
14658bfffbccSCorey Minyard         /* Just clear everything */
14668bfffbccSCorey Minyard         sens->states = 0;
14678bfffbccSCorey Minyard         return;
14688bfffbccSCorey Minyard     }
1469d13ada5dSCédric Le Goater }
14708bfffbccSCorey Minyard 
14718bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
14728bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14738bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14748bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14758bfffbccSCorey Minyard {
14768bfffbccSCorey Minyard     IPMISensor *sens;
14778bfffbccSCorey Minyard 
14788bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
14798bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14808bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14818bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1482d13ada5dSCédric Le Goater         return;
14838bfffbccSCorey Minyard     }
14848bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14858bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
14868bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
14878bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_states & 0xff);
14888bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
14898bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
14908bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
14918bfffbccSCorey Minyard }
14928bfffbccSCorey Minyard 
14938bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
14948bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
14958bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
14968bfffbccSCorey Minyard                                unsigned int max_rsp_len)
14978bfffbccSCorey Minyard {
14988bfffbccSCorey Minyard     IPMISensor *sens;
14998bfffbccSCorey Minyard 
15008bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
15018bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
15028bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15038bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1504d13ada5dSCédric Le Goater         return;
15058bfffbccSCorey Minyard     }
15068bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15078bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15088bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15098bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->states & 0xff);
15108bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
15118bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
15128bfffbccSCorey Minyard     }
15138bfffbccSCorey Minyard }
15148bfffbccSCorey Minyard 
151562a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
15168bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
15178bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
15188bfffbccSCorey Minyard     [IPMI_CMD_CHASSIS_CONTROL] = chassis_control
15198bfffbccSCorey Minyard };
15208bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
152162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
15228bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
15238bfffbccSCorey Minyard };
15248bfffbccSCorey Minyard 
152562a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
15268bfffbccSCorey Minyard     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
15278bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
15288bfffbccSCorey Minyard     [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
15298bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
15308bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading
15318bfffbccSCorey Minyard };
15328bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
153362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
15348bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
15358bfffbccSCorey Minyard };
15368bfffbccSCorey Minyard 
153762a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
15388bfffbccSCorey Minyard     [IPMI_CMD_GET_DEVICE_ID] = get_device_id,
15398bfffbccSCorey Minyard     [IPMI_CMD_COLD_RESET] = cold_reset,
15408bfffbccSCorey Minyard     [IPMI_CMD_WARM_RESET] = warm_reset,
15418bfffbccSCorey Minyard     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
15428bfffbccSCorey Minyard     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
15438bfffbccSCorey Minyard     [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
15448bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags,
15458bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG] = get_msg,
15468bfffbccSCorey Minyard     [IPMI_CMD_SEND_MSG] = send_msg,
15478bfffbccSCorey Minyard     [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf,
15488bfffbccSCorey Minyard     [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer,
15498bfffbccSCorey Minyard     [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer,
15508bfffbccSCorey Minyard     [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
15518bfffbccSCorey Minyard };
15528bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
155362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
15548bfffbccSCorey Minyard     .cmd_handlers = app_cmds
15558bfffbccSCorey Minyard };
15568bfffbccSCorey Minyard 
155762a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
15588bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
15598bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
15608bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR] = get_sdr,
15618bfffbccSCorey Minyard     [IPMI_CMD_ADD_SDR] = add_sdr,
15628bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep,
15638bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_INFO] = get_sel_info,
15648bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SEL] = reserve_sel,
15658bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry,
15668bfffbccSCorey Minyard     [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry,
15678bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SEL] = clear_sel,
15688bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = get_sel_time,
15698bfffbccSCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = set_sel_time,
15708bfffbccSCorey Minyard };
15718bfffbccSCorey Minyard 
15728bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
157362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
15748bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
15758bfffbccSCorey Minyard };
15768bfffbccSCorey Minyard 
15778bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
15788bfffbccSCorey Minyard {
15798bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
15808bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
15818bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
15828bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
15838bfffbccSCorey Minyard }
15848bfffbccSCorey Minyard 
15858bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
15868bfffbccSCorey Minyard     /* Watchdog device */
15878bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
15888bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
15898bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15908bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
15918bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
15928bfffbccSCorey Minyard     /* End */
15938bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
15948bfffbccSCorey Minyard };
15958bfffbccSCorey Minyard 
1596bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1597bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1598bd66bcfcSCorey Minyard     .version_id = 1,
1599bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1600bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1601bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1602bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1603bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1604bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1605bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1606bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1607bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1608bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1609bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1610bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1611bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1612bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1613bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1614bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1615bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1616bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1617bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1618bd66bcfcSCorey Minyard                        IPMIBmcSim),
1619bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1620bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1621bd66bcfcSCorey Minyard     }
1622bd66bcfcSCorey Minyard };
1623bd66bcfcSCorey Minyard 
16248bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj)
16258bfffbccSCorey Minyard {
16268bfffbccSCorey Minyard     IPMIBmc *b = IPMI_BMC(obj);
16278bfffbccSCorey Minyard     unsigned int i;
16288bfffbccSCorey Minyard     unsigned int recid;
16298bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
16308bfffbccSCorey Minyard 
16318bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
16328bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
16338bfffbccSCorey Minyard 
16348bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
16358bfffbccSCorey Minyard     ibs->device_id = 0x20;
16368bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
16378bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
16388bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
16398bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
16408bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
16418bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
16428bfffbccSCorey Minyard     }
16438bfffbccSCorey Minyard 
16448bfffbccSCorey Minyard     for (i = 0;;) {
16458bfffbccSCorey Minyard         int len;
16468bfffbccSCorey Minyard         if ((i + 5) > sizeof(init_sdrs)) {
1647*7cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
16488bfffbccSCorey Minyard             return;
16498bfffbccSCorey Minyard         }
16508bfffbccSCorey Minyard         len = init_sdrs[i + 4];
16518bfffbccSCorey Minyard         recid = init_sdrs[i] | (init_sdrs[i + 1] << 8);
16528bfffbccSCorey Minyard         if (recid == 0xffff) {
16538bfffbccSCorey Minyard             break;
16548bfffbccSCorey Minyard         }
16558bfffbccSCorey Minyard         if ((i + len + 5) > sizeof(init_sdrs)) {
1656*7cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
16578bfffbccSCorey Minyard             return;
16588bfffbccSCorey Minyard         }
16598bfffbccSCorey Minyard         sdr_add_entry(ibs, init_sdrs + i, len, NULL);
16608bfffbccSCorey Minyard         i += len + 5;
16618bfffbccSCorey Minyard     }
16628bfffbccSCorey Minyard 
16638bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
16648bfffbccSCorey Minyard     register_cmds(ibs);
16658bfffbccSCorey Minyard 
16668bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1667bd66bcfcSCorey Minyard 
1668bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
16698bfffbccSCorey Minyard }
16708bfffbccSCorey Minyard 
16718bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
16728bfffbccSCorey Minyard {
16738bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
16748bfffbccSCorey Minyard 
16758bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
16768bfffbccSCorey Minyard }
16778bfffbccSCorey Minyard 
16788bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
16798bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
16808bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
16818bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
16828bfffbccSCorey Minyard     .instance_init = ipmi_sim_init,
16838bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
16848bfffbccSCorey Minyard };
16858bfffbccSCorey Minyard 
16868bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
16878bfffbccSCorey Minyard {
16888bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
16898bfffbccSCorey Minyard }
16908bfffbccSCorey Minyard 
16918bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1692