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