xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision a2295f0a5871e2b9d8ea24bc3a1d2e02bda6ef2d)
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 
321*a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
322*a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3238bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3248bfffbccSCorey Minyard {
325*a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
326*a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
327*a2295f0aSCédric Le Goater 
328*a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3298bfffbccSCorey Minyard         return 1;
3308bfffbccSCorey Minyard     }
3318bfffbccSCorey Minyard 
332*a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3338bfffbccSCorey Minyard         return 1;
3348bfffbccSCorey Minyard     }
3358bfffbccSCorey Minyard 
3368bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3378bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3388bfffbccSCorey Minyard         return 1;
3398bfffbccSCorey Minyard     }
3408bfffbccSCorey Minyard 
341*a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
342*a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
343*a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
344*a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3458bfffbccSCorey Minyard 
3468bfffbccSCorey Minyard     if (recid) {
3478bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3488bfffbccSCorey Minyard     }
3498bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3508bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3518bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3528bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3538bfffbccSCorey Minyard     return 0;
3548bfffbccSCorey Minyard }
3558bfffbccSCorey Minyard 
3568bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3578bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3588bfffbccSCorey Minyard {
3598bfffbccSCorey Minyard     unsigned int pos = *retpos;
3608bfffbccSCorey Minyard 
3618bfffbccSCorey Minyard     while (pos < sdr->next_free) {
362*a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
363*a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
364*a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
365*a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3668bfffbccSCorey Minyard 
3678bfffbccSCorey Minyard         if (trec == recid) {
3688bfffbccSCorey Minyard             if (nextrec) {
3698bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3708bfffbccSCorey Minyard                     *nextrec = 0xffff;
3718bfffbccSCorey Minyard                 } else {
3728bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3738bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3748bfffbccSCorey Minyard                 }
3758bfffbccSCorey Minyard             }
3768bfffbccSCorey Minyard             *retpos = pos;
3778bfffbccSCorey Minyard             return 0;
3788bfffbccSCorey Minyard         }
3798bfffbccSCorey Minyard         pos = nextpos;
3808bfffbccSCorey Minyard     }
3818bfffbccSCorey Minyard     return 1;
3828bfffbccSCorey Minyard }
3838bfffbccSCorey Minyard 
3848bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
3858bfffbccSCorey Minyard {
3868bfffbccSCorey Minyard     sel->reservation++;
3878bfffbccSCorey Minyard     if (sel->reservation == 0) {
3888bfffbccSCorey Minyard         sel->reservation = 1;
3898bfffbccSCorey Minyard     }
3908bfffbccSCorey Minyard }
3918bfffbccSCorey Minyard 
3928bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
3938bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
3948bfffbccSCorey Minyard {
3958bfffbccSCorey Minyard     event[0] = 0xff;
3968bfffbccSCorey Minyard     event[1] = 0xff;
3978bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
3988bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
3998bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4008bfffbccSCorey Minyard         return 1;
4018bfffbccSCorey Minyard     }
4028bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4038bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4048bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4058bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4068bfffbccSCorey Minyard     ibs->sel.next_free++;
4078bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4088bfffbccSCorey Minyard     return 0;
4098bfffbccSCorey Minyard }
4108bfffbccSCorey Minyard 
4118bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4128bfffbccSCorey Minyard {
4138bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4148bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4158bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4168bfffbccSCorey Minyard }
4178bfffbccSCorey Minyard 
4188bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4198bfffbccSCorey Minyard {
4208bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4218bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4228bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4238bfffbccSCorey Minyard }
4248bfffbccSCorey Minyard 
4258bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4268bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4278bfffbccSCorey Minyard {
4288bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4298bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4308bfffbccSCorey Minyard     uint8_t evt[16];
4318bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4328bfffbccSCorey Minyard 
4338bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4348bfffbccSCorey Minyard         return;
4358bfffbccSCorey Minyard     }
4368bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4378bfffbccSCorey Minyard         return;
4388bfffbccSCorey Minyard     }
4398bfffbccSCorey Minyard 
4408bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4418bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4428bfffbccSCorey Minyard     evt[8] = 0;
4438bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4448bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4458bfffbccSCorey Minyard     evt[11] = sens_num;
4468bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4478bfffbccSCorey Minyard     evt[13] = evd1;
4488bfffbccSCorey Minyard     evt[14] = evd2;
4498bfffbccSCorey Minyard     evt[15] = evd3;
4508bfffbccSCorey Minyard 
4518bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4528bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4538bfffbccSCorey Minyard     }
4548bfffbccSCorey Minyard 
4558bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
456d13ada5dSCédric Le Goater         return;
4578bfffbccSCorey Minyard     }
4588bfffbccSCorey Minyard 
4598bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4608bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4618bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4628bfffbccSCorey Minyard }
4638bfffbccSCorey Minyard 
4648bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4658bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4668bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4678bfffbccSCorey Minyard {
4688bfffbccSCorey Minyard     IPMISensor *sens;
4698bfffbccSCorey Minyard     uint16_t mask;
4708bfffbccSCorey Minyard 
4718bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4728bfffbccSCorey Minyard         return;
4738bfffbccSCorey Minyard     }
4748bfffbccSCorey Minyard     if (bit >= 16) {
4758bfffbccSCorey Minyard         return;
4768bfffbccSCorey Minyard     }
4778bfffbccSCorey Minyard 
4788bfffbccSCorey Minyard     mask = (1 << bit);
4798bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
4808bfffbccSCorey Minyard     if (val) {
4818bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
4828bfffbccSCorey Minyard         if (sens->assert_states & mask) {
4838bfffbccSCorey Minyard             return; /* Already asserted */
4848bfffbccSCorey Minyard         }
4858bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
4868bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
4878bfffbccSCorey Minyard             /* Send an event on assert */
4888bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
4898bfffbccSCorey Minyard         }
4908bfffbccSCorey Minyard     } else {
4918bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
4928bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
4938bfffbccSCorey Minyard             return; /* Already deasserted */
4948bfffbccSCorey Minyard         }
4958bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
4968bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
4978bfffbccSCorey Minyard             /* Send an event on deassert */
4988bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
4998bfffbccSCorey Minyard         }
5008bfffbccSCorey Minyard     }
5018bfffbccSCorey Minyard }
5028bfffbccSCorey Minyard 
5038bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5048bfffbccSCorey Minyard {
5058bfffbccSCorey Minyard     unsigned int i, pos;
5068bfffbccSCorey Minyard     IPMISensor *sens;
5078bfffbccSCorey Minyard 
5088bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5098bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5108bfffbccSCorey Minyard     }
5118bfffbccSCorey Minyard 
5128bfffbccSCorey Minyard     pos = 0;
5138bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
514*a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
515*a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
516*a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5178bfffbccSCorey Minyard 
5188bfffbccSCorey Minyard         if (len < 20) {
5198bfffbccSCorey Minyard             continue;
5208bfffbccSCorey Minyard         }
521*a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5228bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5238bfffbccSCorey Minyard         }
5248bfffbccSCorey Minyard 
525*a2295f0aSCédric Le Goater         if (sdr->sensor_owner_number > MAX_SENSORS) {
5268bfffbccSCorey Minyard             continue;
5278bfffbccSCorey Minyard         }
528*a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5298bfffbccSCorey Minyard 
5308bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
531*a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
532*a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
533*a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
534*a2295f0aSCédric Le Goater         sens->deassert_suppt =
535*a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
536*a2295f0aSCédric Le Goater         sens->states_suppt =
537*a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
538*a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
539*a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5408bfffbccSCorey Minyard 
5418bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5428bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5438bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5448bfffbccSCorey Minyard     }
5458bfffbccSCorey Minyard }
5468bfffbccSCorey Minyard 
5478bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5488bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5498bfffbccSCorey Minyard {
5508bfffbccSCorey Minyard     if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) {
5518bfffbccSCorey Minyard         return -1;
5528bfffbccSCorey Minyard     }
5538bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5548bfffbccSCorey Minyard     return 0;
5558bfffbccSCorey Minyard }
5568bfffbccSCorey Minyard 
5578bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
5588bfffbccSCorey Minyard {
5598bfffbccSCorey Minyard     int64_t next;
5608bfffbccSCorey Minyard     if (ibs->watchdog_running) {
5618bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
5628bfffbccSCorey Minyard     } else {
5638bfffbccSCorey Minyard         /* Wait a minute */
5648bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
5658bfffbccSCorey Minyard     }
5668bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
5678bfffbccSCorey Minyard }
5688bfffbccSCorey Minyard 
5698bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
5708bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
5718bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
5728bfffbccSCorey Minyard                                     uint8_t msg_id)
5738bfffbccSCorey Minyard {
5748bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
5758bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5768bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5778bfffbccSCorey Minyard     unsigned int netfn;
5788bfffbccSCorey Minyard     uint8_t rsp[MAX_IPMI_MSG_SIZE];
5798bfffbccSCorey Minyard     unsigned int rsp_len_holder = 0;
5808bfffbccSCorey Minyard     unsigned int *rsp_len = &rsp_len_holder;
5818bfffbccSCorey Minyard     unsigned int max_rsp_len = sizeof(rsp);
5828bfffbccSCorey Minyard 
5838bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
5848bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
585d13ada5dSCédric Le Goater     if (max_rsp_len < 3) {
586d13ada5dSCédric Le Goater         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
587d13ada5dSCédric Le Goater         goto out;
588d13ada5dSCédric Le Goater     }
589d13ada5dSCédric Le Goater 
5908bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
5918bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[1]);
5928bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0); /* Assume success */
5938bfffbccSCorey Minyard 
5948bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
5958bfffbccSCorey Minyard     if (cmd_len < 2) {
5968bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
5978bfffbccSCorey Minyard         goto out;
5988bfffbccSCorey Minyard     }
5998bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6008bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
6018bfffbccSCorey Minyard         goto out;
6028bfffbccSCorey Minyard     }
6038bfffbccSCorey Minyard 
6048bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6058bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6068bfffbccSCorey Minyard         rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
6078bfffbccSCorey Minyard         goto out;
6088bfffbccSCorey Minyard     }
6098bfffbccSCorey Minyard 
6108bfffbccSCorey Minyard     netfn = cmd[0] >> 2;
6118bfffbccSCorey Minyard 
6128bfffbccSCorey Minyard     /* Odd netfns are not valid, make sure the command is registered */
6138bfffbccSCorey Minyard     if ((netfn & 1) || !ibs->netfns[netfn / 2] ||
6148bfffbccSCorey Minyard                         (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) ||
6158bfffbccSCorey Minyard                         (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) {
6168bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_CMD;
6178bfffbccSCorey Minyard         goto out;
6188bfffbccSCorey Minyard     }
6198bfffbccSCorey Minyard 
6208bfffbccSCorey Minyard     ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len,
6218bfffbccSCorey Minyard                                                 max_rsp_len);
6228bfffbccSCorey Minyard 
6238bfffbccSCorey Minyard  out:
6248bfffbccSCorey Minyard     k->handle_rsp(s, msg_id, rsp, *rsp_len);
6258bfffbccSCorey Minyard 
6268bfffbccSCorey Minyard     next_timeout(ibs);
6278bfffbccSCorey Minyard }
6288bfffbccSCorey Minyard 
6298bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6308bfffbccSCorey Minyard {
6318bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6328bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6338bfffbccSCorey Minyard 
6348bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6358bfffbccSCorey Minyard         goto out;
6368bfffbccSCorey Minyard     }
6378bfffbccSCorey Minyard 
6388bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6398bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6408bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6418bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6428bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6438bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6448bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6458bfffbccSCorey Minyard             break;
6468bfffbccSCorey Minyard 
6478bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6488bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6498bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6508bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6518bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6528bfffbccSCorey Minyard             break;
6538bfffbccSCorey Minyard 
6548bfffbccSCorey Minyard         default:
6558bfffbccSCorey Minyard             goto do_full_expiry;
6568bfffbccSCorey Minyard         }
6578bfffbccSCorey Minyard 
6588bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
6598bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
6608bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
6618bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
6628bfffbccSCorey Minyard         goto out;
6638bfffbccSCorey Minyard     }
6648bfffbccSCorey Minyard 
6658bfffbccSCorey Minyard  do_full_expiry:
6668bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
6678bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
6688bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
6698bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
6708bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
6718bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
6728bfffbccSCorey Minyard         break;
6738bfffbccSCorey Minyard 
6748bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
6758bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
6768bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
6778bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
6788bfffbccSCorey Minyard         break;
6798bfffbccSCorey Minyard 
6808bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
6818bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6828bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
6838bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
6848bfffbccSCorey Minyard         break;
6858bfffbccSCorey Minyard 
6868bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
6878bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6888bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
6898bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
6908bfffbccSCorey Minyard         break;
6918bfffbccSCorey Minyard     }
6928bfffbccSCorey Minyard 
6938bfffbccSCorey Minyard  out:
6948bfffbccSCorey Minyard     next_timeout(ibs);
6958bfffbccSCorey Minyard }
6968bfffbccSCorey Minyard 
6978bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
6988bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
6998bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
7008bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
7018bfffbccSCorey Minyard {
7028bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7038bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7048bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7058bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7068bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7078bfffbccSCorey Minyard }
7088bfffbccSCorey Minyard 
7098bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7108bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
7118bfffbccSCorey Minyard                            uint8_t *rsp, unsigned int *rsp_len,
7128bfffbccSCorey Minyard                            unsigned int max_rsp_len)
7138bfffbccSCorey Minyard {
7148bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */
7158bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7168bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7178bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7188bfffbccSCorey Minyard }
7198bfffbccSCorey Minyard 
7208bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7218bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
7228bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
7238bfffbccSCorey Minyard                             unsigned int max_rsp_len)
7248bfffbccSCorey Minyard {
7258bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7268bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7278bfffbccSCorey Minyard 
7288bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
7298bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7308bfffbccSCorey Minyard     case 0: /* power down */
7318bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7328bfffbccSCorey Minyard         break;
7338bfffbccSCorey Minyard     case 1: /* power up */
7348bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
7358bfffbccSCorey Minyard         break;
7368bfffbccSCorey Minyard     case 2: /* power cycle */
7378bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7388bfffbccSCorey Minyard         break;
7398bfffbccSCorey Minyard     case 3: /* hard reset */
7408bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7418bfffbccSCorey Minyard         break;
7428bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
7438bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
7448bfffbccSCorey Minyard         break;
7458bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
7468bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s,
7478bfffbccSCorey Minyard                              IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
7488bfffbccSCorey Minyard         break;
7498bfffbccSCorey Minyard     default:
7508bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
7518bfffbccSCorey Minyard         return;
7528bfffbccSCorey Minyard     }
753d13ada5dSCédric Le Goater }
7548bfffbccSCorey Minyard 
7558bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
7568bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
7578bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
7588bfffbccSCorey Minyard                           unsigned int max_rsp_len)
7598bfffbccSCorey Minyard {
7608bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_id);
7618bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf);
7628bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f);
7638bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev2);
7648bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->ipmi_version);
7658bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */
7668bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[0]);
7678bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[1]);
7688bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
7698bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[0]);
7708bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[1]);
7718bfffbccSCorey Minyard }
7728bfffbccSCorey Minyard 
7738bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
7748bfffbccSCorey Minyard {
7758bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7768bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7778bfffbccSCorey Minyard     bool irqs_on;
7788bfffbccSCorey Minyard 
7798bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
7808bfffbccSCorey Minyard 
7818bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
7828bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
7838bfffbccSCorey Minyard 
7848bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
7858bfffbccSCorey Minyard }
7868bfffbccSCorey Minyard 
7878bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
7888bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
7898bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
7908bfffbccSCorey Minyard                        unsigned int max_rsp_len)
7918bfffbccSCorey Minyard {
7928bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7938bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7948bfffbccSCorey Minyard 
7958bfffbccSCorey Minyard     /* Disable all interrupts */
7968bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
7978bfffbccSCorey Minyard 
7988bfffbccSCorey Minyard     if (k->reset) {
7998bfffbccSCorey Minyard         k->reset(s, true);
8008bfffbccSCorey Minyard     }
8018bfffbccSCorey Minyard }
8028bfffbccSCorey Minyard 
8038bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8048bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
8058bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
8068bfffbccSCorey Minyard                        unsigned int max_rsp_len)
8078bfffbccSCorey Minyard {
8088bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8098bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8108bfffbccSCorey Minyard 
8118bfffbccSCorey Minyard     if (k->reset) {
8128bfffbccSCorey Minyard         k->reset(s, false);
8138bfffbccSCorey Minyard     }
8148bfffbccSCorey Minyard }
8158bfffbccSCorey Minyard 
8168bfffbccSCorey Minyard static void set_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_CHECK_CMD_LEN(3);
8228bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8238bfffbccSCorey Minyard }
8248bfffbccSCorey Minyard 
8258bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8268bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8278bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8288bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8298bfffbccSCorey Minyard {
8308bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
8318bfffbccSCorey Minyard }
8328bfffbccSCorey Minyard 
8338bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
8348bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8358bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8368bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8378bfffbccSCorey Minyard {
8388bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8398bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8408bfffbccSCorey Minyard 
8418bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8428bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
8438bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8448bfffbccSCorey Minyard }
8458bfffbccSCorey Minyard 
8468bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
8478bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8488bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8498bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8508bfffbccSCorey Minyard {
8518bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->msg_flags);
8528bfffbccSCorey Minyard }
8538bfffbccSCorey Minyard 
8548bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
8558bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
8568bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
8578bfffbccSCorey Minyard                             unsigned int max_rsp_len)
8588bfffbccSCorey Minyard {
8598bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8608bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8618bfffbccSCorey Minyard     unsigned int i;
8628bfffbccSCorey Minyard 
8638bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
8648bfffbccSCorey Minyard         rsp[2] = 0x80;
865d13ada5dSCédric Le Goater         return;
8668bfffbccSCorey Minyard     }
8678bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
8688bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
8698bfffbccSCorey Minyard     }
8708bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
8718bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8728bfffbccSCorey Minyard }
8738bfffbccSCorey Minyard 
8748bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
8758bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
8768bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
8778bfffbccSCorey Minyard                     unsigned int max_rsp_len)
8788bfffbccSCorey Minyard {
8798bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
8808bfffbccSCorey Minyard 
8818bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
8828bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
8838bfffbccSCorey Minyard         rsp[2] = 0x80; /* Queue empty */
8848bfffbccSCorey Minyard         goto out;
8858bfffbccSCorey Minyard     }
8868bfffbccSCorey Minyard     rsp[3] = 0; /* Channel 0 */
8878bfffbccSCorey Minyard     *rsp_len += 1;
8888bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
8898bfffbccSCorey Minyard     memcpy(rsp + 4, msg->buf, msg->len);
8908bfffbccSCorey Minyard     *rsp_len += msg->len;
8918bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
8928bfffbccSCorey Minyard     g_free(msg);
8938bfffbccSCorey Minyard 
8948bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
8958bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
8968bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8978bfffbccSCorey Minyard 
8988bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
8998bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9008bfffbccSCorey Minyard     }
9018bfffbccSCorey Minyard 
9028bfffbccSCorey Minyard out:
9038bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
9048bfffbccSCorey Minyard     return;
9058bfffbccSCorey Minyard }
9068bfffbccSCorey Minyard 
9078bfffbccSCorey Minyard static unsigned char
9088bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9098bfffbccSCorey Minyard {
9108bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9118bfffbccSCorey Minyard             csum += *data;
9128bfffbccSCorey Minyard     }
9138bfffbccSCorey Minyard 
9148bfffbccSCorey Minyard     return -csum;
9158bfffbccSCorey Minyard }
9168bfffbccSCorey Minyard 
9178bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9188bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
9198bfffbccSCorey Minyard                      uint8_t *rsp, unsigned int *rsp_len,
9208bfffbccSCorey Minyard                      unsigned int max_rsp_len)
9218bfffbccSCorey Minyard {
9228bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9238bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9248bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9258bfffbccSCorey Minyard     uint8_t *buf;
9268bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9278bfffbccSCorey Minyard 
9288bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
9298bfffbccSCorey Minyard 
9308bfffbccSCorey Minyard     if (cmd[2] != 0) {
9318bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
9328bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
933d13ada5dSCédric Le Goater         return;
9348bfffbccSCorey Minyard     }
9358bfffbccSCorey Minyard 
9368bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(10);
9378bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9388bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
9398bfffbccSCorey Minyard         rsp[2] = 0x83; /* NAK on write */
940d13ada5dSCédric Le Goater         return;
9418bfffbccSCorey Minyard     }
9428bfffbccSCorey Minyard 
9438bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
9448bfffbccSCorey Minyard     cmd_len -= 3;
9458bfffbccSCorey Minyard 
9468bfffbccSCorey Minyard     /*
9478bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
9488bfffbccSCorey Minyard      * be returned in the response.
9498bfffbccSCorey Minyard      */
9508bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
9518bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
952d13ada5dSCédric Le Goater         return; /* No response */
9538bfffbccSCorey Minyard     }
9548bfffbccSCorey Minyard 
9558bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
9568bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
9578bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
9588bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
9598bfffbccSCorey Minyard 
9608bfffbccSCorey Minyard     if (rqLun != 2) {
9618bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
962d13ada5dSCédric Le Goater         return;
9638bfffbccSCorey Minyard     }
9648bfffbccSCorey Minyard 
9658bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
9668bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
9678bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
9688bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
9698bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
9708bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
9718bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
9728bfffbccSCorey Minyard     msg->len = 6;
9738bfffbccSCorey Minyard 
9748bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
9758bfffbccSCorey Minyard         /* Not a command we handle. */
9768bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
9778bfffbccSCorey Minyard         goto end_msg;
9788bfffbccSCorey Minyard     }
9798bfffbccSCorey Minyard 
9808bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
9818bfffbccSCorey Minyard     buf[0] = 0;
9828bfffbccSCorey Minyard     buf[1] = 0;
9838bfffbccSCorey Minyard     buf[2] = 0;
9848bfffbccSCorey Minyard     buf[3] = 0;
9858bfffbccSCorey Minyard     buf[4] = 0x51;
9868bfffbccSCorey Minyard     buf[5] = 0;
9878bfffbccSCorey Minyard     buf[6] = 0;
9888bfffbccSCorey Minyard     buf[7] = 0;
9898bfffbccSCorey Minyard     buf[8] = 0;
9908bfffbccSCorey Minyard     buf[9] = 0;
9918bfffbccSCorey Minyard     buf[10] = 0;
9928bfffbccSCorey Minyard     msg->len += 11;
9938bfffbccSCorey Minyard 
9948bfffbccSCorey Minyard  end_msg:
9958bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
9968bfffbccSCorey Minyard     msg->len++;
9978bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
9988bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
9998bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10008bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10018bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
10028bfffbccSCorey Minyard }
10038bfffbccSCorey Minyard 
10048bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
10058bfffbccSCorey Minyard {
10068bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
10078bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
10088bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10098bfffbccSCorey Minyard         return;
10108bfffbccSCorey Minyard     }
10118bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10128bfffbccSCorey Minyard 
10138bfffbccSCorey Minyard 
10148bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10158bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10168bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10178bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10188bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10198bfffbccSCorey Minyard     }
10208bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10218bfffbccSCorey Minyard }
10228bfffbccSCorey Minyard 
10238bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10248bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
10258bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
10268bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
10278bfffbccSCorey Minyard {
10288bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
10298bfffbccSCorey Minyard         rsp[2] = 0x80;
1030d13ada5dSCédric Le Goater         return;
10318bfffbccSCorey Minyard     }
10328bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10338bfffbccSCorey Minyard }
10348bfffbccSCorey Minyard 
10358bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10368bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
10378bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
10388bfffbccSCorey Minyard                                unsigned int max_rsp_len)
10398bfffbccSCorey Minyard {
10408bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10418bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10428bfffbccSCorey Minyard     unsigned int val;
10438bfffbccSCorey Minyard 
10448bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
10458bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
10468bfffbccSCorey Minyard     if (val == 0 || val > 5) {
10478bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1048d13ada5dSCédric Le Goater         return;
10498bfffbccSCorey Minyard     }
10508bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
10518bfffbccSCorey Minyard     switch (val) {
10528bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
10538bfffbccSCorey Minyard         break;
10548bfffbccSCorey Minyard 
10558bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
10568bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
10578bfffbccSCorey Minyard         break;
10588bfffbccSCorey Minyard 
10598bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
10608bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
10618bfffbccSCorey Minyard         break;
10628bfffbccSCorey Minyard 
10638bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
10648bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
10658bfffbccSCorey Minyard         break;
10668bfffbccSCorey Minyard 
10678bfffbccSCorey Minyard     default:
10688bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
10698bfffbccSCorey Minyard     }
10708bfffbccSCorey Minyard     if (rsp[2]) {
10718bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1072d13ada5dSCédric Le Goater         return;
10738bfffbccSCorey Minyard     }
10748bfffbccSCorey Minyard 
10758bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
10768bfffbccSCorey Minyard     switch (val) {
10778bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
10788bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
10798bfffbccSCorey Minyard         break;
10808bfffbccSCorey Minyard 
10818bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
10828bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
10838bfffbccSCorey Minyard             /* NMI not supported. */
10848bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1085d13ada5dSCédric Le Goater             return;
10868bfffbccSCorey Minyard         }
10878bfffbccSCorey Minyard     default:
10888bfffbccSCorey Minyard         /* We don't support PRE_SMI */
10898bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1090d13ada5dSCédric Le Goater         return;
10918bfffbccSCorey Minyard     }
10928bfffbccSCorey Minyard 
10938bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
10948bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
10958bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
10968bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
10978bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
10988bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
10998bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11008bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11018bfffbccSCorey Minyard     } else {
11028bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11038bfffbccSCorey Minyard     }
11048bfffbccSCorey Minyard }
11058bfffbccSCorey Minyard 
11068bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
11078bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
11088bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
11098bfffbccSCorey Minyard                                unsigned int max_rsp_len)
11108bfffbccSCorey Minyard {
11118bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_use);
11128bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_action);
11138bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout);
11148bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_expired);
11158bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11168bfffbccSCorey Minyard         long timeout;
11178bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11188bfffbccSCorey Minyard                    / 100000000);
11198bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(timeout & 0xff);
11208bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff);
11218bfffbccSCorey Minyard     } else {
11228bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11238bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11248bfffbccSCorey Minyard     }
11258bfffbccSCorey Minyard }
11268bfffbccSCorey Minyard 
11278bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11288bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
11298bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
11308bfffbccSCorey Minyard                              unsigned int max_rsp_len)
11318bfffbccSCorey Minyard {
11328bfffbccSCorey Minyard     unsigned int i;
11338bfffbccSCorey Minyard 
11348bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */
11358bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff);
11368bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff);
11378bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
11388bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11398bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11408bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]);
11418bfffbccSCorey Minyard     }
11428bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11438bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]);
11448bfffbccSCorey Minyard     }
11458bfffbccSCorey Minyard     /* Only modal support, reserve supported */
11468bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
11478bfffbccSCorey Minyard }
11488bfffbccSCorey Minyard 
11498bfffbccSCorey Minyard static void reserve_sdr_rep(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     IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
11558bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
11568bfffbccSCorey Minyard }
11578bfffbccSCorey Minyard 
11588bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
11598bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
11608bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
11618bfffbccSCorey Minyard                     unsigned int max_rsp_len)
11628bfffbccSCorey Minyard {
11638bfffbccSCorey Minyard     unsigned int pos;
11648bfffbccSCorey Minyard     uint16_t nextrec;
1165*a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
11668bfffbccSCorey Minyard 
11678bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
11688bfffbccSCorey Minyard     if (cmd[6]) {
11698bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
11708bfffbccSCorey Minyard     }
11718bfffbccSCorey Minyard     pos = 0;
11728bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
11738bfffbccSCorey Minyard                        &pos, &nextrec)) {
11748bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1175d13ada5dSCédric Le Goater         return;
11768bfffbccSCorey Minyard     }
1177*a2295f0aSCédric Le Goater 
1178*a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1179*a2295f0aSCédric Le Goater 
1180*a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
11818bfffbccSCorey Minyard         rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1182d13ada5dSCédric Le Goater         return;
11838bfffbccSCorey Minyard     }
11848bfffbccSCorey Minyard 
11858bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(nextrec & 0xff);
11868bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
11878bfffbccSCorey Minyard 
11888bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1189*a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
11908bfffbccSCorey Minyard     }
11918bfffbccSCorey Minyard 
11928bfffbccSCorey Minyard     if ((cmd[7] + *rsp_len) > max_rsp_len) {
11938bfffbccSCorey Minyard         rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1194d13ada5dSCédric Le Goater         return;
11958bfffbccSCorey Minyard     }
11968bfffbccSCorey Minyard     memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
11978bfffbccSCorey Minyard     *rsp_len += cmd[7];
11988bfffbccSCorey Minyard }
11998bfffbccSCorey Minyard 
12008bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12018bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
12028bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
12038bfffbccSCorey Minyard                     unsigned int max_rsp_len)
12048bfffbccSCorey Minyard {
12058bfffbccSCorey Minyard     uint16_t recid;
1206*a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
12078bfffbccSCorey Minyard 
1208*a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
12098bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1210d13ada5dSCédric Le Goater         return;
12118bfffbccSCorey Minyard     }
12128bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(recid & 0xff);
12138bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
12148bfffbccSCorey Minyard }
12158bfffbccSCorey Minyard 
12168bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12178bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12188bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12198bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12208bfffbccSCorey Minyard {
12218bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12228bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
12238bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
12248bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1225d13ada5dSCédric Le Goater         return;
12268bfffbccSCorey Minyard     }
12278bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12288bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12298bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12308bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
12318bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12328bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12338bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
12348bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12358bfffbccSCorey Minyard     } else {
12368bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
12378bfffbccSCorey Minyard         return;
12388bfffbccSCorey Minyard     }
1239d13ada5dSCédric Le Goater }
12408bfffbccSCorey Minyard 
12418bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
12428bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
12438bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
12448bfffbccSCorey Minyard                          unsigned int max_rsp_len)
12458bfffbccSCorey Minyard {
12468bfffbccSCorey Minyard     unsigned int i, val;
12478bfffbccSCorey Minyard 
12488bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */
12498bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff);
12508bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff);
12518bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
12528bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
12538bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
12548bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
12558bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]);
12568bfffbccSCorey Minyard     }
12578bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
12588bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]);
12598bfffbccSCorey Minyard     }
12608bfffbccSCorey Minyard     /* Only support Reserve SEL */
12618bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
12628bfffbccSCorey Minyard }
12638bfffbccSCorey Minyard 
12648bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
12658bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
12668bfffbccSCorey Minyard                         uint8_t *rsp, unsigned int *rsp_len,
12678bfffbccSCorey Minyard                         unsigned int max_rsp_len)
12688bfffbccSCorey Minyard {
12698bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
12708bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
12718bfffbccSCorey Minyard }
12728bfffbccSCorey Minyard 
12738bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
12748bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12758bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12768bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12778bfffbccSCorey Minyard {
12788bfffbccSCorey Minyard     unsigned int val;
12798bfffbccSCorey Minyard 
12808bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12818bfffbccSCorey Minyard     if (cmd[6]) {
12828bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
12838bfffbccSCorey Minyard     }
12848bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
12858bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1286d13ada5dSCédric Le Goater         return;
12878bfffbccSCorey Minyard     }
12888bfffbccSCorey Minyard     if (cmd[6] > 15) {
12898bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1290d13ada5dSCédric Le Goater         return;
12918bfffbccSCorey Minyard     }
12928bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
12938bfffbccSCorey Minyard         cmd[7] = 16;
12948bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
12958bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1296d13ada5dSCédric Le Goater         return;
12978bfffbccSCorey Minyard     } else {
12988bfffbccSCorey Minyard         cmd[7] += cmd[6];
12998bfffbccSCorey Minyard     }
13008bfffbccSCorey Minyard 
13018bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
13028bfffbccSCorey Minyard     if (val == 0xffff) {
13038bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
13048bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
13058bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1306d13ada5dSCédric Le Goater         return;
13078bfffbccSCorey Minyard     }
13088bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
13098bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
13108bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
13118bfffbccSCorey Minyard     } else {
13128bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((val + 1) & 0xff);
13138bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff);
13148bfffbccSCorey Minyard     }
13158bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
13168bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
13178bfffbccSCorey Minyard     }
13188bfffbccSCorey Minyard }
13198bfffbccSCorey Minyard 
13208bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13218bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
13228bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
13238bfffbccSCorey Minyard                           unsigned int max_rsp_len)
13248bfffbccSCorey Minyard {
13258bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(18);
13268bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
13278bfffbccSCorey Minyard         rsp[2] = IPMI_CC_OUT_OF_SPACE;
1328d13ada5dSCédric Le Goater         return;
13298bfffbccSCorey Minyard     }
13308bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
13318bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[2]);
13328bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[3]);
13338bfffbccSCorey Minyard }
13348bfffbccSCorey Minyard 
13358bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13368bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
13378bfffbccSCorey Minyard                       uint8_t *rsp, unsigned int *rsp_len,
13388bfffbccSCorey Minyard                       unsigned int max_rsp_len)
13398bfffbccSCorey Minyard {
13408bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
13418bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
13428bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13438bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1344d13ada5dSCédric Le Goater         return;
13458bfffbccSCorey Minyard     }
13468bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13478bfffbccSCorey Minyard         ibs->sel.next_free = 0;
13488bfffbccSCorey Minyard         ibs->sel.overflow = 0;
13498bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
13508bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
13518bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
13528bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
13538bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
13548bfffbccSCorey Minyard     } else {
13558bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
13568bfffbccSCorey Minyard         return;
13578bfffbccSCorey Minyard     }
1358d13ada5dSCédric Le Goater }
13598bfffbccSCorey Minyard 
13608bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
13618bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
13628bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
13638bfffbccSCorey Minyard                          unsigned int max_rsp_len)
13648bfffbccSCorey Minyard {
13658bfffbccSCorey Minyard     uint32_t val;
13668bfffbccSCorey Minyard     struct ipmi_time now;
13678bfffbccSCorey Minyard 
13688bfffbccSCorey Minyard     ipmi_gettime(&now);
13698bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
13708bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
13718bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
13728bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
13738bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
13748bfffbccSCorey Minyard }
13758bfffbccSCorey Minyard 
13768bfffbccSCorey Minyard static void set_sel_time(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     uint32_t val;
13828bfffbccSCorey Minyard     struct ipmi_time now;
13838bfffbccSCorey Minyard 
13848bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(6);
13858bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
13868bfffbccSCorey Minyard     ipmi_gettime(&now);
13878bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
13888bfffbccSCorey Minyard }
13898bfffbccSCorey Minyard 
13908bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
13918bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
13928bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
13938bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
13948bfffbccSCorey Minyard {
13958bfffbccSCorey Minyard     IPMISensor *sens;
13968bfffbccSCorey Minyard 
13978bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
13988bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
13998bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14008bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1401d13ada5dSCédric Le Goater         return;
14028bfffbccSCorey Minyard     }
14038bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14048bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
14058bfffbccSCorey Minyard     case 0: /* Do not change */
14068bfffbccSCorey Minyard         break;
14078bfffbccSCorey Minyard     case 1: /* Enable 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 2: /* Disable bits */
14228bfffbccSCorey Minyard         if (cmd_len > 4) {
14238bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14248bfffbccSCorey Minyard         }
14258bfffbccSCorey Minyard         if (cmd_len > 5) {
14268bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14278bfffbccSCorey Minyard         }
14288bfffbccSCorey Minyard         if (cmd_len > 6) {
14298bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14308bfffbccSCorey Minyard         }
14318bfffbccSCorey Minyard         if (cmd_len > 7) {
14328bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14338bfffbccSCorey Minyard         }
14348bfffbccSCorey Minyard         break;
14358bfffbccSCorey Minyard     case 3:
14368bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1437d13ada5dSCédric Le Goater         return;
14388bfffbccSCorey Minyard     }
14398bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14408bfffbccSCorey Minyard }
14418bfffbccSCorey Minyard 
14428bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14438bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14448bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14458bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14468bfffbccSCorey Minyard {
14478bfffbccSCorey Minyard     IPMISensor *sens;
14488bfffbccSCorey Minyard 
14498bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
14508bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14518bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14528bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1453d13ada5dSCédric Le Goater         return;
14548bfffbccSCorey Minyard     }
14558bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14568bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
14578bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff);
14588bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
14598bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
14608bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
14618bfffbccSCorey Minyard }
14628bfffbccSCorey Minyard 
14638bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
14648bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
14658bfffbccSCorey Minyard                               uint8_t *rsp, unsigned int *rsp_len,
14668bfffbccSCorey Minyard                               unsigned int max_rsp_len)
14678bfffbccSCorey Minyard {
14688bfffbccSCorey Minyard     IPMISensor *sens;
14698bfffbccSCorey Minyard 
14708bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
14718bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14728bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14738bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1474d13ada5dSCédric Le Goater         return;
14758bfffbccSCorey Minyard     }
14768bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14778bfffbccSCorey Minyard 
14788bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
14798bfffbccSCorey Minyard         /* Just clear everything */
14808bfffbccSCorey Minyard         sens->states = 0;
14818bfffbccSCorey Minyard         return;
14828bfffbccSCorey Minyard     }
1483d13ada5dSCédric Le Goater }
14848bfffbccSCorey Minyard 
14858bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
14868bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14878bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14888bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14898bfffbccSCorey Minyard {
14908bfffbccSCorey Minyard     IPMISensor *sens;
14918bfffbccSCorey Minyard 
14928bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
14938bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14948bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14958bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1496d13ada5dSCédric Le Goater         return;
14978bfffbccSCorey Minyard     }
14988bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14998bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15008bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15018bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_states & 0xff);
15028bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
15038bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
15048bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
15058bfffbccSCorey Minyard }
15068bfffbccSCorey Minyard 
15078bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
15088bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
15098bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
15108bfffbccSCorey Minyard                                unsigned int max_rsp_len)
15118bfffbccSCorey Minyard {
15128bfffbccSCorey Minyard     IPMISensor *sens;
15138bfffbccSCorey Minyard 
15148bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
15158bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
15168bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15178bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1518d13ada5dSCédric Le Goater         return;
15198bfffbccSCorey Minyard     }
15208bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15218bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15228bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15238bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->states & 0xff);
15248bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
15258bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
15268bfffbccSCorey Minyard     }
15278bfffbccSCorey Minyard }
15288bfffbccSCorey Minyard 
152962a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
15308bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
15318bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
15328bfffbccSCorey Minyard     [IPMI_CMD_CHASSIS_CONTROL] = chassis_control
15338bfffbccSCorey Minyard };
15348bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
153562a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
15368bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
15378bfffbccSCorey Minyard };
15388bfffbccSCorey Minyard 
153962a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
15408bfffbccSCorey Minyard     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
15418bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
15428bfffbccSCorey Minyard     [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
15438bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
15448bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading
15458bfffbccSCorey Minyard };
15468bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
154762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
15488bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
15498bfffbccSCorey Minyard };
15508bfffbccSCorey Minyard 
155162a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
15528bfffbccSCorey Minyard     [IPMI_CMD_GET_DEVICE_ID] = get_device_id,
15538bfffbccSCorey Minyard     [IPMI_CMD_COLD_RESET] = cold_reset,
15548bfffbccSCorey Minyard     [IPMI_CMD_WARM_RESET] = warm_reset,
15558bfffbccSCorey Minyard     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
15568bfffbccSCorey Minyard     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
15578bfffbccSCorey Minyard     [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
15588bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags,
15598bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG] = get_msg,
15608bfffbccSCorey Minyard     [IPMI_CMD_SEND_MSG] = send_msg,
15618bfffbccSCorey Minyard     [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf,
15628bfffbccSCorey Minyard     [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer,
15638bfffbccSCorey Minyard     [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer,
15648bfffbccSCorey Minyard     [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
15658bfffbccSCorey Minyard };
15668bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
156762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
15688bfffbccSCorey Minyard     .cmd_handlers = app_cmds
15698bfffbccSCorey Minyard };
15708bfffbccSCorey Minyard 
157162a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
15728bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
15738bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
15748bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR] = get_sdr,
15758bfffbccSCorey Minyard     [IPMI_CMD_ADD_SDR] = add_sdr,
15768bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep,
15778bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_INFO] = get_sel_info,
15788bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SEL] = reserve_sel,
15798bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry,
15808bfffbccSCorey Minyard     [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry,
15818bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SEL] = clear_sel,
15828bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = get_sel_time,
15838bfffbccSCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = set_sel_time,
15848bfffbccSCorey Minyard };
15858bfffbccSCorey Minyard 
15868bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
158762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
15888bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
15898bfffbccSCorey Minyard };
15908bfffbccSCorey Minyard 
15918bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
15928bfffbccSCorey Minyard {
15938bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
15948bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
15958bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
15968bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
15978bfffbccSCorey Minyard }
15988bfffbccSCorey Minyard 
15998bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
16008bfffbccSCorey Minyard     /* Watchdog device */
16018bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
16028bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
16038bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16048bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
16058bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
16068bfffbccSCorey Minyard     /* End */
16078bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
16088bfffbccSCorey Minyard };
16098bfffbccSCorey Minyard 
1610bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1611bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1612bd66bcfcSCorey Minyard     .version_id = 1,
1613bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1614bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1615bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1616bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1617bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1618bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1619bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1620bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1621bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1622bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1623bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1624bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1625bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1626bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1627bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1628bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1629bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1630bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1631bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1632bd66bcfcSCorey Minyard                        IPMIBmcSim),
1633bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1634bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1635bd66bcfcSCorey Minyard     }
1636bd66bcfcSCorey Minyard };
1637bd66bcfcSCorey Minyard 
16388bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj)
16398bfffbccSCorey Minyard {
16408bfffbccSCorey Minyard     IPMIBmc *b = IPMI_BMC(obj);
16418bfffbccSCorey Minyard     unsigned int i;
16428bfffbccSCorey Minyard     unsigned int recid;
16438bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
16448bfffbccSCorey Minyard 
16458bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
16468bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
16478bfffbccSCorey Minyard 
16488bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
16498bfffbccSCorey Minyard     ibs->device_id = 0x20;
16508bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
16518bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
16528bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
16538bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
16548bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
16558bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
16568bfffbccSCorey Minyard     }
16578bfffbccSCorey Minyard 
16588bfffbccSCorey Minyard     for (i = 0;;) {
1659*a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh;
16608bfffbccSCorey Minyard         int len;
1661*a2295f0aSCédric Le Goater         if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) {
16627cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
16638bfffbccSCorey Minyard             return;
16648bfffbccSCorey Minyard         }
1665*a2295f0aSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &init_sdrs[i];
1666*a2295f0aSCédric Le Goater         len = ipmi_sdr_length(sdrh);
1667*a2295f0aSCédric Le Goater         recid = ipmi_sdr_recid(sdrh);
16688bfffbccSCorey Minyard         if (recid == 0xffff) {
16698bfffbccSCorey Minyard             break;
16708bfffbccSCorey Minyard         }
1671792afddbSCédric Le Goater         if ((i + len) > sizeof(init_sdrs)) {
16727cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
16738bfffbccSCorey Minyard             return;
16748bfffbccSCorey Minyard         }
1675*a2295f0aSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
1676792afddbSCédric Le Goater         i += len;
16778bfffbccSCorey Minyard     }
16788bfffbccSCorey Minyard 
16798bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
16808bfffbccSCorey Minyard     register_cmds(ibs);
16818bfffbccSCorey Minyard 
16828bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1683bd66bcfcSCorey Minyard 
1684bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
16858bfffbccSCorey Minyard }
16868bfffbccSCorey Minyard 
16878bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
16888bfffbccSCorey Minyard {
16898bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
16908bfffbccSCorey Minyard 
16918bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
16928bfffbccSCorey Minyard }
16938bfffbccSCorey Minyard 
16948bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
16958bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
16968bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
16978bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
16988bfffbccSCorey Minyard     .instance_init = ipmi_sim_init,
16998bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
17008bfffbccSCorey Minyard };
17018bfffbccSCorey Minyard 
17028bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
17038bfffbccSCorey Minyard {
17048bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
17058bfffbccSCorey Minyard }
17068bfffbccSCorey Minyard 
17078bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1708