xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 73d60fa5fae60c8e07e1f295d8c7fd5d04320160)
18bfffbccSCorey Minyard /*
28bfffbccSCorey Minyard  * IPMI BMC emulation
38bfffbccSCorey Minyard  *
48bfffbccSCorey Minyard  * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
58bfffbccSCorey Minyard  *
68bfffbccSCorey Minyard  * Permission is hereby granted, free of charge, to any person obtaining a copy
78bfffbccSCorey Minyard  * of this software and associated documentation files (the "Software"), to deal
88bfffbccSCorey Minyard  * in the Software without restriction, including without limitation the rights
98bfffbccSCorey Minyard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108bfffbccSCorey Minyard  * copies of the Software, and to permit persons to whom the Software is
118bfffbccSCorey Minyard  * furnished to do so, subject to the following conditions:
128bfffbccSCorey Minyard  *
138bfffbccSCorey Minyard  * The above copyright notice and this permission notice shall be included in
148bfffbccSCorey Minyard  * all copies or substantial portions of the Software.
158bfffbccSCorey Minyard  *
168bfffbccSCorey Minyard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178bfffbccSCorey Minyard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188bfffbccSCorey Minyard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198bfffbccSCorey Minyard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208bfffbccSCorey Minyard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218bfffbccSCorey Minyard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228bfffbccSCorey Minyard  * THE SOFTWARE.
238bfffbccSCorey Minyard  */
248bfffbccSCorey Minyard 
250430891cSPeter Maydell #include "qemu/osdep.h"
2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h"
278bfffbccSCorey Minyard #include "qemu/timer.h"
288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h"
298bfffbccSCorey Minyard #include "qemu/error-report.h"
308bfffbccSCorey Minyard 
318bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
328bfffbccSCorey Minyard 
338bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
358bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
36b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
378bfffbccSCorey Minyard 
388bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
398bfffbccSCorey Minyard 
408bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
418bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
428bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
438bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
45728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
46728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
478bfffbccSCorey Minyard 
488bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
498bfffbccSCorey Minyard 
508bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
518bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
528bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
5352ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
5452ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
568bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
578bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
588bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
598bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
608bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
618bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
628bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
648bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
658bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
668bfffbccSCorey Minyard 
678bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
688bfffbccSCorey Minyard 
698bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
718bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
728bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
738bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
748bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
758bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
768bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
788bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
798bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
808bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
818bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
828bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
848bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
858bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
868bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
878bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
888bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
898bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
908bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
918bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
928bfffbccSCorey Minyard 
938bfffbccSCorey Minyard 
948bfffbccSCorey Minyard /* Same as a timespec struct. */
958bfffbccSCorey Minyard struct ipmi_time {
968bfffbccSCorey Minyard     long tv_sec;
978bfffbccSCorey Minyard     long tv_nsec;
988bfffbccSCorey Minyard };
998bfffbccSCorey Minyard 
1008bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1018bfffbccSCorey Minyard 
1028bfffbccSCorey Minyard typedef struct IPMISel {
1038bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1048bfffbccSCorey Minyard     unsigned int next_free;
1058bfffbccSCorey Minyard     long time_offset;
1068bfffbccSCorey Minyard     uint16_t reservation;
1078bfffbccSCorey Minyard     uint8_t last_addition[4];
1088bfffbccSCorey Minyard     uint8_t last_clear[4];
1098bfffbccSCorey Minyard     uint8_t overflow;
1108bfffbccSCorey Minyard } IPMISel;
1118bfffbccSCorey Minyard 
1128bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1138bfffbccSCorey Minyard 
1148bfffbccSCorey Minyard typedef struct IPMISdr {
1158bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1168bfffbccSCorey Minyard     unsigned int next_free;
1178bfffbccSCorey Minyard     uint16_t next_rec_id;
1188bfffbccSCorey Minyard     uint16_t reservation;
1198bfffbccSCorey Minyard     uint8_t last_addition[4];
1208bfffbccSCorey Minyard     uint8_t last_clear[4];
1218bfffbccSCorey Minyard     uint8_t overflow;
1228bfffbccSCorey Minyard } IPMISdr;
1238bfffbccSCorey Minyard 
1248bfffbccSCorey Minyard typedef struct IPMISensor {
1258bfffbccSCorey Minyard     uint8_t status;
1268bfffbccSCorey Minyard     uint8_t reading;
1278bfffbccSCorey Minyard     uint16_t states_suppt;
1288bfffbccSCorey Minyard     uint16_t assert_suppt;
1298bfffbccSCorey Minyard     uint16_t deassert_suppt;
1308bfffbccSCorey Minyard     uint16_t states;
1318bfffbccSCorey Minyard     uint16_t assert_states;
1328bfffbccSCorey Minyard     uint16_t deassert_states;
1338bfffbccSCorey Minyard     uint16_t assert_enable;
1348bfffbccSCorey Minyard     uint16_t deassert_enable;
1358bfffbccSCorey Minyard     uint8_t  sensor_type;
1368bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1378bfffbccSCorey Minyard } IPMISensor;
1388bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1398bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1408bfffbccSCorey Minyard                                              !!(v))
1418bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1428bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1438bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1448bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1458bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1468bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1478bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1488bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1498bfffbccSCorey Minyard                                              (v & 0xc0))
1508bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1518bfffbccSCorey Minyard 
1528bfffbccSCorey Minyard #define MAX_SENSORS 20
1538bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1548bfffbccSCorey Minyard 
1558bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
1568bfffbccSCorey Minyard 
1578bfffbccSCorey Minyard #define MAX_NETFNS 64
1588bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s,
1598bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1608bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
1618bfffbccSCorey Minyard                                unsigned int max_rsp_len);
1628bfffbccSCorey Minyard typedef struct IPMINetfn {
1638bfffbccSCorey Minyard     unsigned int cmd_nums;
1648bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1658bfffbccSCorey Minyard } IPMINetfn;
1668bfffbccSCorey Minyard 
1678bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1688bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1698bfffbccSCorey Minyard     uint8_t len;
1708bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1718bfffbccSCorey Minyard } IPMIRcvBufEntry;
1728bfffbccSCorey Minyard 
1738bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1748bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1758bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1768bfffbccSCorey Minyard struct IPMIBmcSim {
1778bfffbccSCorey Minyard     IPMIBmc parent;
1788bfffbccSCorey Minyard 
1798bfffbccSCorey Minyard     QEMUTimer *timer;
1808bfffbccSCorey Minyard 
1818bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1828bfffbccSCorey Minyard     uint8_t msg_flags;
1838bfffbccSCorey Minyard 
1848bfffbccSCorey Minyard     bool     watchdog_initialized;
1858bfffbccSCorey Minyard     uint8_t  watchdog_use;
1868bfffbccSCorey Minyard     uint8_t  watchdog_action;
1878bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1888bfffbccSCorey Minyard     bool     watchdog_expired;
1898bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1908bfffbccSCorey Minyard 
1918bfffbccSCorey Minyard     bool     watchdog_running;
1928bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1938bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1948bfffbccSCorey Minyard 
1958bfffbccSCorey Minyard     uint8_t device_id;
1968bfffbccSCorey Minyard     uint8_t ipmi_version;
1978bfffbccSCorey Minyard     uint8_t device_rev;
1988bfffbccSCorey Minyard     uint8_t fwrev1;
1998bfffbccSCorey Minyard     uint8_t fwrev2;
2008bfffbccSCorey Minyard     uint8_t mfg_id[3];
2018bfffbccSCorey Minyard     uint8_t product_id[2];
2028bfffbccSCorey Minyard 
203b7088392SCédric Le Goater     uint8_t restart_cause;
204b7088392SCédric Le Goater 
20552ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
20652ba4d50SCédric Le Goater     uint8_t uuid[16];
20752ba4d50SCédric Le Goater 
2088bfffbccSCorey Minyard     IPMISel sel;
2098bfffbccSCorey Minyard     IPMISdr sdr;
2108bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2118bfffbccSCorey Minyard 
2128bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2138bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2148bfffbccSCorey Minyard 
2158bfffbccSCorey Minyard     QemuMutex lock;
2168bfffbccSCorey Minyard     /* We allow one event in the buffer */
2178bfffbccSCorey Minyard     uint8_t evtbuf[16];
2188bfffbccSCorey Minyard 
2198bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2208bfffbccSCorey Minyard };
2218bfffbccSCorey Minyard 
2228bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2238bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2248bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2258bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2268bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2278bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2288bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2308bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2318bfffbccSCorey Minyard 
2328bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2338bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2348bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2358bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2368bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2378bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2388bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2398bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2418bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2428bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2438bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2448bfffbccSCorey Minyard 
2458bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2468bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2478bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2488bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2498bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2608bfffbccSCorey Minyard 
2618bfffbccSCorey Minyard 
2628bfffbccSCorey Minyard /* Add a byte to the response. */
2638bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \
2648bfffbccSCorey Minyard     do {                                                   \
2658bfffbccSCorey Minyard         if (*rsp_len >= max_rsp_len) {                     \
2668bfffbccSCorey Minyard             rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;       \
267d13ada5dSCédric Le Goater             return;                                        \
2688bfffbccSCorey Minyard         }                                                  \
2698bfffbccSCorey Minyard         rsp[(*rsp_len)++] = (b);                           \
2708bfffbccSCorey Minyard     } while (0)
2718bfffbccSCorey Minyard 
2728bfffbccSCorey Minyard /* Verify that the received command is a certain length. */
2738bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \
2748bfffbccSCorey Minyard     if (cmd_len < l) {                                     \
2758bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;      \
276d13ada5dSCédric Le Goater         return; \
2778bfffbccSCorey Minyard     }
2788bfffbccSCorey Minyard 
2798bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */
2808bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \
2818bfffbccSCorey Minyard     do {                                                   \
2828bfffbccSCorey Minyard         if ((cmd[off] | (cmd[off + 1] << 8)) != r) {       \
2838bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_RESERVATION;          \
284d13ada5dSCédric Le Goater             return;                                        \
2858bfffbccSCorey Minyard         }                                                  \
2868bfffbccSCorey Minyard     } while (0)
2878bfffbccSCorey Minyard 
2888bfffbccSCorey Minyard 
2898bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2908bfffbccSCorey Minyard 
2918bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2928bfffbccSCorey Minyard {
2938bfffbccSCorey Minyard     int64_t stime;
2948bfffbccSCorey Minyard 
2958bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2968bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
2978bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
2988bfffbccSCorey Minyard }
2998bfffbccSCorey Minyard 
3008bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3018bfffbccSCorey Minyard {
3028bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3038bfffbccSCorey Minyard }
3048bfffbccSCorey Minyard 
3058bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3068bfffbccSCorey Minyard {
3078bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3088bfffbccSCorey Minyard 
3098bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3108bfffbccSCorey Minyard }
3118bfffbccSCorey Minyard 
3128bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3138bfffbccSCorey Minyard {
3148bfffbccSCorey Minyard     unsigned int val;
3158bfffbccSCorey Minyard     struct ipmi_time now;
3168bfffbccSCorey Minyard 
3178bfffbccSCorey Minyard     ipmi_gettime(&now);
3188bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3198bfffbccSCorey Minyard     ts[0] = val & 0xff;
3208bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3218bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3228bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3238bfffbccSCorey Minyard }
3248bfffbccSCorey Minyard 
3258bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3268bfffbccSCorey Minyard {
3278bfffbccSCorey Minyard     sdr->reservation++;
3288bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3298bfffbccSCorey Minyard         sdr->reservation = 1;
3308bfffbccSCorey Minyard     }
3318bfffbccSCorey Minyard }
3328bfffbccSCorey Minyard 
333a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
334a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3358bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3368bfffbccSCorey Minyard {
337a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
338a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
339a2295f0aSCédric Le Goater 
340a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3418bfffbccSCorey Minyard         return 1;
3428bfffbccSCorey Minyard     }
3438bfffbccSCorey Minyard 
344a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3458bfffbccSCorey Minyard         return 1;
3468bfffbccSCorey Minyard     }
3478bfffbccSCorey Minyard 
3488bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3498bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3508bfffbccSCorey Minyard         return 1;
3518bfffbccSCorey Minyard     }
3528bfffbccSCorey Minyard 
353a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
354a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
355a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
356a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3578bfffbccSCorey Minyard 
3588bfffbccSCorey Minyard     if (recid) {
3598bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3608bfffbccSCorey Minyard     }
3618bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3628bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3638bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3648bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3658bfffbccSCorey Minyard     return 0;
3668bfffbccSCorey Minyard }
3678bfffbccSCorey Minyard 
3688bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3698bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3708bfffbccSCorey Minyard {
3718bfffbccSCorey Minyard     unsigned int pos = *retpos;
3728bfffbccSCorey Minyard 
3738bfffbccSCorey Minyard     while (pos < sdr->next_free) {
374a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
375a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
376a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
377a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3788bfffbccSCorey Minyard 
3798bfffbccSCorey Minyard         if (trec == recid) {
3808bfffbccSCorey Minyard             if (nextrec) {
3818bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3828bfffbccSCorey Minyard                     *nextrec = 0xffff;
3838bfffbccSCorey Minyard                 } else {
3848bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3858bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3868bfffbccSCorey Minyard                 }
3878bfffbccSCorey Minyard             }
3888bfffbccSCorey Minyard             *retpos = pos;
3898bfffbccSCorey Minyard             return 0;
3908bfffbccSCorey Minyard         }
3918bfffbccSCorey Minyard         pos = nextpos;
3928bfffbccSCorey Minyard     }
3938bfffbccSCorey Minyard     return 1;
3948bfffbccSCorey Minyard }
3958bfffbccSCorey Minyard 
3968bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
3978bfffbccSCorey Minyard {
3988bfffbccSCorey Minyard     sel->reservation++;
3998bfffbccSCorey Minyard     if (sel->reservation == 0) {
4008bfffbccSCorey Minyard         sel->reservation = 1;
4018bfffbccSCorey Minyard     }
4028bfffbccSCorey Minyard }
4038bfffbccSCorey Minyard 
4048bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4058bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4068bfffbccSCorey Minyard {
4078bfffbccSCorey Minyard     event[0] = 0xff;
4088bfffbccSCorey Minyard     event[1] = 0xff;
4098bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
4108bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4118bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4128bfffbccSCorey Minyard         return 1;
4138bfffbccSCorey Minyard     }
4148bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4158bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4168bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4178bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4188bfffbccSCorey Minyard     ibs->sel.next_free++;
4198bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4208bfffbccSCorey Minyard     return 0;
4218bfffbccSCorey Minyard }
4228bfffbccSCorey Minyard 
4238bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4248bfffbccSCorey Minyard {
4258bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4268bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4278bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4288bfffbccSCorey Minyard }
4298bfffbccSCorey Minyard 
4308bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4318bfffbccSCorey Minyard {
4328bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4338bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4348bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4358bfffbccSCorey Minyard }
4368bfffbccSCorey Minyard 
4378bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4388bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4398bfffbccSCorey Minyard {
4408bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4418bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4428bfffbccSCorey Minyard     uint8_t evt[16];
4438bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4448bfffbccSCorey Minyard 
4458bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4468bfffbccSCorey Minyard         return;
4478bfffbccSCorey Minyard     }
4488bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4498bfffbccSCorey Minyard         return;
4508bfffbccSCorey Minyard     }
4518bfffbccSCorey Minyard 
4528bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4538bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4548bfffbccSCorey Minyard     evt[8] = 0;
4558bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4568bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4578bfffbccSCorey Minyard     evt[11] = sens_num;
4588bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4598bfffbccSCorey Minyard     evt[13] = evd1;
4608bfffbccSCorey Minyard     evt[14] = evd2;
4618bfffbccSCorey Minyard     evt[15] = evd3;
4628bfffbccSCorey Minyard 
4638bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4648bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4658bfffbccSCorey Minyard     }
4668bfffbccSCorey Minyard 
4678bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
468d13ada5dSCédric Le Goater         return;
4698bfffbccSCorey Minyard     }
4708bfffbccSCorey Minyard 
4718bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4728bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4738bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4748bfffbccSCorey Minyard }
4758bfffbccSCorey Minyard 
4768bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4778bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4788bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4798bfffbccSCorey Minyard {
4808bfffbccSCorey Minyard     IPMISensor *sens;
4818bfffbccSCorey Minyard     uint16_t mask;
4828bfffbccSCorey Minyard 
4838bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4848bfffbccSCorey Minyard         return;
4858bfffbccSCorey Minyard     }
4868bfffbccSCorey Minyard     if (bit >= 16) {
4878bfffbccSCorey Minyard         return;
4888bfffbccSCorey Minyard     }
4898bfffbccSCorey Minyard 
4908bfffbccSCorey Minyard     mask = (1 << bit);
4918bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
4928bfffbccSCorey Minyard     if (val) {
4938bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
4948bfffbccSCorey Minyard         if (sens->assert_states & mask) {
4958bfffbccSCorey Minyard             return; /* Already asserted */
4968bfffbccSCorey Minyard         }
4978bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
4988bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
4998bfffbccSCorey Minyard             /* Send an event on assert */
5008bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5018bfffbccSCorey Minyard         }
5028bfffbccSCorey Minyard     } else {
5038bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5048bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5058bfffbccSCorey Minyard             return; /* Already deasserted */
5068bfffbccSCorey Minyard         }
5078bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5088bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5098bfffbccSCorey Minyard             /* Send an event on deassert */
5108bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5118bfffbccSCorey Minyard         }
5128bfffbccSCorey Minyard     }
5138bfffbccSCorey Minyard }
5148bfffbccSCorey Minyard 
5158bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5168bfffbccSCorey Minyard {
5178bfffbccSCorey Minyard     unsigned int i, pos;
5188bfffbccSCorey Minyard     IPMISensor *sens;
5198bfffbccSCorey Minyard 
5208bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5218bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5228bfffbccSCorey Minyard     }
5238bfffbccSCorey Minyard 
5248bfffbccSCorey Minyard     pos = 0;
5258bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
526a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
527a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
528a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5298bfffbccSCorey Minyard 
5308bfffbccSCorey Minyard         if (len < 20) {
5318bfffbccSCorey Minyard             continue;
5328bfffbccSCorey Minyard         }
533a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5348bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5358bfffbccSCorey Minyard         }
5368bfffbccSCorey Minyard 
537*73d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5388bfffbccSCorey Minyard             continue;
5398bfffbccSCorey Minyard         }
540a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5418bfffbccSCorey Minyard 
5428bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
543a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
544a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
545a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
546a2295f0aSCédric Le Goater         sens->deassert_suppt =
547a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
548a2295f0aSCédric Le Goater         sens->states_suppt =
549a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
550a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
551a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5528bfffbccSCorey Minyard 
5538bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5548bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5558bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5568bfffbccSCorey Minyard     }
5578bfffbccSCorey Minyard }
5588bfffbccSCorey Minyard 
5598bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5608bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5618bfffbccSCorey Minyard {
56293a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
5638bfffbccSCorey Minyard         return -1;
5648bfffbccSCorey Minyard     }
5658bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5668bfffbccSCorey Minyard     return 0;
5678bfffbccSCorey Minyard }
5688bfffbccSCorey Minyard 
5698bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
5708bfffbccSCorey Minyard {
5718bfffbccSCorey Minyard     int64_t next;
5728bfffbccSCorey Minyard     if (ibs->watchdog_running) {
5738bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
5748bfffbccSCorey Minyard     } else {
5758bfffbccSCorey Minyard         /* Wait a minute */
5768bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
5778bfffbccSCorey Minyard     }
5788bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
5798bfffbccSCorey Minyard }
5808bfffbccSCorey Minyard 
5818bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
5828bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
5838bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
5848bfffbccSCorey Minyard                                     uint8_t msg_id)
5858bfffbccSCorey Minyard {
5868bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
5878bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
5888bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
5898bfffbccSCorey Minyard     unsigned int netfn;
5908bfffbccSCorey Minyard     uint8_t rsp[MAX_IPMI_MSG_SIZE];
5918bfffbccSCorey Minyard     unsigned int rsp_len_holder = 0;
5928bfffbccSCorey Minyard     unsigned int *rsp_len = &rsp_len_holder;
5938bfffbccSCorey Minyard     unsigned int max_rsp_len = sizeof(rsp);
5948bfffbccSCorey Minyard 
5958bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
5968bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
597d13ada5dSCédric Le Goater     if (max_rsp_len < 3) {
598d13ada5dSCédric Le Goater         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
599d13ada5dSCédric Le Goater         goto out;
600d13ada5dSCédric Le Goater     }
601d13ada5dSCédric Le Goater 
6028bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[0] | 0x04);
6038bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[1]);
6048bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0); /* Assume success */
6058bfffbccSCorey Minyard 
6068bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6078bfffbccSCorey Minyard     if (cmd_len < 2) {
6088bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID;
6098bfffbccSCorey Minyard         goto out;
6108bfffbccSCorey Minyard     }
6118bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6128bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED;
6138bfffbccSCorey Minyard         goto out;
6148bfffbccSCorey Minyard     }
6158bfffbccSCorey Minyard 
6168bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6178bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6188bfffbccSCorey Minyard         rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN;
6198bfffbccSCorey Minyard         goto out;
6208bfffbccSCorey Minyard     }
6218bfffbccSCorey Minyard 
6228bfffbccSCorey Minyard     netfn = cmd[0] >> 2;
6238bfffbccSCorey Minyard 
6248bfffbccSCorey Minyard     /* Odd netfns are not valid, make sure the command is registered */
6258bfffbccSCorey Minyard     if ((netfn & 1) || !ibs->netfns[netfn / 2] ||
6268bfffbccSCorey Minyard                         (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) ||
6278bfffbccSCorey Minyard                         (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) {
6288bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_CMD;
6298bfffbccSCorey Minyard         goto out;
6308bfffbccSCorey Minyard     }
6318bfffbccSCorey Minyard 
6328bfffbccSCorey Minyard     ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len,
6338bfffbccSCorey Minyard                                                 max_rsp_len);
6348bfffbccSCorey Minyard 
6358bfffbccSCorey Minyard  out:
6368bfffbccSCorey Minyard     k->handle_rsp(s, msg_id, rsp, *rsp_len);
6378bfffbccSCorey Minyard 
6388bfffbccSCorey Minyard     next_timeout(ibs);
6398bfffbccSCorey Minyard }
6408bfffbccSCorey Minyard 
6418bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6428bfffbccSCorey Minyard {
6438bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6448bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6458bfffbccSCorey Minyard 
6468bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6478bfffbccSCorey Minyard         goto out;
6488bfffbccSCorey Minyard     }
6498bfffbccSCorey Minyard 
6508bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6518bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6528bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6538bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6548bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6558bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6568bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6578bfffbccSCorey Minyard             break;
6588bfffbccSCorey Minyard 
6598bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6608bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6618bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6628bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6638bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6648bfffbccSCorey Minyard             break;
6658bfffbccSCorey Minyard 
6668bfffbccSCorey Minyard         default:
6678bfffbccSCorey Minyard             goto do_full_expiry;
6688bfffbccSCorey Minyard         }
6698bfffbccSCorey Minyard 
6708bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
6718bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
6728bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
6738bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
6748bfffbccSCorey Minyard         goto out;
6758bfffbccSCorey Minyard     }
6768bfffbccSCorey Minyard 
6778bfffbccSCorey Minyard  do_full_expiry:
6788bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
6798bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
6808bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
6818bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
6828bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
6838bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
6848bfffbccSCorey Minyard         break;
6858bfffbccSCorey Minyard 
6868bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
6878bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
6888bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
6898bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
6908bfffbccSCorey Minyard         break;
6918bfffbccSCorey Minyard 
6928bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
6938bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
6948bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
6958bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
6968bfffbccSCorey Minyard         break;
6978bfffbccSCorey Minyard 
6988bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
6998bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7008bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7018bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7028bfffbccSCorey Minyard         break;
7038bfffbccSCorey Minyard     }
7048bfffbccSCorey Minyard 
7058bfffbccSCorey Minyard  out:
7068bfffbccSCorey Minyard     next_timeout(ibs);
7078bfffbccSCorey Minyard }
7088bfffbccSCorey Minyard 
7098bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7108bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
7118bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
7128bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
7138bfffbccSCorey Minyard {
7148bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7158bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7168bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7178bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7188bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->parent.slave_addr);
7198bfffbccSCorey Minyard }
7208bfffbccSCorey Minyard 
7218bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7228bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
7238bfffbccSCorey Minyard                            uint8_t *rsp, unsigned int *rsp_len,
7248bfffbccSCorey Minyard                            unsigned int max_rsp_len)
7258bfffbccSCorey Minyard {
7268bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */
7278bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7288bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7298bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0);
7308bfffbccSCorey Minyard }
7318bfffbccSCorey Minyard 
7328bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7338bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
7348bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
7358bfffbccSCorey Minyard                             unsigned int max_rsp_len)
7368bfffbccSCorey Minyard {
7378bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7388bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7398bfffbccSCorey Minyard 
7408bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
7418bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7428bfffbccSCorey Minyard     case 0: /* power down */
7438bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7448bfffbccSCorey Minyard         break;
7458bfffbccSCorey Minyard     case 1: /* power up */
7468bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0);
7478bfffbccSCorey Minyard         break;
7488bfffbccSCorey Minyard     case 2: /* power cycle */
7498bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7508bfffbccSCorey Minyard         break;
7518bfffbccSCorey Minyard     case 3: /* hard reset */
7528bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7538bfffbccSCorey Minyard         break;
7548bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
7558bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0);
7568bfffbccSCorey Minyard         break;
7578bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
7588bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s,
7598bfffbccSCorey Minyard                              IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0);
7608bfffbccSCorey Minyard         break;
7618bfffbccSCorey Minyard     default:
7628bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
7638bfffbccSCorey Minyard         return;
7648bfffbccSCorey Minyard     }
765d13ada5dSCédric Le Goater }
7668bfffbccSCorey Minyard 
767b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
768b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
769b7088392SCédric Le Goater                            uint8_t *rsp, unsigned int *rsp_len,
770b7088392SCédric Le Goater                            unsigned int max_rsp_len)
771b7088392SCédric Le Goater {
772b7088392SCédric Le Goater     IPMI_ADD_RSP_DATA(ibs->restart_cause & 0xf); /* Restart Cause */
773b7088392SCédric Le Goater     IPMI_ADD_RSP_DATA(0);  /* Channel 0 */
774b7088392SCédric Le Goater }
775b7088392SCédric Le Goater 
7768bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
7778bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
7788bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
7798bfffbccSCorey Minyard                           unsigned int max_rsp_len)
7808bfffbccSCorey Minyard {
7818bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_id);
7828bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf);
7838bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f);
7848bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->fwrev2);
7858bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->ipmi_version);
7868bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */
7878bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[0]);
7888bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[1]);
7898bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->mfg_id[2]);
7908bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[0]);
7918bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->product_id[1]);
7928bfffbccSCorey Minyard }
7938bfffbccSCorey Minyard 
7948bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
7958bfffbccSCorey Minyard {
7968bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7978bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7988bfffbccSCorey Minyard     bool irqs_on;
7998bfffbccSCorey Minyard 
8008bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8018bfffbccSCorey Minyard 
8028bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8038bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8048bfffbccSCorey Minyard 
8058bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8068bfffbccSCorey Minyard }
8078bfffbccSCorey Minyard 
8088bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8098bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
8108bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
8118bfffbccSCorey Minyard                        unsigned int max_rsp_len)
8128bfffbccSCorey Minyard {
8138bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8148bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8158bfffbccSCorey Minyard 
8168bfffbccSCorey Minyard     /* Disable all interrupts */
8178bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8188bfffbccSCorey Minyard 
8198bfffbccSCorey Minyard     if (k->reset) {
8208bfffbccSCorey Minyard         k->reset(s, true);
8218bfffbccSCorey Minyard     }
8228bfffbccSCorey Minyard }
8238bfffbccSCorey Minyard 
8248bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8258bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
8268bfffbccSCorey Minyard                        uint8_t *rsp, unsigned int *rsp_len,
8278bfffbccSCorey Minyard                        unsigned int max_rsp_len)
8288bfffbccSCorey Minyard {
8298bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8308bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8318bfffbccSCorey Minyard 
8328bfffbccSCorey Minyard     if (k->reset) {
8338bfffbccSCorey Minyard         k->reset(s, false);
8348bfffbccSCorey Minyard     }
8358bfffbccSCorey Minyard }
83652ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
83752ba4d50SCédric Le Goater                           uint8_t *cmd, unsigned int cmd_len,
83852ba4d50SCédric Le Goater                           uint8_t *rsp, unsigned int *rsp_len,
83952ba4d50SCédric Le Goater                           unsigned int max_rsp_len)
84052ba4d50SCédric Le Goater {
84152ba4d50SCédric Le Goater     IPMI_CHECK_CMD_LEN(4);
84252ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
84352ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
84452ba4d50SCédric Le Goater }
84552ba4d50SCédric Le Goater 
84652ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
84752ba4d50SCédric Le Goater                           uint8_t *cmd, unsigned int cmd_len,
84852ba4d50SCédric Le Goater                           uint8_t *rsp, unsigned int *rsp_len,
84952ba4d50SCédric Le Goater                           unsigned int max_rsp_len)
85052ba4d50SCédric Le Goater {
85152ba4d50SCédric Le Goater     IPMI_ADD_RSP_DATA(ibs->acpi_power_state[0]);
85252ba4d50SCédric Le Goater     IPMI_ADD_RSP_DATA(ibs->acpi_power_state[1]);
85352ba4d50SCédric Le Goater }
85452ba4d50SCédric Le Goater 
85552ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
85652ba4d50SCédric Le Goater                           uint8_t *cmd, unsigned int cmd_len,
85752ba4d50SCédric Le Goater                           uint8_t *rsp, unsigned int *rsp_len,
85852ba4d50SCédric Le Goater                           unsigned int max_rsp_len)
85952ba4d50SCédric Le Goater {
86052ba4d50SCédric Le Goater     unsigned int i;
86152ba4d50SCédric Le Goater 
86252ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
86352ba4d50SCédric Le Goater         IPMI_ADD_RSP_DATA(ibs->uuid[i]);
86452ba4d50SCédric Le Goater     }
86552ba4d50SCédric Le Goater }
8668bfffbccSCorey Minyard 
8678bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
8688bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8698bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8708bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8718bfffbccSCorey Minyard {
8728bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8738bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8748bfffbccSCorey Minyard }
8758bfffbccSCorey Minyard 
8768bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8778bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
8788bfffbccSCorey Minyard                                    uint8_t *rsp, unsigned int *rsp_len,
8798bfffbccSCorey Minyard                                    unsigned int max_rsp_len)
8808bfffbccSCorey Minyard {
8818bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->bmc_global_enables);
8828bfffbccSCorey Minyard }
8838bfffbccSCorey Minyard 
8848bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
8858bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8868bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
8878bfffbccSCorey Minyard                           unsigned int max_rsp_len)
8888bfffbccSCorey Minyard {
8898bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8908bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8918bfffbccSCorey Minyard 
8928bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
8938bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
8948bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
8958bfffbccSCorey Minyard }
8968bfffbccSCorey Minyard 
8978bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
8988bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
8998bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
9008bfffbccSCorey Minyard                           unsigned int max_rsp_len)
9018bfffbccSCorey Minyard {
9028bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->msg_flags);
9038bfffbccSCorey Minyard }
9048bfffbccSCorey Minyard 
9058bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9068bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
9078bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
9088bfffbccSCorey Minyard                             unsigned int max_rsp_len)
9098bfffbccSCorey Minyard {
9108bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9118bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9128bfffbccSCorey Minyard     unsigned int i;
9138bfffbccSCorey Minyard 
9148bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9158bfffbccSCorey Minyard         rsp[2] = 0x80;
916d13ada5dSCédric Le Goater         return;
9178bfffbccSCorey Minyard     }
9188bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
9198bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->evtbuf[i]);
9208bfffbccSCorey Minyard     }
9218bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9228bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9238bfffbccSCorey Minyard }
9248bfffbccSCorey Minyard 
9258bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9268bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
9278bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
9288bfffbccSCorey Minyard                     unsigned int max_rsp_len)
9298bfffbccSCorey Minyard {
9308bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9318bfffbccSCorey Minyard 
9328bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
9338bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9348bfffbccSCorey Minyard         rsp[2] = 0x80; /* Queue empty */
9358bfffbccSCorey Minyard         goto out;
9368bfffbccSCorey Minyard     }
9378bfffbccSCorey Minyard     rsp[3] = 0; /* Channel 0 */
9388bfffbccSCorey Minyard     *rsp_len += 1;
9398bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
9408bfffbccSCorey Minyard     memcpy(rsp + 4, msg->buf, msg->len);
9418bfffbccSCorey Minyard     *rsp_len += msg->len;
9428bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9438bfffbccSCorey Minyard     g_free(msg);
9448bfffbccSCorey Minyard 
9458bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9468bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
9478bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9488bfffbccSCorey Minyard 
9498bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9508bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9518bfffbccSCorey Minyard     }
9528bfffbccSCorey Minyard 
9538bfffbccSCorey Minyard out:
9548bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
9558bfffbccSCorey Minyard     return;
9568bfffbccSCorey Minyard }
9578bfffbccSCorey Minyard 
9588bfffbccSCorey Minyard static unsigned char
9598bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9608bfffbccSCorey Minyard {
9618bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9628bfffbccSCorey Minyard             csum += *data;
9638bfffbccSCorey Minyard     }
9648bfffbccSCorey Minyard 
9658bfffbccSCorey Minyard     return -csum;
9668bfffbccSCorey Minyard }
9678bfffbccSCorey Minyard 
9688bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9698bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
9708bfffbccSCorey Minyard                      uint8_t *rsp, unsigned int *rsp_len,
9718bfffbccSCorey Minyard                      unsigned int max_rsp_len)
9728bfffbccSCorey Minyard {
9738bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9748bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9758bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9768bfffbccSCorey Minyard     uint8_t *buf;
9778bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9788bfffbccSCorey Minyard 
9798bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
9808bfffbccSCorey Minyard 
9818bfffbccSCorey Minyard     if (cmd[2] != 0) {
9828bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
9838bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
984d13ada5dSCédric Le Goater         return;
9858bfffbccSCorey Minyard     }
9868bfffbccSCorey Minyard 
9878bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(10);
9888bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9898bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
9908bfffbccSCorey Minyard         rsp[2] = 0x83; /* NAK on write */
991d13ada5dSCédric Le Goater         return;
9928bfffbccSCorey Minyard     }
9938bfffbccSCorey Minyard 
9948bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
9958bfffbccSCorey Minyard     cmd_len -= 3;
9968bfffbccSCorey Minyard 
9978bfffbccSCorey Minyard     /*
9988bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
9998bfffbccSCorey Minyard      * be returned in the response.
10008bfffbccSCorey Minyard      */
10018bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10028bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1003d13ada5dSCédric Le Goater         return; /* No response */
10048bfffbccSCorey Minyard     }
10058bfffbccSCorey Minyard 
10068bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10078bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10088bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10098bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10108bfffbccSCorey Minyard 
10118bfffbccSCorey Minyard     if (rqLun != 2) {
10128bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1013d13ada5dSCédric Le Goater         return;
10148bfffbccSCorey Minyard     }
10158bfffbccSCorey Minyard 
10168bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10178bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10188bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10198bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10208bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10218bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10228bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10238bfffbccSCorey Minyard     msg->len = 6;
10248bfffbccSCorey Minyard 
10258bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10268bfffbccSCorey Minyard         /* Not a command we handle. */
10278bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10288bfffbccSCorey Minyard         goto end_msg;
10298bfffbccSCorey Minyard     }
10308bfffbccSCorey Minyard 
10318bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10328bfffbccSCorey Minyard     buf[0] = 0;
10338bfffbccSCorey Minyard     buf[1] = 0;
10348bfffbccSCorey Minyard     buf[2] = 0;
10358bfffbccSCorey Minyard     buf[3] = 0;
10368bfffbccSCorey Minyard     buf[4] = 0x51;
10378bfffbccSCorey Minyard     buf[5] = 0;
10388bfffbccSCorey Minyard     buf[6] = 0;
10398bfffbccSCorey Minyard     buf[7] = 0;
10408bfffbccSCorey Minyard     buf[8] = 0;
10418bfffbccSCorey Minyard     buf[9] = 0;
10428bfffbccSCorey Minyard     buf[10] = 0;
10438bfffbccSCorey Minyard     msg->len += 11;
10448bfffbccSCorey Minyard 
10458bfffbccSCorey Minyard  end_msg:
10468bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10478bfffbccSCorey Minyard     msg->len++;
10488bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
10498bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10508bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10518bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10528bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
10538bfffbccSCorey Minyard }
10548bfffbccSCorey Minyard 
10558bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
10568bfffbccSCorey Minyard {
10578bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
10588bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
10598bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10608bfffbccSCorey Minyard         return;
10618bfffbccSCorey Minyard     }
10628bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10638bfffbccSCorey Minyard 
10648bfffbccSCorey Minyard 
10658bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10668bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10678bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10688bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10698bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10708bfffbccSCorey Minyard     }
10718bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10728bfffbccSCorey Minyard }
10738bfffbccSCorey Minyard 
10748bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10758bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
10768bfffbccSCorey Minyard                                  uint8_t *rsp, unsigned int *rsp_len,
10778bfffbccSCorey Minyard                                  unsigned int max_rsp_len)
10788bfffbccSCorey Minyard {
10798bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
10808bfffbccSCorey Minyard         rsp[2] = 0x80;
1081d13ada5dSCédric Le Goater         return;
10828bfffbccSCorey Minyard     }
10838bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10848bfffbccSCorey Minyard }
10858bfffbccSCorey Minyard 
10868bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10878bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
10888bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
10898bfffbccSCorey Minyard                                unsigned int max_rsp_len)
10908bfffbccSCorey Minyard {
10918bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10928bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10938bfffbccSCorey Minyard     unsigned int val;
10948bfffbccSCorey Minyard 
10958bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
10968bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
10978bfffbccSCorey Minyard     if (val == 0 || val > 5) {
10988bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1099d13ada5dSCédric Le Goater         return;
11008bfffbccSCorey Minyard     }
11018bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11028bfffbccSCorey Minyard     switch (val) {
11038bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11048bfffbccSCorey Minyard         break;
11058bfffbccSCorey Minyard 
11068bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11078bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1);
11088bfffbccSCorey Minyard         break;
11098bfffbccSCorey Minyard 
11108bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11118bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1);
11128bfffbccSCorey Minyard         break;
11138bfffbccSCorey Minyard 
11148bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11158bfffbccSCorey Minyard         rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1);
11168bfffbccSCorey Minyard         break;
11178bfffbccSCorey Minyard 
11188bfffbccSCorey Minyard     default:
11198bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
11208bfffbccSCorey Minyard     }
11218bfffbccSCorey Minyard     if (rsp[2]) {
11228bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1123d13ada5dSCédric Le Goater         return;
11248bfffbccSCorey Minyard     }
11258bfffbccSCorey Minyard 
11268bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11278bfffbccSCorey Minyard     switch (val) {
11288bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11298bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11308bfffbccSCorey Minyard         break;
11318bfffbccSCorey Minyard 
11328bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11338bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11348bfffbccSCorey Minyard             /* NMI not supported. */
11358bfffbccSCorey Minyard             rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1136d13ada5dSCédric Le Goater             return;
11378bfffbccSCorey Minyard         }
113837eebb86SCorey Minyard         break;
113937eebb86SCorey Minyard 
11408bfffbccSCorey Minyard     default:
11418bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11428bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1143d13ada5dSCédric Le Goater         return;
11448bfffbccSCorey Minyard     }
11458bfffbccSCorey Minyard 
11468bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11478bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11488bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11498bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11508bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11518bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11528bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11538bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11548bfffbccSCorey Minyard     } else {
11558bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11568bfffbccSCorey Minyard     }
11578bfffbccSCorey Minyard }
11588bfffbccSCorey Minyard 
11598bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
11608bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
11618bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
11628bfffbccSCorey Minyard                                unsigned int max_rsp_len)
11638bfffbccSCorey Minyard {
11648bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_use);
11658bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_action);
11668bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout);
11678bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->watchdog_expired);
11688bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11698bfffbccSCorey Minyard         long timeout;
11708bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11718bfffbccSCorey Minyard                    / 100000000);
11728bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(timeout & 0xff);
11738bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff);
11748bfffbccSCorey Minyard     } else {
11758bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11768bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0);
11778bfffbccSCorey Minyard     }
11788bfffbccSCorey Minyard }
11798bfffbccSCorey Minyard 
11808bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11818bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
11828bfffbccSCorey Minyard                              uint8_t *rsp, unsigned int *rsp_len,
11838bfffbccSCorey Minyard                              unsigned int max_rsp_len)
11848bfffbccSCorey Minyard {
11858bfffbccSCorey Minyard     unsigned int i;
11868bfffbccSCorey Minyard 
11878bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */
11888bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff);
11898bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff);
11908bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
11918bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11928bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11938bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]);
11948bfffbccSCorey Minyard     }
11958bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
11968bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]);
11978bfffbccSCorey Minyard     }
11988bfffbccSCorey Minyard     /* Only modal support, reserve supported */
11998bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22);
12008bfffbccSCorey Minyard }
12018bfffbccSCorey Minyard 
12028bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12038bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
12048bfffbccSCorey Minyard                             uint8_t *rsp, unsigned int *rsp_len,
12058bfffbccSCorey Minyard                             unsigned int max_rsp_len)
12068bfffbccSCorey Minyard {
12078bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff);
12088bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff);
12098bfffbccSCorey Minyard }
12108bfffbccSCorey Minyard 
12118bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12128bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
12138bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
12148bfffbccSCorey Minyard                     unsigned int max_rsp_len)
12158bfffbccSCorey Minyard {
12168bfffbccSCorey Minyard     unsigned int pos;
12178bfffbccSCorey Minyard     uint16_t nextrec;
1218a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12198bfffbccSCorey Minyard 
12208bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12218bfffbccSCorey Minyard     if (cmd[6]) {
12228bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
12238bfffbccSCorey Minyard     }
12248bfffbccSCorey Minyard     pos = 0;
12258bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12268bfffbccSCorey Minyard                        &pos, &nextrec)) {
12278bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1228d13ada5dSCédric Le Goater         return;
12298bfffbccSCorey Minyard     }
1230a2295f0aSCédric Le Goater 
1231a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1232a2295f0aSCédric Le Goater 
1233a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
12348bfffbccSCorey Minyard         rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE;
1235d13ada5dSCédric Le Goater         return;
12368bfffbccSCorey Minyard     }
12378bfffbccSCorey Minyard 
12388bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(nextrec & 0xff);
12398bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff);
12408bfffbccSCorey Minyard 
12418bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1242a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12438bfffbccSCorey Minyard     }
12448bfffbccSCorey Minyard 
12458bfffbccSCorey Minyard     if ((cmd[7] + *rsp_len) > max_rsp_len) {
12468bfffbccSCorey Minyard         rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
1247d13ada5dSCédric Le Goater         return;
12488bfffbccSCorey Minyard     }
12498bfffbccSCorey Minyard     memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12508bfffbccSCorey Minyard     *rsp_len += cmd[7];
12518bfffbccSCorey Minyard }
12528bfffbccSCorey Minyard 
12538bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12548bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
12558bfffbccSCorey Minyard                     uint8_t *rsp, unsigned int *rsp_len,
12568bfffbccSCorey Minyard                     unsigned int max_rsp_len)
12578bfffbccSCorey Minyard {
12588bfffbccSCorey Minyard     uint16_t recid;
1259a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
12608bfffbccSCorey Minyard 
1261a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
12628bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1263d13ada5dSCédric Le Goater         return;
12648bfffbccSCorey Minyard     }
12658bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(recid & 0xff);
12668bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((recid >> 8) & 0xff);
12678bfffbccSCorey Minyard }
12688bfffbccSCorey Minyard 
12698bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12708bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
12718bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
12728bfffbccSCorey Minyard                           unsigned int max_rsp_len)
12738bfffbccSCorey Minyard {
12748bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
12758bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation);
12768bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
12778bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1278d13ada5dSCédric Le Goater         return;
12798bfffbccSCorey Minyard     }
12808bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12818bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12828bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12838bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
12848bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12858bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12868bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
12878bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
12888bfffbccSCorey Minyard     } else {
12898bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
12908bfffbccSCorey Minyard         return;
12918bfffbccSCorey Minyard     }
1292d13ada5dSCédric Le Goater }
12938bfffbccSCorey Minyard 
12948bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
12958bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
12968bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
12978bfffbccSCorey Minyard                          unsigned int max_rsp_len)
12988bfffbccSCorey Minyard {
12998bfffbccSCorey Minyard     unsigned int i, val;
13008bfffbccSCorey Minyard 
13018bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */
13028bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff);
13038bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff);
13048bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
13058bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
13068bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
13078bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
13088bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]);
13098bfffbccSCorey Minyard     }
13108bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
13118bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]);
13128bfffbccSCorey Minyard     }
13138bfffbccSCorey Minyard     /* Only support Reserve SEL */
13148bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02);
13158bfffbccSCorey Minyard }
13168bfffbccSCorey Minyard 
13178bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
13188bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
13198bfffbccSCorey Minyard                         uint8_t *rsp, unsigned int *rsp_len,
13208bfffbccSCorey Minyard                         unsigned int max_rsp_len)
13218bfffbccSCorey Minyard {
13228bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff);
13238bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff);
13248bfffbccSCorey Minyard }
13258bfffbccSCorey Minyard 
13268bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
13278bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
13288bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
13298bfffbccSCorey Minyard                           unsigned int max_rsp_len)
13308bfffbccSCorey Minyard {
13318bfffbccSCorey Minyard     unsigned int val;
13328bfffbccSCorey Minyard 
13338bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
13348bfffbccSCorey Minyard     if (cmd[6]) {
13358bfffbccSCorey Minyard         IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
13368bfffbccSCorey Minyard     }
13378bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
13388bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1339d13ada5dSCédric Le Goater         return;
13408bfffbccSCorey Minyard     }
13418bfffbccSCorey Minyard     if (cmd[6] > 15) {
13428bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1343d13ada5dSCédric Le Goater         return;
13448bfffbccSCorey Minyard     }
13458bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
13468bfffbccSCorey Minyard         cmd[7] = 16;
13478bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
13488bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1349d13ada5dSCédric Le Goater         return;
13508bfffbccSCorey Minyard     } else {
13518bfffbccSCorey Minyard         cmd[7] += cmd[6];
13528bfffbccSCorey Minyard     }
13538bfffbccSCorey Minyard 
13548bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
13558bfffbccSCorey Minyard     if (val == 0xffff) {
13568bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
13578bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
13588bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1359d13ada5dSCédric Le Goater         return;
13608bfffbccSCorey Minyard     }
13618bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
13628bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
13638bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(0xff);
13648bfffbccSCorey Minyard     } else {
13658bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((val + 1) & 0xff);
13668bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff);
13678bfffbccSCorey Minyard     }
13688bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
13698bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]);
13708bfffbccSCorey Minyard     }
13718bfffbccSCorey Minyard }
13728bfffbccSCorey Minyard 
13738bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13748bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
13758bfffbccSCorey Minyard                           uint8_t *rsp, unsigned int *rsp_len,
13768bfffbccSCorey Minyard                           unsigned int max_rsp_len)
13778bfffbccSCorey Minyard {
13788bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(18);
13798bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
13808bfffbccSCorey Minyard         rsp[2] = IPMI_CC_OUT_OF_SPACE;
1381d13ada5dSCédric Le Goater         return;
13828bfffbccSCorey Minyard     }
13838bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
13848bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[2]);
13858bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(cmd[3]);
13868bfffbccSCorey Minyard }
13878bfffbccSCorey Minyard 
13888bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13898bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
13908bfffbccSCorey Minyard                       uint8_t *rsp, unsigned int *rsp_len,
13918bfffbccSCorey Minyard                       unsigned int max_rsp_len)
13928bfffbccSCorey Minyard {
13938bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(8);
13948bfffbccSCorey Minyard     IPMI_CHECK_RESERVATION(2, ibs->sel.reservation);
13958bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13968bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1397d13ada5dSCédric Le Goater         return;
13988bfffbccSCorey Minyard     }
13998bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
14008bfffbccSCorey Minyard         ibs->sel.next_free = 0;
14018bfffbccSCorey Minyard         ibs->sel.overflow = 0;
14028bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
14038bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
14048bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
14058bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
14068bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA(1); /* Erasure complete */
14078bfffbccSCorey Minyard     } else {
14088bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
14098bfffbccSCorey Minyard         return;
14108bfffbccSCorey Minyard     }
1411d13ada5dSCédric Le Goater }
14128bfffbccSCorey Minyard 
14138bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
14148bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
14158bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
14168bfffbccSCorey Minyard                          unsigned int max_rsp_len)
14178bfffbccSCorey Minyard {
14188bfffbccSCorey Minyard     uint32_t val;
14198bfffbccSCorey Minyard     struct ipmi_time now;
14208bfffbccSCorey Minyard 
14218bfffbccSCorey Minyard     ipmi_gettime(&now);
14228bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
14238bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(val & 0xff);
14248bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 8) & 0xff);
14258bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 16) & 0xff);
14268bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((val >> 24) & 0xff);
14278bfffbccSCorey Minyard }
14288bfffbccSCorey Minyard 
14298bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
14308bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
14318bfffbccSCorey Minyard                          uint8_t *rsp, unsigned int *rsp_len,
14328bfffbccSCorey Minyard                          unsigned int max_rsp_len)
14338bfffbccSCorey Minyard {
14348bfffbccSCorey Minyard     uint32_t val;
14358bfffbccSCorey Minyard     struct ipmi_time now;
14368bfffbccSCorey Minyard 
14378bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(6);
14388bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
14398bfffbccSCorey Minyard     ipmi_gettime(&now);
14408bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
14418bfffbccSCorey Minyard }
14428bfffbccSCorey Minyard 
14438bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
14448bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14458bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14468bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14478bfffbccSCorey Minyard {
14488bfffbccSCorey Minyard     IPMISensor *sens;
14498bfffbccSCorey Minyard 
14508bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
1451*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
14528bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14538bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1454d13ada5dSCédric Le Goater         return;
14558bfffbccSCorey Minyard     }
14568bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14578bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
14588bfffbccSCorey Minyard     case 0: /* Do not change */
14598bfffbccSCorey Minyard         break;
14608bfffbccSCorey Minyard     case 1: /* Enable bits */
14618bfffbccSCorey Minyard         if (cmd_len > 4) {
14628bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
14638bfffbccSCorey Minyard         }
14648bfffbccSCorey Minyard         if (cmd_len > 5) {
14658bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
14668bfffbccSCorey Minyard         }
14678bfffbccSCorey Minyard         if (cmd_len > 6) {
14688bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
14698bfffbccSCorey Minyard         }
14708bfffbccSCorey Minyard         if (cmd_len > 7) {
14718bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
14728bfffbccSCorey Minyard         }
14738bfffbccSCorey Minyard         break;
14748bfffbccSCorey Minyard     case 2: /* Disable bits */
14758bfffbccSCorey Minyard         if (cmd_len > 4) {
14768bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14778bfffbccSCorey Minyard         }
14788bfffbccSCorey Minyard         if (cmd_len > 5) {
14798bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14808bfffbccSCorey Minyard         }
14818bfffbccSCorey Minyard         if (cmd_len > 6) {
14828bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14838bfffbccSCorey Minyard         }
14848bfffbccSCorey Minyard         if (cmd_len > 7) {
14858bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14868bfffbccSCorey Minyard         }
14878bfffbccSCorey Minyard         break;
14888bfffbccSCorey Minyard     case 3:
14898bfffbccSCorey Minyard         rsp[2] = IPMI_CC_INVALID_DATA_FIELD;
1490d13ada5dSCédric Le Goater         return;
14918bfffbccSCorey Minyard     }
14928bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14938bfffbccSCorey Minyard }
14948bfffbccSCorey Minyard 
14958bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14968bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
14978bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
14988bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
14998bfffbccSCorey Minyard {
15008bfffbccSCorey Minyard     IPMISensor *sens;
15018bfffbccSCorey Minyard 
15028bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
1503*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15048bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15058bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1506d13ada5dSCédric Le Goater         return;
15078bfffbccSCorey Minyard     }
15088bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15098bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15108bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff);
15118bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff);
15128bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff);
15138bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff);
15148bfffbccSCorey Minyard }
15158bfffbccSCorey Minyard 
15168bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
15178bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
15188bfffbccSCorey Minyard                               uint8_t *rsp, unsigned int *rsp_len,
15198bfffbccSCorey Minyard                               unsigned int max_rsp_len)
15208bfffbccSCorey Minyard {
15218bfffbccSCorey Minyard     IPMISensor *sens;
15228bfffbccSCorey Minyard 
15238bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(4);
1524*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15258bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15268bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1527d13ada5dSCédric Le Goater         return;
15288bfffbccSCorey Minyard     }
15298bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15308bfffbccSCorey Minyard 
15318bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
15328bfffbccSCorey Minyard         /* Just clear everything */
15338bfffbccSCorey Minyard         sens->states = 0;
15348bfffbccSCorey Minyard         return;
15358bfffbccSCorey Minyard     }
1536d13ada5dSCédric Le Goater }
15378bfffbccSCorey Minyard 
15388bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
15398bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
15408bfffbccSCorey Minyard                                   uint8_t *rsp, unsigned int *rsp_len,
15418bfffbccSCorey Minyard                                   unsigned int max_rsp_len)
15428bfffbccSCorey Minyard {
15438bfffbccSCorey Minyard     IPMISensor *sens;
15448bfffbccSCorey Minyard 
15458bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
1546*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15478bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15488bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1549d13ada5dSCédric Le Goater         return;
15508bfffbccSCorey Minyard     }
15518bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15528bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15538bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15548bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->assert_states & 0xff);
15558bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff);
15568bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff);
15578bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff);
15588bfffbccSCorey Minyard }
15598bfffbccSCorey Minyard 
15608bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
15618bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
15628bfffbccSCorey Minyard                                uint8_t *rsp, unsigned int *rsp_len,
15638bfffbccSCorey Minyard                                unsigned int max_rsp_len)
15648bfffbccSCorey Minyard {
15658bfffbccSCorey Minyard     IPMISensor *sens;
15668bfffbccSCorey Minyard 
15678bfffbccSCorey Minyard     IPMI_CHECK_CMD_LEN(3);
1568*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15698bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15708bfffbccSCorey Minyard         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1571d13ada5dSCédric Le Goater         return;
15728bfffbccSCorey Minyard     }
15738bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15748bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->reading);
15758bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens));
15768bfffbccSCorey Minyard     IPMI_ADD_RSP_DATA(sens->states & 0xff);
15778bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
15788bfffbccSCorey Minyard         IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff);
15798bfffbccSCorey Minyard     }
15808bfffbccSCorey Minyard }
15818bfffbccSCorey Minyard 
1582728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1583728710e1SCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1584728710e1SCédric Le Goater                                uint8_t *rsp, unsigned int *rsp_len,
1585728710e1SCédric Le Goater                                unsigned int max_rsp_len)
1586728710e1SCédric Le Goater {
1587728710e1SCédric Le Goater     IPMISensor *sens;
1588728710e1SCédric Le Goater 
1589728710e1SCédric Le Goater 
1590728710e1SCédric Le Goater     IPMI_CHECK_CMD_LEN(5);
1591*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1592728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1593728710e1SCédric Le Goater         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1594728710e1SCédric Le Goater         return;
1595728710e1SCédric Le Goater     }
1596728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1597728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1598728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1599728710e1SCédric Le Goater }
1600728710e1SCédric Le Goater 
1601728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1602728710e1SCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1603728710e1SCédric Le Goater                                uint8_t *rsp, unsigned int *rsp_len,
1604728710e1SCédric Le Goater                                unsigned int max_rsp_len)
1605728710e1SCédric Le Goater {
1606728710e1SCédric Le Goater     IPMISensor *sens;
1607728710e1SCédric Le Goater 
1608728710e1SCédric Le Goater 
1609728710e1SCédric Le Goater     IPMI_CHECK_CMD_LEN(3);
1610*73d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1611728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1612728710e1SCédric Le Goater         rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT;
1613728710e1SCédric Le Goater         return;
1614728710e1SCédric Le Goater     }
1615728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1616728710e1SCédric Le Goater     IPMI_ADD_RSP_DATA(sens->sensor_type);
1617728710e1SCédric Le Goater     IPMI_ADD_RSP_DATA(sens->evt_reading_type_code);
1618728710e1SCédric Le Goater }
1619728710e1SCédric Le Goater 
1620728710e1SCédric Le Goater 
162162a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
16228bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities,
16238bfffbccSCorey Minyard     [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status,
1624b7088392SCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = chassis_control,
1625b7088392SCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = chassis_get_sys_restart_cause
16268bfffbccSCorey Minyard };
16278bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
162862a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
16298bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
16308bfffbccSCorey Minyard };
16318bfffbccSCorey Minyard 
163262a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
16338bfffbccSCorey Minyard     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable,
16348bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable,
16358bfffbccSCorey Minyard     [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts,
16368bfffbccSCorey Minyard     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status,
1637728710e1SCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading,
1638728710e1SCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = set_sensor_type,
1639728710e1SCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = get_sensor_type,
16408bfffbccSCorey Minyard };
16418bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
164262a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
16438bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
16448bfffbccSCorey Minyard };
16458bfffbccSCorey Minyard 
164662a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
16478bfffbccSCorey Minyard     [IPMI_CMD_GET_DEVICE_ID] = get_device_id,
16488bfffbccSCorey Minyard     [IPMI_CMD_COLD_RESET] = cold_reset,
16498bfffbccSCorey Minyard     [IPMI_CMD_WARM_RESET] = warm_reset,
165052ba4d50SCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = set_acpi_power_state,
165152ba4d50SCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = get_acpi_power_state,
165252ba4d50SCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = get_device_guid,
16538bfffbccSCorey Minyard     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables,
16548bfffbccSCorey Minyard     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables,
16558bfffbccSCorey Minyard     [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags,
16568bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags,
16578bfffbccSCorey Minyard     [IPMI_CMD_GET_MSG] = get_msg,
16588bfffbccSCorey Minyard     [IPMI_CMD_SEND_MSG] = send_msg,
16598bfffbccSCorey Minyard     [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf,
16608bfffbccSCorey Minyard     [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer,
16618bfffbccSCorey Minyard     [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer,
16628bfffbccSCorey Minyard     [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer,
16638bfffbccSCorey Minyard };
16648bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
166562a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
16668bfffbccSCorey Minyard     .cmd_handlers = app_cmds
16678bfffbccSCorey Minyard };
16688bfffbccSCorey Minyard 
166962a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
16708bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info,
16718bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep,
16728bfffbccSCorey Minyard     [IPMI_CMD_GET_SDR] = get_sdr,
16738bfffbccSCorey Minyard     [IPMI_CMD_ADD_SDR] = add_sdr,
16748bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep,
16758bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_INFO] = get_sel_info,
16768bfffbccSCorey Minyard     [IPMI_CMD_RESERVE_SEL] = reserve_sel,
16778bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry,
16788bfffbccSCorey Minyard     [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry,
16798bfffbccSCorey Minyard     [IPMI_CMD_CLEAR_SEL] = clear_sel,
16808bfffbccSCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = get_sel_time,
16818bfffbccSCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = set_sel_time,
16828bfffbccSCorey Minyard };
16838bfffbccSCorey Minyard 
16848bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
168562a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
16868bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
16878bfffbccSCorey Minyard };
16888bfffbccSCorey Minyard 
16898bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
16908bfffbccSCorey Minyard {
16918bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
16928bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
16938bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
16948bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
16958bfffbccSCorey Minyard }
16968bfffbccSCorey Minyard 
16978bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
16988bfffbccSCorey Minyard     /* Watchdog device */
16998bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
17008bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
17018bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17028bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
17038bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
17048bfffbccSCorey Minyard     /* End */
17058bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
17068bfffbccSCorey Minyard };
17078bfffbccSCorey Minyard 
1708bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1709bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1710bd66bcfcSCorey Minyard     .version_id = 1,
1711bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1712bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1713bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1714bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1715bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1716bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1717bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1718bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1719bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1720bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1721bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1722bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1723bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1724bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1725bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1726bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1727bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1728bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1729bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1730bd66bcfcSCorey Minyard                        IPMIBmcSim),
1731bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1732bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1733bd66bcfcSCorey Minyard     }
1734bd66bcfcSCorey Minyard };
1735bd66bcfcSCorey Minyard 
17368bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj)
17378bfffbccSCorey Minyard {
17388bfffbccSCorey Minyard     IPMIBmc *b = IPMI_BMC(obj);
17398bfffbccSCorey Minyard     unsigned int i;
17408bfffbccSCorey Minyard     unsigned int recid;
17418bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
17428bfffbccSCorey Minyard 
17438bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
17448bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
17458bfffbccSCorey Minyard 
17468bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
17478bfffbccSCorey Minyard     ibs->device_id = 0x20;
17488bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1749b7088392SCédric Le Goater     ibs->restart_cause = 0;
17508bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
17518bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
17528bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
17538bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
17548bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
17558bfffbccSCorey Minyard     }
17568bfffbccSCorey Minyard 
17578bfffbccSCorey Minyard     for (i = 0;;) {
1758a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh;
17598bfffbccSCorey Minyard         int len;
1760a2295f0aSCédric Le Goater         if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) {
17617cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
17628bfffbccSCorey Minyard             return;
17638bfffbccSCorey Minyard         }
1764a2295f0aSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &init_sdrs[i];
1765a2295f0aSCédric Le Goater         len = ipmi_sdr_length(sdrh);
1766a2295f0aSCédric Le Goater         recid = ipmi_sdr_recid(sdrh);
17678bfffbccSCorey Minyard         if (recid == 0xffff) {
17688bfffbccSCorey Minyard             break;
17698bfffbccSCorey Minyard         }
1770792afddbSCédric Le Goater         if ((i + len) > sizeof(init_sdrs)) {
17717cfa06a2SCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
17728bfffbccSCorey Minyard             return;
17738bfffbccSCorey Minyard         }
1774a2295f0aSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
1775792afddbSCédric Le Goater         i += len;
17768bfffbccSCorey Minyard     }
17778bfffbccSCorey Minyard 
177852ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
177952ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
178052ba4d50SCédric Le Goater 
178152ba4d50SCédric Le Goater     if (qemu_uuid_set) {
178252ba4d50SCédric Le Goater         memcpy(&ibs->uuid, qemu_uuid, 16);
178352ba4d50SCédric Le Goater     } else {
178452ba4d50SCédric Le Goater         memset(&ibs->uuid, 0, 16);
178552ba4d50SCédric Le Goater     }
178652ba4d50SCédric Le Goater 
17878bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
17888bfffbccSCorey Minyard     register_cmds(ibs);
17898bfffbccSCorey Minyard 
17908bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1791bd66bcfcSCorey Minyard 
1792bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
17938bfffbccSCorey Minyard }
17948bfffbccSCorey Minyard 
17958bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
17968bfffbccSCorey Minyard {
17978bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
17988bfffbccSCorey Minyard 
17998bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
18008bfffbccSCorey Minyard }
18018bfffbccSCorey Minyard 
18028bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
18038bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
18048bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
18058bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
18068bfffbccSCorey Minyard     .instance_init = ipmi_sim_init,
18078bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
18088bfffbccSCorey Minyard };
18098bfffbccSCorey Minyard 
18108bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
18118bfffbccSCorey Minyard {
18128bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
18138bfffbccSCorey Minyard }
18148bfffbccSCorey Minyard 
18158bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1816