xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision b7088392239d0d6fd1140690a3efdb24df1bc7c6)
18bfffbccSCorey Minyard /*
28bfffbccSCorey Minyard  * IPMI BMC emulation
38bfffbccSCorey Minyard  *
48bfffbccSCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
58bfffbccSCorey Minyard  *
68bfffbccSCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
78bfffbccSCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
88bfffbccSCorey Minyard  * in the Software without restriction, including without limitation the rights
98bfffbccSCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108bfffbccSCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
118bfffbccSCorey Minyard  * furnished to do so, subject to the following conditions:
128bfffbccSCorey Minyard  *
138bfffbccSCorey Minyard  * The above copyright notice and this permission notice shall be included in
148bfffbccSCorey Minyard  * all copies or substantial portions of the Software.
158bfffbccSCorey Minyard  *
168bfffbccSCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178bfffbccSCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188bfffbccSCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198bfffbccSCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208bfffbccSCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218bfffbccSCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228bfffbccSCorey Minyard  * THE SOFTWARE.
238bfffbccSCorey Minyard  */
248bfffbccSCorey Minyard 
250430891cSPeter Maydell #include "qemu/osdep.h"
268bfffbccSCorey Minyard #include "qemu/timer.h"
278bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
288bfffbccSCorey Minyard #include "qemu/error-report.h"
298bfffbccSCorey Minyard 
308bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
318bfffbccSCorey Minyard 
328bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
338bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
348bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
35*b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
368bfffbccSCorey Minyard 
378bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
388bfffbccSCorey Minyard 
398bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
408bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
418bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
438bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
44728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
45728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
468bfffbccSCorey Minyard 
478bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
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 
658bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
668bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
678bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
688bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
698bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
708bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
718bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
728bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
748bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
758bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
768bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
778bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
788bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
798bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
808bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
818bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
828bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
838bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
848bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
858bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
868bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
878bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
888bfffbccSCorey Minyard 
898bfffbccSCorey Minyard 
908bfffbccSCorey Minyard /* Same as a timespec struct. */
918bfffbccSCorey Minyard struct ipmi_time {
928bfffbccSCorey Minyard     long tv_sec;
938bfffbccSCorey Minyard     long tv_nsec;
948bfffbccSCorey Minyard };
958bfffbccSCorey Minyard 
968bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
978bfffbccSCorey Minyard 
988bfffbccSCorey Minyard typedef struct IPMISel {
998bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1008bfffbccSCorey Minyard     unsigned int next_free;
1018bfffbccSCorey Minyard     long time_offset;
1028bfffbccSCorey Minyard     uint16_t reservation;
1038bfffbccSCorey Minyard     uint8_t last_addition[4];
1048bfffbccSCorey Minyard     uint8_t last_clear[4];
1058bfffbccSCorey Minyard     uint8_t overflow;
1068bfffbccSCorey Minyard } IPMISel;
1078bfffbccSCorey Minyard 
1088bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1098bfffbccSCorey Minyard 
1108bfffbccSCorey Minyard typedef struct IPMISdr {
1118bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1128bfffbccSCorey Minyard     unsigned int next_free;
1138bfffbccSCorey Minyard     uint16_t next_rec_id;
1148bfffbccSCorey Minyard     uint16_t reservation;
1158bfffbccSCorey Minyard     uint8_t last_addition[4];
1168bfffbccSCorey Minyard     uint8_t last_clear[4];
1178bfffbccSCorey Minyard     uint8_t overflow;
1188bfffbccSCorey Minyard } IPMISdr;
1198bfffbccSCorey Minyard 
1208bfffbccSCorey Minyard typedef struct IPMISensor {
1218bfffbccSCorey Minyard     uint8_t status;
1228bfffbccSCorey Minyard     uint8_t reading;
1238bfffbccSCorey Minyard     uint16_t states_suppt;
1248bfffbccSCorey Minyard     uint16_t assert_suppt;
1258bfffbccSCorey Minyard     uint16_t deassert_suppt;
1268bfffbccSCorey Minyard     uint16_t states;
1278bfffbccSCorey Minyard     uint16_t assert_states;
1288bfffbccSCorey Minyard     uint16_t deassert_states;
1298bfffbccSCorey Minyard     uint16_t assert_enable;
1308bfffbccSCorey Minyard     uint16_t deassert_enable;
1318bfffbccSCorey Minyard     uint8_t  sensor_type;
1328bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1338bfffbccSCorey Minyard } IPMISensor;
1348bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1358bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1368bfffbccSCorey Minyard                                              !!(v))
1378bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1388bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1398bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1408bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1418bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1428bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1438bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1448bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1458bfffbccSCorey Minyard                                              (v & 0xc0))
1468bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1478bfffbccSCorey Minyard 
1488bfffbccSCorey Minyard #define MAX_SENSORS 20
1498bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1508bfffbccSCorey Minyard 
1518bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
1528bfffbccSCorey Minyard 
1538bfffbccSCorey Minyard #define MAX_NETFNS 64
1548bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s,
1558bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1568bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
1578bfffbccSCorey Minyard                                unsigned int max_rsp_len);
1588bfffbccSCorey Minyard typedef struct IPMINetfn {
1598bfffbccSCorey Minyard     unsigned int cmd_nums;
1608bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1618bfffbccSCorey Minyard } IPMINetfn;
1628bfffbccSCorey Minyard 
1638bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1648bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1658bfffbccSCorey Minyard     uint8_t len;
1668bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1678bfffbccSCorey Minyard } IPMIRcvBufEntry;
1688bfffbccSCorey Minyard 
1698bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1708bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1718bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1728bfffbccSCorey Minyard struct IPMIBmcSim {
1738bfffbccSCorey Minyard     IPMIBmc parent;
1748bfffbccSCorey Minyard 
1758bfffbccSCorey Minyard     QEMUTimer *timer;
1768bfffbccSCorey Minyard 
1778bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1788bfffbccSCorey Minyard     uint8_t msg_flags;
1798bfffbccSCorey Minyard 
1808bfffbccSCorey Minyard     bool     watchdog_initialized;
1818bfffbccSCorey Minyard     uint8_t  watchdog_use;
1828bfffbccSCorey Minyard     uint8_t  watchdog_action;
1838bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1848bfffbccSCorey Minyard     bool     watchdog_expired;
1858bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1868bfffbccSCorey Minyard 
1878bfffbccSCorey Minyard     bool     watchdog_running;
1888bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1898bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1908bfffbccSCorey Minyard 
1918bfffbccSCorey Minyard     uint8_t device_id;
1928bfffbccSCorey Minyard     uint8_t ipmi_version;
1938bfffbccSCorey Minyard     uint8_t device_rev;
1948bfffbccSCorey Minyard     uint8_t fwrev1;
1958bfffbccSCorey Minyard     uint8_t fwrev2;
1968bfffbccSCorey Minyard     uint8_t mfg_id[3];
1978bfffbccSCorey Minyard     uint8_t product_id[2];
1988bfffbccSCorey Minyard 
199*b7088392SCédric Le Goater     uint8_t restart_cause;
200*b7088392SCédric Le Goater 
2018bfffbccSCorey Minyard     IPMISel sel;
2028bfffbccSCorey Minyard     IPMISdr sdr;
2038bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2048bfffbccSCorey Minyard 
2058bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2068bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2078bfffbccSCorey Minyard 
2088bfffbccSCorey Minyard     QemuMutex lock;
2098bfffbccSCorey Minyard     /* We allow one event in the buffer */
2108bfffbccSCorey Minyard     uint8_t evtbuf[16];
2118bfffbccSCorey Minyard 
2128bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2138bfffbccSCorey Minyard };
2148bfffbccSCorey Minyard 
2158bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2168bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2178bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2188bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2198bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2208bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2218bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2228bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2238bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2248bfffbccSCorey Minyard 
2258bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2268bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2278bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2288bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2308bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2318bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2328bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2338bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2348bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2358bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2368bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2378bfffbccSCorey Minyard 
2388bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2398bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2408bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2418bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2428bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2438bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2448bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2458bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2468bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2478bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2488bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2498bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2538bfffbccSCorey Minyard 
2548bfffbccSCorey Minyard 
2558bfffbccSCorey Minyard /* Add a byte to the response. */
2568bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \
2578bfffbccSCorey Minyard     do {                                                   \
2588bfffbccSCorey Minyard         if (*rsp_len >= max_rsp_len) {                     \
2598bfffbccSCorey Minyard             rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;       \
260d13ada5dSCédric Le Goater             return;                                        \
2618bfffbccSCorey Minyard         }                                                  \
2628bfffbccSCorey Minyard         rsp[(*rsp_len)++] = (b);                           \
2638bfffbccSCorey Minyard     } while (0)
2648bfffbccSCorey Minyard 
2658bfffbccSCorey Minyard /* Verify that the received command is a certain length. */
2668bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \
2678bfffbccSCorey Minyard     if (cmd_len < l) {                                     \
2688bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;      \
269d13ada5dSCédric Le Goater         return; \
2708bfffbccSCorey Minyard     }
2718bfffbccSCorey Minyard 
2728bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */
2738bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \
2748bfffbccSCorey Minyard     do {                                                   \
2758bfffbccSCorey Minyard         if ((cmd[off] | (cmd[off + 1] << 8)) != r) {       \
2768bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_RESERVATION;          \
277d13ada5dSCédric Le Goater             return;                                        \
2788bfffbccSCorey Minyard         }                                                  \
2798bfffbccSCorey Minyard     } while (0)
2808bfffbccSCorey Minyard 
2818bfffbccSCorey Minyard 
2828bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2838bfffbccSCorey Minyard 
2848bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2858bfffbccSCorey Minyard {
2868bfffbccSCorey Minyard     int64_t stime;
2878bfffbccSCorey Minyard 
2888bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2898bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
2908bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
2918bfffbccSCorey Minyard }
2928bfffbccSCorey Minyard 
2938bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2948bfffbccSCorey Minyard {
2958bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2968bfffbccSCorey Minyard }
2978bfffbccSCorey Minyard 
2988bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2998bfffbccSCorey Minyard {
3008bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3018bfffbccSCorey Minyard 
3028bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3038bfffbccSCorey Minyard }
3048bfffbccSCorey Minyard 
3058bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3068bfffbccSCorey Minyard {
3078bfffbccSCorey Minyard     unsigned int val;
3088bfffbccSCorey Minyard     struct ipmi_time now;
3098bfffbccSCorey Minyard 
3108bfffbccSCorey Minyard     ipmi_gettime(&now);
3118bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3128bfffbccSCorey Minyard     ts[0] = val & 0xff;
3138bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3148bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3158bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3168bfffbccSCorey Minyard }
3178bfffbccSCorey Minyard 
3188bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3198bfffbccSCorey Minyard {
3208bfffbccSCorey Minyard     sdr->reservation++;
3218bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3228bfffbccSCorey Minyard         sdr->reservation = 1;
3238bfffbccSCorey Minyard     }
3248bfffbccSCorey Minyard }
3258bfffbccSCorey Minyard 
326a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
327a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3288bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3298bfffbccSCorey Minyard {
330a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
331a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
332a2295f0aSCédric Le Goater 
333a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3348bfffbccSCorey Minyard         return 1;
3358bfffbccSCorey Minyard     }
3368bfffbccSCorey Minyard 
337a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3388bfffbccSCorey Minyard         return 1;
3398bfffbccSCorey Minyard     }
3408bfffbccSCorey Minyard 
3418bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3428bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3438bfffbccSCorey Minyard         return 1;
3448bfffbccSCorey Minyard     }
3458bfffbccSCorey Minyard 
346a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
347a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
348a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
349a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3508bfffbccSCorey Minyard 
3518bfffbccSCorey Minyard     if (recid) {
3528bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3538bfffbccSCorey Minyard     }
3548bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3558bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3568bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3578bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3588bfffbccSCorey Minyard     return 0;
3598bfffbccSCorey Minyard }
3608bfffbccSCorey Minyard 
3618bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3628bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3638bfffbccSCorey Minyard {
3648bfffbccSCorey Minyard     unsigned int pos = *retpos;
3658bfffbccSCorey Minyard 
3668bfffbccSCorey Minyard     while (pos < sdr->next_free) {
367a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
368a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
369a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
370a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3718bfffbccSCorey Minyard 
3728bfffbccSCorey Minyard         if (trec == recid) {
3738bfffbccSCorey Minyard             if (nextrec) {
3748bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3758bfffbccSCorey Minyard                     *nextrec = 0xffff;
3768bfffbccSCorey Minyard                 } else {
3778bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3788bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3798bfffbccSCorey Minyard                 }
3808bfffbccSCorey Minyard             }
3818bfffbccSCorey Minyard             *retpos = pos;
3828bfffbccSCorey Minyard             return 0;
3838bfffbccSCorey Minyard         }
3848bfffbccSCorey Minyard         pos = nextpos;
3858bfffbccSCorey Minyard     }
3868bfffbccSCorey Minyard     return 1;
3878bfffbccSCorey Minyard }
3888bfffbccSCorey Minyard 
3898bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
3908bfffbccSCorey Minyard {
3918bfffbccSCorey Minyard     sel->reservation++;
3928bfffbccSCorey Minyard     if (sel->reservation == 0) {
3938bfffbccSCorey Minyard         sel->reservation = 1;
3948bfffbccSCorey Minyard     }
3958bfffbccSCorey Minyard }
3968bfffbccSCorey Minyard 
3978bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
3988bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
3998bfffbccSCorey Minyard {
4008bfffbccSCorey Minyard     event[0] = 0xff;
4018bfffbccSCorey Minyard     event[1] = 0xff;
4028bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
4038bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4048bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4058bfffbccSCorey Minyard         return 1;
4068bfffbccSCorey Minyard     }
4078bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4088bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4098bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4108bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4118bfffbccSCorey Minyard     ibs->sel.next_free++;
4128bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4138bfffbccSCorey Minyard     return 0;
4148bfffbccSCorey Minyard }
4158bfffbccSCorey Minyard 
4168bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4178bfffbccSCorey Minyard {
4188bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4198bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4208bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4218bfffbccSCorey Minyard }
4228bfffbccSCorey Minyard 
4238bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4248bfffbccSCorey Minyard {
4258bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4268bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4278bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4288bfffbccSCorey Minyard }
4298bfffbccSCorey Minyard 
4308bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4318bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4328bfffbccSCorey Minyard {
4338bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4348bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4358bfffbccSCorey Minyard     uint8_t evt[16];
4368bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4378bfffbccSCorey Minyard 
4388bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4398bfffbccSCorey Minyard         return;
4408bfffbccSCorey Minyard     }
4418bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4428bfffbccSCorey Minyard         return;
4438bfffbccSCorey Minyard     }
4448bfffbccSCorey Minyard 
4458bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4468bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4478bfffbccSCorey Minyard     evt[8] = 0;
4488bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4498bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4508bfffbccSCorey Minyard     evt[11] = sens_num;
4518bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4528bfffbccSCorey Minyard     evt[13] = evd1;
4538bfffbccSCorey Minyard     evt[14] = evd2;
4548bfffbccSCorey Minyard     evt[15] = evd3;
4558bfffbccSCorey Minyard 
4568bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4578bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4588bfffbccSCorey Minyard     }
4598bfffbccSCorey Minyard 
4608bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
461d13ada5dSCédric Le Goater         return;
4628bfffbccSCorey Minyard     }
4638bfffbccSCorey Minyard 
4648bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4658bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4668bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4678bfffbccSCorey Minyard }
4688bfffbccSCorey Minyard 
4698bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4708bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4718bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4728bfffbccSCorey Minyard {
4738bfffbccSCorey Minyard     IPMISensor *sens;
4748bfffbccSCorey Minyard     uint16_t mask;
4758bfffbccSCorey Minyard 
4768bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4778bfffbccSCorey Minyard         return;
4788bfffbccSCorey Minyard     }
4798bfffbccSCorey Minyard     if (bit >= 16) {
4808bfffbccSCorey Minyard         return;
4818bfffbccSCorey Minyard     }
4828bfffbccSCorey Minyard 
4838bfffbccSCorey Minyard     mask = (1 << bit);
4848bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
4858bfffbccSCorey Minyard     if (val) {
4868bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
4878bfffbccSCorey Minyard         if (sens->assert_states & mask) {
4888bfffbccSCorey Minyard             return; /* Already asserted */
4898bfffbccSCorey Minyard         }
4908bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
4918bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
4928bfffbccSCorey Minyard             /* Send an event on assert */
4938bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
4948bfffbccSCorey Minyard         }
4958bfffbccSCorey Minyard     } else {
4968bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
4978bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
4988bfffbccSCorey Minyard             return; /* Already deasserted */
4998bfffbccSCorey Minyard         }
5008bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5018bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5028bfffbccSCorey Minyard             /* Send an event on deassert */
5038bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5048bfffbccSCorey Minyard         }
5058bfffbccSCorey Minyard     }
5068bfffbccSCorey Minyard }
5078bfffbccSCorey Minyard 
5088bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5098bfffbccSCorey Minyard {
5108bfffbccSCorey Minyard     unsigned int i, pos;
5118bfffbccSCorey Minyard     IPMISensor *sens;
5128bfffbccSCorey Minyard 
5138bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5148bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5158bfffbccSCorey Minyard     }
5168bfffbccSCorey Minyard 
5178bfffbccSCorey Minyard     pos = 0;
5188bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
519a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
520a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
521a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5228bfffbccSCorey Minyard 
5238bfffbccSCorey Minyard         if (len < 20) {
5248bfffbccSCorey Minyard             continue;
5258bfffbccSCorey Minyard         }
526a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5278bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5288bfffbccSCorey Minyard         }
5298bfffbccSCorey Minyard 
530a2295f0aSCédric Le Goater         if (sdr->sensor_owner_number > MAX_SENSORS) {
5318bfffbccSCorey Minyard             continue;
5328bfffbccSCorey Minyard         }
533a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5348bfffbccSCorey Minyard 
5358bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
536a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
537a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
538a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
539a2295f0aSCédric Le Goater         sens->deassert_suppt =
540a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
541a2295f0aSCédric Le Goater         sens->states_suppt =
542a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
543a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
544a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5458bfffbccSCorey Minyard 
5468bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5478bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5488bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5498bfffbccSCorey Minyard     }
5508bfffbccSCorey Minyard }
5518bfffbccSCorey Minyard 
5528bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5538bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5548bfffbccSCorey Minyard {
5558bfffbccSCorey Minyard     if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) {
5568bfffbccSCorey Minyard         return -1;
5578bfffbccSCorey Minyard     }
5588bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5598bfffbccSCorey Minyard     return 0;
5608bfffbccSCorey Minyard }
5618bfffbccSCorey Minyard 
5628bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
5638bfffbccSCorey Minyard {
5648bfffbccSCorey Minyard     int64_t next;
5658bfffbccSCorey Minyard     if (ibs->watchdog_running) {
5668bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
5678bfffbccSCorey Minyard     } else {
5688bfffbccSCorey Minyard         /* Wait a minute */
5698bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
5708bfffbccSCorey Minyard     }
5718bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
5728bfffbccSCorey Minyard }
5738bfffbccSCorey Minyard 
5748bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
5758bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
5768bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
5778bfffbccSCorey Minyard                                     uint8_t msg_id)
5788bfffbccSCorey Minyard {
5798bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
5808bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5818bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5828bfffbccSCorey Minyard     unsigned int netfn;
5838bfffbccSCorey Minyard     uint8_t rsp[MAX_IPMI_MSG_SIZE];
5848bfffbccSCorey Minyard     unsigned int rsp_len_holder = 0;
5858bfffbccSCorey Minyard     unsigned int *rsp_len = &rsp_len_holder;
5868bfffbccSCorey Minyard     unsigned int max_rsp_len = sizeof(rsp);
5878bfffbccSCorey Minyard 
5888bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
5898bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
590d13ada5dSCédric Le Goater     if (max_rsp_len < 3) {
591d13ada5dSCédric Le Goater         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
592d13ada5dSCédric Le Goater         goto out;
593d13ada5dSCédric Le Goater     }
594d13ada5dSCédric Le Goater 
5958bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
5968bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[1]);
5978bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0); /* Assume success */
5988bfffbccSCorey Minyard 
5998bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6008bfffbccSCorey Minyard     if (cmd_len < 2) {
6018bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
6028bfffbccSCorey Minyard         goto out;
6038bfffbccSCorey Minyard     }
6048bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6058bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
6068bfffbccSCorey Minyard         goto out;
6078bfffbccSCorey Minyard     }
6088bfffbccSCorey Minyard 
6098bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6108bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6118bfffbccSCorey Minyard         rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
6128bfffbccSCorey Minyard         goto out;
6138bfffbccSCorey Minyard     }
6148bfffbccSCorey Minyard 
6158bfffbccSCorey Minyard     netfn = cmd[0] >> 2;
6168bfffbccSCorey Minyard 
6178bfffbccSCorey Minyard     /* Odd netfns are not valid, make sure the command is registered */
6188bfffbccSCorey Minyard     if ((netfn & 1) || !ibs->netfns[netfn / 2] ||
6198bfffbccSCorey Minyard                         (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) ||
6208bfffbccSCorey Minyard                         (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) {
6218bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_CMD;
6228bfffbccSCorey Minyard         goto out;
6238bfffbccSCorey Minyard     }
6248bfffbccSCorey Minyard 
6258bfffbccSCorey Minyard     ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len,
6268bfffbccSCorey Minyard                                                 max_rsp_len);
6278bfffbccSCorey Minyard 
6288bfffbccSCorey Minyard  out:
6298bfffbccSCorey Minyard     k->handle_rsp(s, msg_id, rsp, *rsp_len);
6308bfffbccSCorey Minyard 
6318bfffbccSCorey Minyard     next_timeout(ibs);
6328bfffbccSCorey Minyard }
6338bfffbccSCorey Minyard 
6348bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6358bfffbccSCorey Minyard {
6368bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6378bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6388bfffbccSCorey Minyard 
6398bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6408bfffbccSCorey Minyard         goto out;
6418bfffbccSCorey Minyard     }
6428bfffbccSCorey Minyard 
6438bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6448bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6458bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6468bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6478bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6488bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6498bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6508bfffbccSCorey Minyard             break;
6518bfffbccSCorey Minyard 
6528bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6538bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6548bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6558bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6568bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6578bfffbccSCorey Minyard             break;
6588bfffbccSCorey Minyard 
6598bfffbccSCorey Minyard         default:
6608bfffbccSCorey Minyard             goto do_full_expiry;
6618bfffbccSCorey Minyard         }
6628bfffbccSCorey Minyard 
6638bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
6648bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
6658bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
6668bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
6678bfffbccSCorey Minyard         goto out;
6688bfffbccSCorey Minyard     }
6698bfffbccSCorey Minyard 
6708bfffbccSCorey Minyard  do_full_expiry:
6718bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
6728bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
6738bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
6748bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
6758bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
6768bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
6778bfffbccSCorey Minyard         break;
6788bfffbccSCorey Minyard 
6798bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
6808bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
6818bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
6828bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
6838bfffbccSCorey Minyard         break;
6848bfffbccSCorey Minyard 
6858bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
6868bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6878bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
6888bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
6898bfffbccSCorey Minyard         break;
6908bfffbccSCorey Minyard 
6918bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
6928bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6938bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
6948bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
6958bfffbccSCorey Minyard         break;
6968bfffbccSCorey Minyard     }
6978bfffbccSCorey Minyard 
6988bfffbccSCorey Minyard  out:
6998bfffbccSCorey Minyard     next_timeout(ibs);
7008bfffbccSCorey Minyard }
7018bfffbccSCorey Minyard 
7028bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7038bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
7048bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
7058bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
7068bfffbccSCorey Minyard {
7078bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7088bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7098bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7108bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7118bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7128bfffbccSCorey Minyard }
7138bfffbccSCorey Minyard 
7148bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7158bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
7168bfffbccSCorey Minyard                            uint8_t *rsp, unsigned int *rsp_len,
7178bfffbccSCorey Minyard                            unsigned int max_rsp_len)
7188bfffbccSCorey Minyard {
7198bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */
7208bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7218bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7228bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7238bfffbccSCorey Minyard }
7248bfffbccSCorey Minyard 
7258bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7268bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
7278bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
7288bfffbccSCorey Minyard                             unsigned int max_rsp_len)
7298bfffbccSCorey Minyard {
7308bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7318bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7328bfffbccSCorey Minyard 
7338bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
7348bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7358bfffbccSCorey Minyard     case 0: /* power down */
7368bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7378bfffbccSCorey Minyard         break;
7388bfffbccSCorey Minyard     case 1: /* power up */
7398bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
7408bfffbccSCorey Minyard         break;
7418bfffbccSCorey Minyard     case 2: /* power cycle */
7428bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7438bfffbccSCorey Minyard         break;
7448bfffbccSCorey Minyard     case 3: /* hard reset */
7458bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7468bfffbccSCorey Minyard         break;
7478bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
7488bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
7498bfffbccSCorey Minyard         break;
7508bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
7518bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s,
7528bfffbccSCorey Minyard                              IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
7538bfffbccSCorey Minyard         break;
7548bfffbccSCorey Minyard     default:
7558bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
7568bfffbccSCorey Minyard         return;
7578bfffbccSCorey Minyard     }
758d13ada5dSCédric Le Goater }
7598bfffbccSCorey Minyard 
760*b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
761*b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
762*b7088392SCédric Le Goater                            uint8_t *rsp, unsigned int *rsp_len,
763*b7088392SCédric Le Goater                            unsigned int max_rsp_len)
764*b7088392SCédric Le Goater {
765*b7088392SCédric Le Goater     IPMI_ADD_RSP_DATA(ibs->restart_cause & 0xf); /* Restart Cause */
766*b7088392SCédric Le Goater     IPMI_ADD_RSP_DATA(0);  /* Channel 0 */
767*b7088392SCédric Le Goater }
768*b7088392SCédric Le Goater 
7698bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
7708bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
7718bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
7728bfffbccSCorey Minyard                           unsigned int max_rsp_len)
7738bfffbccSCorey Minyard {
7748bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_id);
7758bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf);
7768bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f);
7778bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev2);
7788bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->ipmi_version);
7798bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */
7808bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[0]);
7818bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[1]);
7828bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
7838bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[0]);
7848bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[1]);
7858bfffbccSCorey Minyard }
7868bfffbccSCorey Minyard 
7878bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
7888bfffbccSCorey Minyard {
7898bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7908bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7918bfffbccSCorey Minyard     bool irqs_on;
7928bfffbccSCorey Minyard 
7938bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
7948bfffbccSCorey Minyard 
7958bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
7968bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
7978bfffbccSCorey Minyard 
7988bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
7998bfffbccSCorey Minyard }
8008bfffbccSCorey Minyard 
8018bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8028bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
8038bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
8048bfffbccSCorey Minyard                        unsigned int max_rsp_len)
8058bfffbccSCorey Minyard {
8068bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8078bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8088bfffbccSCorey Minyard 
8098bfffbccSCorey Minyard     /* Disable all interrupts */
8108bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8118bfffbccSCorey Minyard 
8128bfffbccSCorey Minyard     if (k->reset) {
8138bfffbccSCorey Minyard         k->reset(s, true);
8148bfffbccSCorey Minyard     }
8158bfffbccSCorey Minyard }
8168bfffbccSCorey Minyard 
8178bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8188bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
8198bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
8208bfffbccSCorey Minyard                        unsigned int max_rsp_len)
8218bfffbccSCorey Minyard {
8228bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8238bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8248bfffbccSCorey Minyard 
8258bfffbccSCorey Minyard     if (k->reset) {
8268bfffbccSCorey Minyard         k->reset(s, false);
8278bfffbccSCorey Minyard     }
8288bfffbccSCorey Minyard }
8298bfffbccSCorey Minyard 
8308bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
8318bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8328bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8338bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8348bfffbccSCorey Minyard {
8358bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8368bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8378bfffbccSCorey Minyard }
8388bfffbccSCorey Minyard 
8398bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8408bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8418bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8428bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8438bfffbccSCorey Minyard {
8448bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
8458bfffbccSCorey Minyard }
8468bfffbccSCorey Minyard 
8478bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
8488bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8498bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8508bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8518bfffbccSCorey Minyard {
8528bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8538bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8548bfffbccSCorey Minyard 
8558bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8568bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
8578bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8588bfffbccSCorey Minyard }
8598bfffbccSCorey Minyard 
8608bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
8618bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8628bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8638bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8648bfffbccSCorey Minyard {
8658bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->msg_flags);
8668bfffbccSCorey Minyard }
8678bfffbccSCorey Minyard 
8688bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
8698bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
8708bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
8718bfffbccSCorey Minyard                             unsigned int max_rsp_len)
8728bfffbccSCorey Minyard {
8738bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8748bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8758bfffbccSCorey Minyard     unsigned int i;
8768bfffbccSCorey Minyard 
8778bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
8788bfffbccSCorey Minyard         rsp[2] = 0x80;
879d13ada5dSCédric Le Goater         return;
8808bfffbccSCorey Minyard     }
8818bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
8828bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
8838bfffbccSCorey Minyard     }
8848bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
8858bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8868bfffbccSCorey Minyard }
8878bfffbccSCorey Minyard 
8888bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
8898bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
8908bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
8918bfffbccSCorey Minyard                     unsigned int max_rsp_len)
8928bfffbccSCorey Minyard {
8938bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
8948bfffbccSCorey Minyard 
8958bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
8968bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
8978bfffbccSCorey Minyard         rsp[2] = 0x80; /* Queue empty */
8988bfffbccSCorey Minyard         goto out;
8998bfffbccSCorey Minyard     }
9008bfffbccSCorey Minyard     rsp[3] = 0; /* Channel 0 */
9018bfffbccSCorey Minyard     *rsp_len += 1;
9028bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
9038bfffbccSCorey Minyard     memcpy(rsp + 4, msg->buf, msg->len);
9048bfffbccSCorey Minyard     *rsp_len += msg->len;
9058bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9068bfffbccSCorey Minyard     g_free(msg);
9078bfffbccSCorey Minyard 
9088bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9098bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
9108bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9118bfffbccSCorey Minyard 
9128bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9138bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9148bfffbccSCorey Minyard     }
9158bfffbccSCorey Minyard 
9168bfffbccSCorey Minyard out:
9178bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
9188bfffbccSCorey Minyard     return;
9198bfffbccSCorey Minyard }
9208bfffbccSCorey Minyard 
9218bfffbccSCorey Minyard static unsigned char
9228bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9238bfffbccSCorey Minyard {
9248bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9258bfffbccSCorey Minyard             csum += *data;
9268bfffbccSCorey Minyard     }
9278bfffbccSCorey Minyard 
9288bfffbccSCorey Minyard     return -csum;
9298bfffbccSCorey Minyard }
9308bfffbccSCorey Minyard 
9318bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9328bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
9338bfffbccSCorey Minyard                      uint8_t *rsp, unsigned int *rsp_len,
9348bfffbccSCorey Minyard                      unsigned int max_rsp_len)
9358bfffbccSCorey Minyard {
9368bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9378bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9388bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9398bfffbccSCorey Minyard     uint8_t *buf;
9408bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9418bfffbccSCorey Minyard 
9428bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
9438bfffbccSCorey Minyard 
9448bfffbccSCorey Minyard     if (cmd[2] != 0) {
9458bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
9468bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
947d13ada5dSCédric Le Goater         return;
9488bfffbccSCorey Minyard     }
9498bfffbccSCorey Minyard 
9508bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(10);
9518bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9528bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
9538bfffbccSCorey Minyard         rsp[2] = 0x83; /* NAK on write */
954d13ada5dSCédric Le Goater         return;
9558bfffbccSCorey Minyard     }
9568bfffbccSCorey Minyard 
9578bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
9588bfffbccSCorey Minyard     cmd_len -= 3;
9598bfffbccSCorey Minyard 
9608bfffbccSCorey Minyard     /*
9618bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
9628bfffbccSCorey Minyard      * be returned in the response.
9638bfffbccSCorey Minyard      */
9648bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
9658bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
966d13ada5dSCédric Le Goater         return; /* No response */
9678bfffbccSCorey Minyard     }
9688bfffbccSCorey Minyard 
9698bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
9708bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
9718bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
9728bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
9738bfffbccSCorey Minyard 
9748bfffbccSCorey Minyard     if (rqLun != 2) {
9758bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
976d13ada5dSCédric Le Goater         return;
9778bfffbccSCorey Minyard     }
9788bfffbccSCorey Minyard 
9798bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
9808bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
9818bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
9828bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
9838bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
9848bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
9858bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
9868bfffbccSCorey Minyard     msg->len = 6;
9878bfffbccSCorey Minyard 
9888bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
9898bfffbccSCorey Minyard         /* Not a command we handle. */
9908bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
9918bfffbccSCorey Minyard         goto end_msg;
9928bfffbccSCorey Minyard     }
9938bfffbccSCorey Minyard 
9948bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
9958bfffbccSCorey Minyard     buf[0] = 0;
9968bfffbccSCorey Minyard     buf[1] = 0;
9978bfffbccSCorey Minyard     buf[2] = 0;
9988bfffbccSCorey Minyard     buf[3] = 0;
9998bfffbccSCorey Minyard     buf[4] = 0x51;
10008bfffbccSCorey Minyard     buf[5] = 0;
10018bfffbccSCorey Minyard     buf[6] = 0;
10028bfffbccSCorey Minyard     buf[7] = 0;
10038bfffbccSCorey Minyard     buf[8] = 0;
10048bfffbccSCorey Minyard     buf[9] = 0;
10058bfffbccSCorey Minyard     buf[10] = 0;
10068bfffbccSCorey Minyard     msg->len += 11;
10078bfffbccSCorey Minyard 
10088bfffbccSCorey Minyard  end_msg:
10098bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10108bfffbccSCorey Minyard     msg->len++;
10118bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
10128bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10138bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10148bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10158bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
10168bfffbccSCorey Minyard }
10178bfffbccSCorey Minyard 
10188bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
10198bfffbccSCorey Minyard {
10208bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
10218bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
10228bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10238bfffbccSCorey Minyard         return;
10248bfffbccSCorey Minyard     }
10258bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10268bfffbccSCorey Minyard 
10278bfffbccSCorey Minyard 
10288bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10298bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10308bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10318bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10328bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10338bfffbccSCorey Minyard     }
10348bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10358bfffbccSCorey Minyard }
10368bfffbccSCorey Minyard 
10378bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10388bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
10398bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
10408bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
10418bfffbccSCorey Minyard {
10428bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
10438bfffbccSCorey Minyard         rsp[2] = 0x80;
1044d13ada5dSCédric Le Goater         return;
10458bfffbccSCorey Minyard     }
10468bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10478bfffbccSCorey Minyard }
10488bfffbccSCorey Minyard 
10498bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10508bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
10518bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
10528bfffbccSCorey Minyard                                unsigned int max_rsp_len)
10538bfffbccSCorey Minyard {
10548bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10558bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10568bfffbccSCorey Minyard     unsigned int val;
10578bfffbccSCorey Minyard 
10588bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
10598bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
10608bfffbccSCorey Minyard     if (val == 0 || val > 5) {
10618bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1062d13ada5dSCédric Le Goater         return;
10638bfffbccSCorey Minyard     }
10648bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
10658bfffbccSCorey Minyard     switch (val) {
10668bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
10678bfffbccSCorey Minyard         break;
10688bfffbccSCorey Minyard 
10698bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
10708bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
10718bfffbccSCorey Minyard         break;
10728bfffbccSCorey Minyard 
10738bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
10748bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
10758bfffbccSCorey Minyard         break;
10768bfffbccSCorey Minyard 
10778bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
10788bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
10798bfffbccSCorey Minyard         break;
10808bfffbccSCorey Minyard 
10818bfffbccSCorey Minyard     default:
10828bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
10838bfffbccSCorey Minyard     }
10848bfffbccSCorey Minyard     if (rsp[2]) {
10858bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1086d13ada5dSCédric Le Goater         return;
10878bfffbccSCorey Minyard     }
10888bfffbccSCorey Minyard 
10898bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
10908bfffbccSCorey Minyard     switch (val) {
10918bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
10928bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
10938bfffbccSCorey Minyard         break;
10948bfffbccSCorey Minyard 
10958bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
10968bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
10978bfffbccSCorey Minyard             /* NMI not supported. */
10988bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1099d13ada5dSCédric Le Goater             return;
11008bfffbccSCorey Minyard         }
11018bfffbccSCorey Minyard     default:
11028bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11038bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1104d13ada5dSCédric Le Goater         return;
11058bfffbccSCorey Minyard     }
11068bfffbccSCorey Minyard 
11078bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11088bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11098bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11108bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11118bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11128bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11138bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11148bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11158bfffbccSCorey Minyard     } else {
11168bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11178bfffbccSCorey Minyard     }
11188bfffbccSCorey Minyard }
11198bfffbccSCorey Minyard 
11208bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
11218bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
11228bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
11238bfffbccSCorey Minyard                                unsigned int max_rsp_len)
11248bfffbccSCorey Minyard {
11258bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_use);
11268bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_action);
11278bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout);
11288bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_expired);
11298bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11308bfffbccSCorey Minyard         long timeout;
11318bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11328bfffbccSCorey Minyard                    / 100000000);
11338bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(timeout & 0xff);
11348bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff);
11358bfffbccSCorey Minyard     } else {
11368bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11378bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11388bfffbccSCorey Minyard     }
11398bfffbccSCorey Minyard }
11408bfffbccSCorey Minyard 
11418bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11428bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
11438bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
11448bfffbccSCorey Minyard                              unsigned int max_rsp_len)
11458bfffbccSCorey Minyard {
11468bfffbccSCorey Minyard     unsigned int i;
11478bfffbccSCorey Minyard 
11488bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */
11498bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff);
11508bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff);
11518bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
11528bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11538bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11548bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]);
11558bfffbccSCorey Minyard     }
11568bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11578bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]);
11588bfffbccSCorey Minyard     }
11598bfffbccSCorey Minyard     /* Only modal support, reserve supported */
11608bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
11618bfffbccSCorey Minyard }
11628bfffbccSCorey Minyard 
11638bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
11648bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
11658bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
11668bfffbccSCorey Minyard                             unsigned int max_rsp_len)
11678bfffbccSCorey Minyard {
11688bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
11698bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
11708bfffbccSCorey Minyard }
11718bfffbccSCorey Minyard 
11728bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
11738bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
11748bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
11758bfffbccSCorey Minyard                     unsigned int max_rsp_len)
11768bfffbccSCorey Minyard {
11778bfffbccSCorey Minyard     unsigned int pos;
11788bfffbccSCorey Minyard     uint16_t nextrec;
1179a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
11808bfffbccSCorey Minyard 
11818bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
11828bfffbccSCorey Minyard     if (cmd[6]) {
11838bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
11848bfffbccSCorey Minyard     }
11858bfffbccSCorey Minyard     pos = 0;
11868bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
11878bfffbccSCorey Minyard                        &pos, &nextrec)) {
11888bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1189d13ada5dSCédric Le Goater         return;
11908bfffbccSCorey Minyard     }
1191a2295f0aSCédric Le Goater 
1192a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1193a2295f0aSCédric Le Goater 
1194a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
11958bfffbccSCorey Minyard         rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1196d13ada5dSCédric Le Goater         return;
11978bfffbccSCorey Minyard     }
11988bfffbccSCorey Minyard 
11998bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(nextrec & 0xff);
12008bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
12018bfffbccSCorey Minyard 
12028bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1203a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12048bfffbccSCorey Minyard     }
12058bfffbccSCorey Minyard 
12068bfffbccSCorey Minyard     if ((cmd[7] + *rsp_len) > max_rsp_len) {
12078bfffbccSCorey Minyard         rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1208d13ada5dSCédric Le Goater         return;
12098bfffbccSCorey Minyard     }
12108bfffbccSCorey Minyard     memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12118bfffbccSCorey Minyard     *rsp_len += cmd[7];
12128bfffbccSCorey Minyard }
12138bfffbccSCorey Minyard 
12148bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12158bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
12168bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
12178bfffbccSCorey Minyard                     unsigned int max_rsp_len)
12188bfffbccSCorey Minyard {
12198bfffbccSCorey Minyard     uint16_t recid;
1220a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
12218bfffbccSCorey Minyard 
1222a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
12238bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1224d13ada5dSCédric Le Goater         return;
12258bfffbccSCorey Minyard     }
12268bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(recid & 0xff);
12278bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
12288bfffbccSCorey Minyard }
12298bfffbccSCorey Minyard 
12308bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12318bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12328bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12338bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12348bfffbccSCorey Minyard {
12358bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12368bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
12378bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
12388bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1239d13ada5dSCédric Le Goater         return;
12408bfffbccSCorey Minyard     }
12418bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12428bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12438bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12448bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
12458bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12468bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12478bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
12488bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12498bfffbccSCorey Minyard     } else {
12508bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
12518bfffbccSCorey Minyard         return;
12528bfffbccSCorey Minyard     }
1253d13ada5dSCédric Le Goater }
12548bfffbccSCorey Minyard 
12558bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
12568bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
12578bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
12588bfffbccSCorey Minyard                          unsigned int max_rsp_len)
12598bfffbccSCorey Minyard {
12608bfffbccSCorey Minyard     unsigned int i, val;
12618bfffbccSCorey Minyard 
12628bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */
12638bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff);
12648bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff);
12658bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
12668bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
12678bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
12688bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
12698bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]);
12708bfffbccSCorey Minyard     }
12718bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
12728bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]);
12738bfffbccSCorey Minyard     }
12748bfffbccSCorey Minyard     /* Only support Reserve SEL */
12758bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
12768bfffbccSCorey Minyard }
12778bfffbccSCorey Minyard 
12788bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
12798bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
12808bfffbccSCorey Minyard                         uint8_t *rsp, unsigned int *rsp_len,
12818bfffbccSCorey Minyard                         unsigned int max_rsp_len)
12828bfffbccSCorey Minyard {
12838bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
12848bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
12858bfffbccSCorey Minyard }
12868bfffbccSCorey Minyard 
12878bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
12888bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12898bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12908bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12918bfffbccSCorey Minyard {
12928bfffbccSCorey Minyard     unsigned int val;
12938bfffbccSCorey Minyard 
12948bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12958bfffbccSCorey Minyard     if (cmd[6]) {
12968bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
12978bfffbccSCorey Minyard     }
12988bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
12998bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1300d13ada5dSCédric Le Goater         return;
13018bfffbccSCorey Minyard     }
13028bfffbccSCorey Minyard     if (cmd[6] > 15) {
13038bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1304d13ada5dSCédric Le Goater         return;
13058bfffbccSCorey Minyard     }
13068bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
13078bfffbccSCorey Minyard         cmd[7] = 16;
13088bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
13098bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1310d13ada5dSCédric Le Goater         return;
13118bfffbccSCorey Minyard     } else {
13128bfffbccSCorey Minyard         cmd[7] += cmd[6];
13138bfffbccSCorey Minyard     }
13148bfffbccSCorey Minyard 
13158bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
13168bfffbccSCorey Minyard     if (val == 0xffff) {
13178bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
13188bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
13198bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1320d13ada5dSCédric Le Goater         return;
13218bfffbccSCorey Minyard     }
13228bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
13238bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
13248bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
13258bfffbccSCorey Minyard     } else {
13268bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((val + 1) & 0xff);
13278bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff);
13288bfffbccSCorey Minyard     }
13298bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
13308bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
13318bfffbccSCorey Minyard     }
13328bfffbccSCorey Minyard }
13338bfffbccSCorey Minyard 
13348bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13358bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
13368bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
13378bfffbccSCorey Minyard                           unsigned int max_rsp_len)
13388bfffbccSCorey Minyard {
13398bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(18);
13408bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
13418bfffbccSCorey Minyard         rsp[2] = IPMI_CC_OUT_OF_SPACE;
1342d13ada5dSCédric Le Goater         return;
13438bfffbccSCorey Minyard     }
13448bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
13458bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[2]);
13468bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[3]);
13478bfffbccSCorey Minyard }
13488bfffbccSCorey Minyard 
13498bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13508bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
13518bfffbccSCorey Minyard                       uint8_t *rsp, unsigned int *rsp_len,
13528bfffbccSCorey Minyard                       unsigned int max_rsp_len)
13538bfffbccSCorey Minyard {
13548bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
13558bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
13568bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13578bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1358d13ada5dSCédric Le Goater         return;
13598bfffbccSCorey Minyard     }
13608bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13618bfffbccSCorey Minyard         ibs->sel.next_free = 0;
13628bfffbccSCorey Minyard         ibs->sel.overflow = 0;
13638bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
13648bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
13658bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
13668bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
13678bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
13688bfffbccSCorey Minyard     } else {
13698bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
13708bfffbccSCorey Minyard         return;
13718bfffbccSCorey Minyard     }
1372d13ada5dSCédric Le Goater }
13738bfffbccSCorey Minyard 
13748bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
13758bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
13768bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
13778bfffbccSCorey Minyard                          unsigned int max_rsp_len)
13788bfffbccSCorey Minyard {
13798bfffbccSCorey Minyard     uint32_t val;
13808bfffbccSCorey Minyard     struct ipmi_time now;
13818bfffbccSCorey Minyard 
13828bfffbccSCorey Minyard     ipmi_gettime(&now);
13838bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
13848bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
13858bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
13868bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
13878bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
13888bfffbccSCorey Minyard }
13898bfffbccSCorey Minyard 
13908bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
13918bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
13928bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
13938bfffbccSCorey Minyard                          unsigned int max_rsp_len)
13948bfffbccSCorey Minyard {
13958bfffbccSCorey Minyard     uint32_t val;
13968bfffbccSCorey Minyard     struct ipmi_time now;
13978bfffbccSCorey Minyard 
13988bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(6);
13998bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
14008bfffbccSCorey Minyard     ipmi_gettime(&now);
14018bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
14028bfffbccSCorey Minyard }
14038bfffbccSCorey Minyard 
14048bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
14058bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14068bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14078bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14088bfffbccSCorey Minyard {
14098bfffbccSCorey Minyard     IPMISensor *sens;
14108bfffbccSCorey Minyard 
14118bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
14128bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14138bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14148bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1415d13ada5dSCédric Le Goater         return;
14168bfffbccSCorey Minyard     }
14178bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14188bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
14198bfffbccSCorey Minyard     case 0: /* Do not change */
14208bfffbccSCorey Minyard         break;
14218bfffbccSCorey Minyard     case 1: /* Enable bits */
14228bfffbccSCorey Minyard         if (cmd_len > 4) {
14238bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
14248bfffbccSCorey Minyard         }
14258bfffbccSCorey Minyard         if (cmd_len > 5) {
14268bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
14278bfffbccSCorey Minyard         }
14288bfffbccSCorey Minyard         if (cmd_len > 6) {
14298bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
14308bfffbccSCorey Minyard         }
14318bfffbccSCorey Minyard         if (cmd_len > 7) {
14328bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
14338bfffbccSCorey Minyard         }
14348bfffbccSCorey Minyard         break;
14358bfffbccSCorey Minyard     case 2: /* Disable bits */
14368bfffbccSCorey Minyard         if (cmd_len > 4) {
14378bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14388bfffbccSCorey Minyard         }
14398bfffbccSCorey Minyard         if (cmd_len > 5) {
14408bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14418bfffbccSCorey Minyard         }
14428bfffbccSCorey Minyard         if (cmd_len > 6) {
14438bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14448bfffbccSCorey Minyard         }
14458bfffbccSCorey Minyard         if (cmd_len > 7) {
14468bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14478bfffbccSCorey Minyard         }
14488bfffbccSCorey Minyard         break;
14498bfffbccSCorey Minyard     case 3:
14508bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1451d13ada5dSCédric Le Goater         return;
14528bfffbccSCorey Minyard     }
14538bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14548bfffbccSCorey Minyard }
14558bfffbccSCorey Minyard 
14568bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14578bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14588bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14598bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14608bfffbccSCorey Minyard {
14618bfffbccSCorey Minyard     IPMISensor *sens;
14628bfffbccSCorey Minyard 
14638bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
14648bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14658bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14668bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1467d13ada5dSCédric Le Goater         return;
14688bfffbccSCorey Minyard     }
14698bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14708bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
14718bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff);
14728bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
14738bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
14748bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
14758bfffbccSCorey Minyard }
14768bfffbccSCorey Minyard 
14778bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
14788bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
14798bfffbccSCorey Minyard                               uint8_t *rsp, unsigned int *rsp_len,
14808bfffbccSCorey Minyard                               unsigned int max_rsp_len)
14818bfffbccSCorey Minyard {
14828bfffbccSCorey Minyard     IPMISensor *sens;
14838bfffbccSCorey Minyard 
14848bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
14858bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
14868bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14878bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1488d13ada5dSCédric Le Goater         return;
14898bfffbccSCorey Minyard     }
14908bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14918bfffbccSCorey Minyard 
14928bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
14938bfffbccSCorey Minyard         /* Just clear everything */
14948bfffbccSCorey Minyard         sens->states = 0;
14958bfffbccSCorey Minyard         return;
14968bfffbccSCorey Minyard     }
1497d13ada5dSCédric Le Goater }
14988bfffbccSCorey Minyard 
14998bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
15008bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
15018bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
15028bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
15038bfffbccSCorey Minyard {
15048bfffbccSCorey Minyard     IPMISensor *sens;
15058bfffbccSCorey Minyard 
15068bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
15078bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
15088bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15098bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1510d13ada5dSCédric Le Goater         return;
15118bfffbccSCorey Minyard     }
15128bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15138bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15148bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15158bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_states & 0xff);
15168bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
15178bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
15188bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
15198bfffbccSCorey Minyard }
15208bfffbccSCorey Minyard 
15218bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
15228bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
15238bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
15248bfffbccSCorey Minyard                                unsigned int max_rsp_len)
15258bfffbccSCorey Minyard {
15268bfffbccSCorey Minyard     IPMISensor *sens;
15278bfffbccSCorey Minyard 
15288bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
15298bfffbccSCorey Minyard     if ((cmd[2] > MAX_SENSORS) ||
15308bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15318bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1532d13ada5dSCédric Le Goater         return;
15338bfffbccSCorey Minyard     }
15348bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15358bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15368bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15378bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->states & 0xff);
15388bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
15398bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
15408bfffbccSCorey Minyard     }
15418bfffbccSCorey Minyard }
15428bfffbccSCorey Minyard 
1543728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1544728710e1SCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1545728710e1SCédric Le Goater                                uint8_t *rsp, unsigned int *rsp_len,
1546728710e1SCédric Le Goater                                unsigned int max_rsp_len)
1547728710e1SCédric Le Goater {
1548728710e1SCédric Le Goater     IPMISensor *sens;
1549728710e1SCédric Le Goater 
1550728710e1SCédric Le Goater 
1551728710e1SCédric Le Goater     IPMI_CHECK_CMD_LEN(5);
1552728710e1SCédric Le Goater     if ((cmd[2] > MAX_SENSORS) ||
1553728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1554728710e1SCédric Le Goater         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1555728710e1SCédric Le Goater         return;
1556728710e1SCédric Le Goater     }
1557728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1558728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1559728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1560728710e1SCédric Le Goater }
1561728710e1SCédric Le Goater 
1562728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1563728710e1SCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1564728710e1SCédric Le Goater                                uint8_t *rsp, unsigned int *rsp_len,
1565728710e1SCédric Le Goater                                unsigned int max_rsp_len)
1566728710e1SCédric Le Goater {
1567728710e1SCédric Le Goater     IPMISensor *sens;
1568728710e1SCédric Le Goater 
1569728710e1SCédric Le Goater 
1570728710e1SCédric Le Goater     IPMI_CHECK_CMD_LEN(3);
1571728710e1SCédric Le Goater     if ((cmd[2] > MAX_SENSORS) ||
1572728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1573728710e1SCédric Le Goater         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1574728710e1SCédric Le Goater         return;
1575728710e1SCédric Le Goater     }
1576728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1577728710e1SCédric Le Goater     IPMI_ADD_RSP_DATA(sens->sensor_type);
1578728710e1SCédric Le Goater     IPMI_ADD_RSP_DATA(sens->evt_reading_type_code);
1579728710e1SCédric Le Goater }
1580728710e1SCédric Le Goater 
1581728710e1SCédric Le Goater 
158262a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
15838bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
15848bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
1585*b7088392SCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = chassis_control,
1586*b7088392SCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = chassis_get_sys_restart_cause
15878bfffbccSCorey Minyard };
15888bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
158962a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
15908bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
15918bfffbccSCorey Minyard };
15928bfffbccSCorey Minyard 
159362a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
15948bfffbccSCorey Minyard     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
15958bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
15968bfffbccSCorey Minyard     [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
15978bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
1598728710e1SCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading,
1599728710e1SCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = set_sensor_type,
1600728710e1SCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = get_sensor_type,
16018bfffbccSCorey Minyard };
16028bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
160362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
16048bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
16058bfffbccSCorey Minyard };
16068bfffbccSCorey Minyard 
160762a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
16088bfffbccSCorey Minyard     [IPMI_CMD_GET_DEVICE_ID] = get_device_id,
16098bfffbccSCorey Minyard     [IPMI_CMD_COLD_RESET] = cold_reset,
16108bfffbccSCorey Minyard     [IPMI_CMD_WARM_RESET] = warm_reset,
16118bfffbccSCorey Minyard     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
16128bfffbccSCorey Minyard     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
16138bfffbccSCorey Minyard     [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
16148bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags,
16158bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG] = get_msg,
16168bfffbccSCorey Minyard     [IPMI_CMD_SEND_MSG] = send_msg,
16178bfffbccSCorey Minyard     [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf,
16188bfffbccSCorey Minyard     [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer,
16198bfffbccSCorey Minyard     [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer,
16208bfffbccSCorey Minyard     [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
16218bfffbccSCorey Minyard };
16228bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
162362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
16248bfffbccSCorey Minyard     .cmd_handlers = app_cmds
16258bfffbccSCorey Minyard };
16268bfffbccSCorey Minyard 
162762a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
16288bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
16298bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
16308bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR] = get_sdr,
16318bfffbccSCorey Minyard     [IPMI_CMD_ADD_SDR] = add_sdr,
16328bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep,
16338bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_INFO] = get_sel_info,
16348bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SEL] = reserve_sel,
16358bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry,
16368bfffbccSCorey Minyard     [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry,
16378bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SEL] = clear_sel,
16388bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = get_sel_time,
16398bfffbccSCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = set_sel_time,
16408bfffbccSCorey Minyard };
16418bfffbccSCorey Minyard 
16428bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
164362a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
16448bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
16458bfffbccSCorey Minyard };
16468bfffbccSCorey Minyard 
16478bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
16488bfffbccSCorey Minyard {
16498bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
16508bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
16518bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
16528bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
16538bfffbccSCorey Minyard }
16548bfffbccSCorey Minyard 
16558bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
16568bfffbccSCorey Minyard     /* Watchdog device */
16578bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
16588bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
16598bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16608bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
16618bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
16628bfffbccSCorey Minyard     /* End */
16638bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
16648bfffbccSCorey Minyard };
16658bfffbccSCorey Minyard 
1666bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1667bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1668bd66bcfcSCorey Minyard     .version_id = 1,
1669bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1670bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1671bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1672bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1673bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1674bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1675bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1676bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1677bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1678bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1679bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1680bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1681bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1682bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1683bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1684bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1685bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1686bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1687bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1688bd66bcfcSCorey Minyard                        IPMIBmcSim),
1689bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1690bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1691bd66bcfcSCorey Minyard     }
1692bd66bcfcSCorey Minyard };
1693bd66bcfcSCorey Minyard 
16948bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj)
16958bfffbccSCorey Minyard {
16968bfffbccSCorey Minyard     IPMIBmc *b = IPMI_BMC(obj);
16978bfffbccSCorey Minyard     unsigned int i;
16988bfffbccSCorey Minyard     unsigned int recid;
16998bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
17008bfffbccSCorey Minyard 
17018bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
17028bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
17038bfffbccSCorey Minyard 
17048bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
17058bfffbccSCorey Minyard     ibs->device_id = 0x20;
17068bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1707*b7088392SCédric Le Goater     ibs->restart_cause = 0;
17088bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
17098bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
17108bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
17118bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
17128bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
17138bfffbccSCorey Minyard     }
17148bfffbccSCorey Minyard 
17158bfffbccSCorey Minyard     for (i = 0;;) {
1716a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh;
17178bfffbccSCorey Minyard         int len;
1718a2295f0aSCédric Le Goater         if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) {
17197cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
17208bfffbccSCorey Minyard             return;
17218bfffbccSCorey Minyard         }
1722a2295f0aSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &init_sdrs[i];
1723a2295f0aSCédric Le Goater         len = ipmi_sdr_length(sdrh);
1724a2295f0aSCédric Le Goater         recid = ipmi_sdr_recid(sdrh);
17258bfffbccSCorey Minyard         if (recid == 0xffff) {
17268bfffbccSCorey Minyard             break;
17278bfffbccSCorey Minyard         }
1728792afddbSCédric Le Goater         if ((i + len) > sizeof(init_sdrs)) {
17297cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
17308bfffbccSCorey Minyard             return;
17318bfffbccSCorey Minyard         }
1732a2295f0aSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
1733792afddbSCédric Le Goater         i += len;
17348bfffbccSCorey Minyard     }
17358bfffbccSCorey Minyard 
17368bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
17378bfffbccSCorey Minyard     register_cmds(ibs);
17388bfffbccSCorey Minyard 
17398bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1740bd66bcfcSCorey Minyard 
1741bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
17428bfffbccSCorey Minyard }
17438bfffbccSCorey Minyard 
17448bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
17458bfffbccSCorey Minyard {
17468bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
17478bfffbccSCorey Minyard 
17488bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
17498bfffbccSCorey Minyard }
17508bfffbccSCorey Minyard 
17518bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
17528bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
17538bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
17548bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
17558bfffbccSCorey Minyard     .instance_init = ipmi_sim_init,
17568bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
17578bfffbccSCorey Minyard };
17588bfffbccSCorey Minyard 
17598bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
17608bfffbccSCorey Minyard {
17618bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
17628bfffbccSCorey Minyard }
17638bfffbccSCorey Minyard 
17648bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1765