xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 4fa9f08e968db4d40fe6faf3ebd1adfdfb816a16)
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;
156a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer;
1578bfffbccSCorey Minyard 
1588bfffbccSCorey Minyard #define MAX_NETFNS 64
1594f298a4bSCédric Le Goater 
1604f298a4bSCédric Le Goater typedef struct IPMICmdHandler {
1614f298a4bSCédric Le Goater     void (*cmd_handler)(IPMIBmcSim *s,
1628bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
163a580d820SCédric Le Goater                         RspBuffer *rsp);
1644f298a4bSCédric Le Goater     unsigned int cmd_len_min;
1654f298a4bSCédric Le Goater } IPMICmdHandler;
1664f298a4bSCédric Le Goater 
1678bfffbccSCorey Minyard typedef struct IPMINetfn {
1688bfffbccSCorey Minyard     unsigned int cmd_nums;
1698bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1708bfffbccSCorey Minyard } IPMINetfn;
1718bfffbccSCorey Minyard 
1728bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1738bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1748bfffbccSCorey Minyard     uint8_t len;
1758bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1768bfffbccSCorey Minyard } IPMIRcvBufEntry;
1778bfffbccSCorey Minyard 
1788bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1798bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1808bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1818bfffbccSCorey Minyard struct IPMIBmcSim {
1828bfffbccSCorey Minyard     IPMIBmc parent;
1838bfffbccSCorey Minyard 
1848bfffbccSCorey Minyard     QEMUTimer *timer;
1858bfffbccSCorey Minyard 
1868bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1878bfffbccSCorey Minyard     uint8_t msg_flags;
1888bfffbccSCorey Minyard 
1898bfffbccSCorey Minyard     bool     watchdog_initialized;
1908bfffbccSCorey Minyard     uint8_t  watchdog_use;
1918bfffbccSCorey Minyard     uint8_t  watchdog_action;
1928bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1938bfffbccSCorey Minyard     bool     watchdog_expired;
1948bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1958bfffbccSCorey Minyard 
1968bfffbccSCorey Minyard     bool     watchdog_running;
1978bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1988bfffbccSCorey Minyard     int64_t  watchdog_expiry;
1998bfffbccSCorey Minyard 
2008bfffbccSCorey Minyard     uint8_t device_id;
2018bfffbccSCorey Minyard     uint8_t ipmi_version;
2028bfffbccSCorey Minyard     uint8_t device_rev;
2038bfffbccSCorey Minyard     uint8_t fwrev1;
2048bfffbccSCorey Minyard     uint8_t fwrev2;
2058bfffbccSCorey Minyard     uint8_t mfg_id[3];
2068bfffbccSCorey Minyard     uint8_t product_id[2];
2078bfffbccSCorey Minyard 
208b7088392SCédric Le Goater     uint8_t restart_cause;
209b7088392SCédric Le Goater 
21052ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
21152ba4d50SCédric Le Goater     uint8_t uuid[16];
21252ba4d50SCédric Le Goater 
2138bfffbccSCorey Minyard     IPMISel sel;
2148bfffbccSCorey Minyard     IPMISdr sdr;
2158bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
2168bfffbccSCorey Minyard 
2178bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2188bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2198bfffbccSCorey Minyard 
2208bfffbccSCorey Minyard     QemuMutex lock;
2218bfffbccSCorey Minyard     /* We allow one event in the buffer */
2228bfffbccSCorey Minyard     uint8_t evtbuf[16];
2238bfffbccSCorey Minyard 
2248bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2258bfffbccSCorey Minyard };
2268bfffbccSCorey Minyard 
2278bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2318bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2328bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2338bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2348bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2358bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2368bfffbccSCorey Minyard 
2378bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2388bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2398bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2428bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2438bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2448bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2458bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2468bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2478bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2488bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2498bfffbccSCorey Minyard 
2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2658bfffbccSCorey Minyard 
266a580d820SCédric Le Goater struct RspBuffer {
267a580d820SCédric Le Goater     uint8_t buffer[MAX_IPMI_MSG_SIZE];
268a580d820SCédric Le Goater     unsigned int len;
269a580d820SCédric Le Goater };
270a580d820SCédric Le Goater 
271a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2728bfffbccSCorey Minyard 
2736acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
2746acb971aSCédric Le Goater {
2756acb971aSCédric Le Goater     rsp->buffer[2] = byte;
2766acb971aSCédric Le Goater }
2776acb971aSCédric Le Goater 
2788bfffbccSCorey Minyard /* Add a byte to the response. */
279a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
280a580d820SCédric Le Goater {
281a580d820SCédric Le Goater     if (rsp->len >= sizeof(rsp->buffer)) {
2826acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
283a580d820SCédric Le Goater         return;
284a580d820SCédric Le Goater     }
285a580d820SCédric Le Goater     rsp->buffer[rsp->len++] = byte;
286a580d820SCédric Le Goater }
287a580d820SCédric Le Goater 
288a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
289a580d820SCédric Le Goater                                        unsigned int n)
290a580d820SCédric Le Goater {
291a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
2926acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
293a580d820SCédric Le Goater         return;
294a580d820SCédric Le Goater     }
295a580d820SCédric Le Goater 
296a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
297a580d820SCédric Le Goater     rsp->len += n;
298a580d820SCédric Le Goater }
2998bfffbccSCorey Minyard 
3008bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
3018bfffbccSCorey Minyard 
3028bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
3038bfffbccSCorey Minyard {
3048bfffbccSCorey Minyard     int64_t stime;
3058bfffbccSCorey Minyard 
3068bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
3078bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
3088bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
3098bfffbccSCorey Minyard }
3108bfffbccSCorey Minyard 
3118bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3128bfffbccSCorey Minyard {
3138bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3148bfffbccSCorey Minyard }
3158bfffbccSCorey Minyard 
3168bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3178bfffbccSCorey Minyard {
3188bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3198bfffbccSCorey Minyard 
3208bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3218bfffbccSCorey Minyard }
3228bfffbccSCorey Minyard 
3238bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3248bfffbccSCorey Minyard {
3258bfffbccSCorey Minyard     unsigned int val;
3268bfffbccSCorey Minyard     struct ipmi_time now;
3278bfffbccSCorey Minyard 
3288bfffbccSCorey Minyard     ipmi_gettime(&now);
3298bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3308bfffbccSCorey Minyard     ts[0] = val & 0xff;
3318bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3328bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3338bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3348bfffbccSCorey Minyard }
3358bfffbccSCorey Minyard 
3368bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3378bfffbccSCorey Minyard {
3388bfffbccSCorey Minyard     sdr->reservation++;
3398bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3408bfffbccSCorey Minyard         sdr->reservation = 1;
3418bfffbccSCorey Minyard     }
3428bfffbccSCorey Minyard }
3438bfffbccSCorey Minyard 
344a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
345a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3468bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3478bfffbccSCorey Minyard {
348a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
349a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
350a2295f0aSCédric Le Goater 
351a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3528bfffbccSCorey Minyard         return 1;
3538bfffbccSCorey Minyard     }
3548bfffbccSCorey Minyard 
355a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3568bfffbccSCorey Minyard         return 1;
3578bfffbccSCorey Minyard     }
3588bfffbccSCorey Minyard 
3598bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3608bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3618bfffbccSCorey Minyard         return 1;
3628bfffbccSCorey Minyard     }
3638bfffbccSCorey Minyard 
364a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
365a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
366a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
367a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3688bfffbccSCorey Minyard 
3698bfffbccSCorey Minyard     if (recid) {
3708bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3718bfffbccSCorey Minyard     }
3728bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3738bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3748bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3758bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3768bfffbccSCorey Minyard     return 0;
3778bfffbccSCorey Minyard }
3788bfffbccSCorey Minyard 
3798bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3808bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3818bfffbccSCorey Minyard {
3828bfffbccSCorey Minyard     unsigned int pos = *retpos;
3838bfffbccSCorey Minyard 
3848bfffbccSCorey Minyard     while (pos < sdr->next_free) {
385a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
386a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
387a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
388a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3898bfffbccSCorey Minyard 
3908bfffbccSCorey Minyard         if (trec == recid) {
3918bfffbccSCorey Minyard             if (nextrec) {
3928bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3938bfffbccSCorey Minyard                     *nextrec = 0xffff;
3948bfffbccSCorey Minyard                 } else {
3958bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3968bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3978bfffbccSCorey Minyard                 }
3988bfffbccSCorey Minyard             }
3998bfffbccSCorey Minyard             *retpos = pos;
4008bfffbccSCorey Minyard             return 0;
4018bfffbccSCorey Minyard         }
4028bfffbccSCorey Minyard         pos = nextpos;
4038bfffbccSCorey Minyard     }
4048bfffbccSCorey Minyard     return 1;
4058bfffbccSCorey Minyard }
4068bfffbccSCorey Minyard 
4078bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4088bfffbccSCorey Minyard {
4098bfffbccSCorey Minyard     sel->reservation++;
4108bfffbccSCorey Minyard     if (sel->reservation == 0) {
4118bfffbccSCorey Minyard         sel->reservation = 1;
4128bfffbccSCorey Minyard     }
4138bfffbccSCorey Minyard }
4148bfffbccSCorey Minyard 
4158bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4168bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4178bfffbccSCorey Minyard {
4188bfffbccSCorey Minyard     event[0] = 0xff;
4198bfffbccSCorey Minyard     event[1] = 0xff;
4208bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
4218bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4228bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4238bfffbccSCorey Minyard         return 1;
4248bfffbccSCorey Minyard     }
4258bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4268bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4278bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4288bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4298bfffbccSCorey Minyard     ibs->sel.next_free++;
4308bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4318bfffbccSCorey Minyard     return 0;
4328bfffbccSCorey Minyard }
4338bfffbccSCorey Minyard 
4348bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4358bfffbccSCorey Minyard {
4368bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4378bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4388bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4398bfffbccSCorey Minyard }
4408bfffbccSCorey Minyard 
4418bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4428bfffbccSCorey Minyard {
4438bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4448bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4458bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4468bfffbccSCorey Minyard }
4478bfffbccSCorey Minyard 
4488bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4498bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4508bfffbccSCorey Minyard {
4518bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4528bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4538bfffbccSCorey Minyard     uint8_t evt[16];
4548bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4558bfffbccSCorey Minyard 
4568bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4578bfffbccSCorey Minyard         return;
4588bfffbccSCorey Minyard     }
4598bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4608bfffbccSCorey Minyard         return;
4618bfffbccSCorey Minyard     }
4628bfffbccSCorey Minyard 
4638bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4648bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4658bfffbccSCorey Minyard     evt[8] = 0;
4668bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4678bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4688bfffbccSCorey Minyard     evt[11] = sens_num;
4698bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4708bfffbccSCorey Minyard     evt[13] = evd1;
4718bfffbccSCorey Minyard     evt[14] = evd2;
4728bfffbccSCorey Minyard     evt[15] = evd3;
4738bfffbccSCorey Minyard 
4748bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4758bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4768bfffbccSCorey Minyard     }
4778bfffbccSCorey Minyard 
4788bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
479d13ada5dSCédric Le Goater         return;
4808bfffbccSCorey Minyard     }
4818bfffbccSCorey Minyard 
4828bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4838bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4848bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4858bfffbccSCorey Minyard }
4868bfffbccSCorey Minyard 
4878bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4888bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4898bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4908bfffbccSCorey Minyard {
4918bfffbccSCorey Minyard     IPMISensor *sens;
4928bfffbccSCorey Minyard     uint16_t mask;
4938bfffbccSCorey Minyard 
4948bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4958bfffbccSCorey Minyard         return;
4968bfffbccSCorey Minyard     }
4978bfffbccSCorey Minyard     if (bit >= 16) {
4988bfffbccSCorey Minyard         return;
4998bfffbccSCorey Minyard     }
5008bfffbccSCorey Minyard 
5018bfffbccSCorey Minyard     mask = (1 << bit);
5028bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5038bfffbccSCorey Minyard     if (val) {
5048bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5058bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5068bfffbccSCorey Minyard             return; /* Already asserted */
5078bfffbccSCorey Minyard         }
5088bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5098bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5108bfffbccSCorey Minyard             /* Send an event on assert */
5118bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5128bfffbccSCorey Minyard         }
5138bfffbccSCorey Minyard     } else {
5148bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5158bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5168bfffbccSCorey Minyard             return; /* Already deasserted */
5178bfffbccSCorey Minyard         }
5188bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5198bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5208bfffbccSCorey Minyard             /* Send an event on deassert */
5218bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5228bfffbccSCorey Minyard         }
5238bfffbccSCorey Minyard     }
5248bfffbccSCorey Minyard }
5258bfffbccSCorey Minyard 
5268bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5278bfffbccSCorey Minyard {
5288bfffbccSCorey Minyard     unsigned int i, pos;
5298bfffbccSCorey Minyard     IPMISensor *sens;
5308bfffbccSCorey Minyard 
5318bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5328bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5338bfffbccSCorey Minyard     }
5348bfffbccSCorey Minyard 
5358bfffbccSCorey Minyard     pos = 0;
5368bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
537a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
538a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
539a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5408bfffbccSCorey Minyard 
5418bfffbccSCorey Minyard         if (len < 20) {
5428bfffbccSCorey Minyard             continue;
5438bfffbccSCorey Minyard         }
544a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5458bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5468bfffbccSCorey Minyard         }
5478bfffbccSCorey Minyard 
54873d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5498bfffbccSCorey Minyard             continue;
5508bfffbccSCorey Minyard         }
551a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5528bfffbccSCorey Minyard 
5538bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
554a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
555a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
556a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
557a2295f0aSCédric Le Goater         sens->deassert_suppt =
558a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
559a2295f0aSCédric Le Goater         sens->states_suppt =
560a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
561a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
562a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5638bfffbccSCorey Minyard 
5648bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5658bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5668bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5678bfffbccSCorey Minyard     }
5688bfffbccSCorey Minyard }
5698bfffbccSCorey Minyard 
5708bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5718bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5728bfffbccSCorey Minyard {
57393a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
5748bfffbccSCorey Minyard         return -1;
5758bfffbccSCorey Minyard     }
5768bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5778bfffbccSCorey Minyard     return 0;
5788bfffbccSCorey Minyard }
5798bfffbccSCorey Minyard 
5804f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
5814f298a4bSCédric Le Goater                                               unsigned int netfn,
5824f298a4bSCédric Le Goater                                               unsigned int cmd)
5834f298a4bSCédric Le Goater {
5844f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
5854f298a4bSCédric Le Goater 
5864f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
5874f298a4bSCédric Le Goater         return NULL;
5884f298a4bSCédric Le Goater     }
5894f298a4bSCédric Le Goater 
5904f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
5914f298a4bSCédric Le Goater         return NULL;
5924f298a4bSCédric Le Goater     }
5934f298a4bSCédric Le Goater 
5944f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
5954f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
5964f298a4bSCédric Le Goater         return NULL;
5974f298a4bSCédric Le Goater     }
5984f298a4bSCédric Le Goater 
5994f298a4bSCédric Le Goater     return hdl;
6004f298a4bSCédric Le Goater }
6014f298a4bSCédric Le Goater 
6028bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6038bfffbccSCorey Minyard {
6048bfffbccSCorey Minyard     int64_t next;
6058bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6068bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6078bfffbccSCorey Minyard     } else {
6088bfffbccSCorey Minyard         /* Wait a minute */
6098bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6108bfffbccSCorey Minyard     }
6118bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6128bfffbccSCorey Minyard }
6138bfffbccSCorey Minyard 
6148bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6158bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6168bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6178bfffbccSCorey Minyard                                     uint8_t msg_id)
6188bfffbccSCorey Minyard {
6198bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6208bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6218bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6224f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
623a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6248bfffbccSCorey Minyard 
6258bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6268bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
627a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6286acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
629d13ada5dSCédric Le Goater         goto out;
630d13ada5dSCédric Le Goater     }
631d13ada5dSCédric Le Goater 
632a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
633a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
634a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6358bfffbccSCorey Minyard 
6368bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6378bfffbccSCorey Minyard     if (cmd_len < 2) {
6386acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6398bfffbccSCorey Minyard         goto out;
6408bfffbccSCorey Minyard     }
6418bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6426acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6438bfffbccSCorey Minyard         goto out;
6448bfffbccSCorey Minyard     }
6458bfffbccSCorey Minyard 
6468bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6478bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6486acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6498bfffbccSCorey Minyard         goto out;
6508bfffbccSCorey Minyard     }
6518bfffbccSCorey Minyard 
6524f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6534f298a4bSCédric Le Goater     if (!hdl) {
6546acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6558bfffbccSCorey Minyard         goto out;
6568bfffbccSCorey Minyard     }
6578bfffbccSCorey Minyard 
6584f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
6596acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6604f298a4bSCédric Le Goater         goto out;
6614f298a4bSCédric Le Goater     }
6624f298a4bSCédric Le Goater 
663a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6648bfffbccSCorey Minyard 
6658bfffbccSCorey Minyard  out:
666a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6678bfffbccSCorey Minyard 
6688bfffbccSCorey Minyard     next_timeout(ibs);
6698bfffbccSCorey Minyard }
6708bfffbccSCorey Minyard 
6718bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6728bfffbccSCorey Minyard {
6738bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6748bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6758bfffbccSCorey Minyard 
6768bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6778bfffbccSCorey Minyard         goto out;
6788bfffbccSCorey Minyard     }
6798bfffbccSCorey Minyard 
6808bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6818bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6828bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6838bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6848bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6858bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6868bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6878bfffbccSCorey Minyard             break;
6888bfffbccSCorey Minyard 
6898bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6908bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6918bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6928bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6938bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6948bfffbccSCorey Minyard             break;
6958bfffbccSCorey Minyard 
6968bfffbccSCorey Minyard         default:
6978bfffbccSCorey Minyard             goto do_full_expiry;
6988bfffbccSCorey Minyard         }
6998bfffbccSCorey Minyard 
7008bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7018bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7028bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7038bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7048bfffbccSCorey Minyard         goto out;
7058bfffbccSCorey Minyard     }
7068bfffbccSCorey Minyard 
7078bfffbccSCorey Minyard  do_full_expiry:
7088bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7098bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7108bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7118bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7128bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7138bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7148bfffbccSCorey Minyard         break;
7158bfffbccSCorey Minyard 
7168bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7178bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7188bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7198bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7208bfffbccSCorey Minyard         break;
7218bfffbccSCorey Minyard 
7228bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7238bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7248bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7258bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7268bfffbccSCorey Minyard         break;
7278bfffbccSCorey Minyard 
7288bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7298bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7308bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7318bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7328bfffbccSCorey Minyard         break;
7338bfffbccSCorey Minyard     }
7348bfffbccSCorey Minyard 
7358bfffbccSCorey Minyard  out:
7368bfffbccSCorey Minyard     next_timeout(ibs);
7378bfffbccSCorey Minyard }
7388bfffbccSCorey Minyard 
7398bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7408bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
741a580d820SCédric Le Goater                                  RspBuffer *rsp)
7428bfffbccSCorey Minyard {
743a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
744a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
745a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
746a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
747a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
7488bfffbccSCorey Minyard }
7498bfffbccSCorey Minyard 
7508bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7518bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
752a580d820SCédric Le Goater                            RspBuffer *rsp)
7538bfffbccSCorey Minyard {
754a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
755a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
756a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
757a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7588bfffbccSCorey Minyard }
7598bfffbccSCorey Minyard 
7608bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7618bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
762a580d820SCédric Le Goater                             RspBuffer *rsp)
7638bfffbccSCorey Minyard {
7648bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7658bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7668bfffbccSCorey Minyard 
7678bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7688bfffbccSCorey Minyard     case 0: /* power down */
7696acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
7708bfffbccSCorey Minyard         break;
7718bfffbccSCorey Minyard     case 1: /* power up */
7726acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
7738bfffbccSCorey Minyard         break;
7748bfffbccSCorey Minyard     case 2: /* power cycle */
7756acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
7768bfffbccSCorey Minyard         break;
7778bfffbccSCorey Minyard     case 3: /* hard reset */
7786acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
7798bfffbccSCorey Minyard         break;
7808bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
7816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
7828bfffbccSCorey Minyard         break;
7838bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
7846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
7856acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
7868bfffbccSCorey Minyard         break;
7878bfffbccSCorey Minyard     default:
7886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
7898bfffbccSCorey Minyard         return;
7908bfffbccSCorey Minyard     }
791d13ada5dSCédric Le Goater }
7928bfffbccSCorey Minyard 
793b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
794b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
795a580d820SCédric Le Goater                            RspBuffer *rsp)
796a580d820SCédric Le Goater 
797b7088392SCédric Le Goater {
798a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
799a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
800b7088392SCédric Le Goater }
801b7088392SCédric Le Goater 
8028bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8038bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
804a580d820SCédric Le Goater                           RspBuffer *rsp)
8058bfffbccSCorey Minyard {
806a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
807a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
808a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
809a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
810a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
811a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
812a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[0]);
813a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[1]);
814a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[2]);
815a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[0]);
816a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[1]);
8178bfffbccSCorey Minyard }
8188bfffbccSCorey Minyard 
8198bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8208bfffbccSCorey Minyard {
8218bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8228bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8238bfffbccSCorey Minyard     bool irqs_on;
8248bfffbccSCorey Minyard 
8258bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8268bfffbccSCorey Minyard 
8278bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8288bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8298bfffbccSCorey Minyard 
8308bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8318bfffbccSCorey Minyard }
8328bfffbccSCorey Minyard 
8338bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8348bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
835a580d820SCédric Le Goater                        RspBuffer *rsp)
8368bfffbccSCorey Minyard {
8378bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8388bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8398bfffbccSCorey Minyard 
8408bfffbccSCorey Minyard     /* Disable all interrupts */
8418bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8428bfffbccSCorey Minyard 
8438bfffbccSCorey Minyard     if (k->reset) {
8448bfffbccSCorey Minyard         k->reset(s, true);
8458bfffbccSCorey Minyard     }
8468bfffbccSCorey Minyard }
8478bfffbccSCorey Minyard 
8488bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8498bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
850a580d820SCédric Le Goater                        RspBuffer *rsp)
8518bfffbccSCorey Minyard {
8528bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8538bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8548bfffbccSCorey Minyard 
8558bfffbccSCorey Minyard     if (k->reset) {
8568bfffbccSCorey Minyard         k->reset(s, false);
8578bfffbccSCorey Minyard     }
8588bfffbccSCorey Minyard }
85952ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
86052ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
861a580d820SCédric Le Goater                                  RspBuffer *rsp)
86252ba4d50SCédric Le Goater {
86352ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
86452ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
86552ba4d50SCédric Le Goater }
86652ba4d50SCédric Le Goater 
86752ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
86852ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
869a580d820SCédric Le Goater                                  RspBuffer *rsp)
87052ba4d50SCédric Le Goater {
871a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
872a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
87352ba4d50SCédric Le Goater }
87452ba4d50SCédric Le Goater 
87552ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
87652ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
877a580d820SCédric Le Goater                             RspBuffer *rsp)
87852ba4d50SCédric Le Goater {
87952ba4d50SCédric Le Goater     unsigned int i;
88052ba4d50SCédric Le Goater 
88152ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
882a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->uuid[i]);
88352ba4d50SCédric Le Goater     }
88452ba4d50SCédric Le Goater }
8858bfffbccSCorey Minyard 
8868bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
8878bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
888a580d820SCédric Le Goater                                    RspBuffer *rsp)
8898bfffbccSCorey Minyard {
8908bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8918bfffbccSCorey Minyard }
8928bfffbccSCorey Minyard 
8938bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8948bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
895a580d820SCédric Le Goater                                    RspBuffer *rsp)
8968bfffbccSCorey Minyard {
897a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
8988bfffbccSCorey Minyard }
8998bfffbccSCorey Minyard 
9008bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9018bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
902a580d820SCédric Le Goater                           RspBuffer *rsp)
9038bfffbccSCorey Minyard {
9048bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9058bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9068bfffbccSCorey Minyard 
9078bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9088bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9098bfffbccSCorey Minyard }
9108bfffbccSCorey Minyard 
9118bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9128bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
913a580d820SCédric Le Goater                           RspBuffer *rsp)
9148bfffbccSCorey Minyard {
915a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9168bfffbccSCorey Minyard }
9178bfffbccSCorey Minyard 
9188bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9198bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
920a580d820SCédric Le Goater                              RspBuffer *rsp)
9218bfffbccSCorey Minyard {
9228bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9238bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9248bfffbccSCorey Minyard     unsigned int i;
9258bfffbccSCorey Minyard 
9268bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9276acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
928d13ada5dSCédric Le Goater         return;
9298bfffbccSCorey Minyard     }
9308bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
931a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9328bfffbccSCorey Minyard     }
9338bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9348bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9358bfffbccSCorey Minyard }
9368bfffbccSCorey Minyard 
9378bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9388bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
939a580d820SCédric Le Goater                     RspBuffer *rsp)
9408bfffbccSCorey Minyard {
9418bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9428bfffbccSCorey Minyard 
9438bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
9448bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9456acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
9468bfffbccSCorey Minyard         goto out;
9478bfffbccSCorey Minyard     }
948a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
9498bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
950a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
9518bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9528bfffbccSCorey Minyard     g_free(msg);
9538bfffbccSCorey Minyard 
9548bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9558bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
9568bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9578bfffbccSCorey Minyard 
9588bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9598bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9608bfffbccSCorey Minyard     }
9618bfffbccSCorey Minyard 
9628bfffbccSCorey Minyard out:
9638bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
9648bfffbccSCorey Minyard     return;
9658bfffbccSCorey Minyard }
9668bfffbccSCorey Minyard 
9678bfffbccSCorey Minyard static unsigned char
9688bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9698bfffbccSCorey Minyard {
9708bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9718bfffbccSCorey Minyard             csum += *data;
9728bfffbccSCorey Minyard     }
9738bfffbccSCorey Minyard 
9748bfffbccSCorey Minyard     return -csum;
9758bfffbccSCorey Minyard }
9768bfffbccSCorey Minyard 
9778bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9788bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
979a580d820SCédric Le Goater                      RspBuffer *rsp)
9808bfffbccSCorey Minyard {
9818bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9828bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9838bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9848bfffbccSCorey Minyard     uint8_t *buf;
9858bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9868bfffbccSCorey Minyard 
9878bfffbccSCorey Minyard     if (cmd[2] != 0) {
9888bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
9896acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
990d13ada5dSCédric Le Goater         return;
9918bfffbccSCorey Minyard     }
9928bfffbccSCorey Minyard 
9934f298a4bSCédric Le Goater     if (cmd_len < 10) {
9946acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
9954f298a4bSCédric Le Goater         return;
9964f298a4bSCédric Le Goater     }
9974f298a4bSCédric Le Goater 
9988bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9998bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10006acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1001d13ada5dSCédric Le Goater         return;
10028bfffbccSCorey Minyard     }
10038bfffbccSCorey Minyard 
10048bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10058bfffbccSCorey Minyard     cmd_len -= 3;
10068bfffbccSCorey Minyard 
10078bfffbccSCorey Minyard     /*
10088bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10098bfffbccSCorey Minyard      * be returned in the response.
10108bfffbccSCorey Minyard      */
10118bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10128bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1013d13ada5dSCédric Le Goater         return; /* No response */
10148bfffbccSCorey Minyard     }
10158bfffbccSCorey Minyard 
10168bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10178bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10188bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10198bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10208bfffbccSCorey Minyard 
10218bfffbccSCorey Minyard     if (rqLun != 2) {
10228bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1023d13ada5dSCédric Le Goater         return;
10248bfffbccSCorey Minyard     }
10258bfffbccSCorey Minyard 
10268bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10278bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10288bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10298bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10308bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10318bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10328bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10338bfffbccSCorey Minyard     msg->len = 6;
10348bfffbccSCorey Minyard 
10358bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10368bfffbccSCorey Minyard         /* Not a command we handle. */
10378bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10388bfffbccSCorey Minyard         goto end_msg;
10398bfffbccSCorey Minyard     }
10408bfffbccSCorey Minyard 
10418bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10428bfffbccSCorey Minyard     buf[0] = 0;
10438bfffbccSCorey Minyard     buf[1] = 0;
10448bfffbccSCorey Minyard     buf[2] = 0;
10458bfffbccSCorey Minyard     buf[3] = 0;
10468bfffbccSCorey Minyard     buf[4] = 0x51;
10478bfffbccSCorey Minyard     buf[5] = 0;
10488bfffbccSCorey Minyard     buf[6] = 0;
10498bfffbccSCorey Minyard     buf[7] = 0;
10508bfffbccSCorey Minyard     buf[8] = 0;
10518bfffbccSCorey Minyard     buf[9] = 0;
10528bfffbccSCorey Minyard     buf[10] = 0;
10538bfffbccSCorey Minyard     msg->len += 11;
10548bfffbccSCorey Minyard 
10558bfffbccSCorey Minyard  end_msg:
10568bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10578bfffbccSCorey Minyard     msg->len++;
10588bfffbccSCorey Minyard     qemu_mutex_lock(&ibs->lock);
10598bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10608bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10618bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10628bfffbccSCorey Minyard     qemu_mutex_unlock(&ibs->lock);
10638bfffbccSCorey Minyard }
10648bfffbccSCorey Minyard 
10658bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
10668bfffbccSCorey Minyard {
10678bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
10688bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
10698bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10708bfffbccSCorey Minyard         return;
10718bfffbccSCorey Minyard     }
10728bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10738bfffbccSCorey Minyard 
10748bfffbccSCorey Minyard 
10758bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10768bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10778bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10788bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10798bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10808bfffbccSCorey Minyard     }
10818bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10828bfffbccSCorey Minyard }
10838bfffbccSCorey Minyard 
10848bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10858bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1086a580d820SCédric Le Goater                                  RspBuffer *rsp)
10878bfffbccSCorey Minyard {
10888bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
10896acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1090d13ada5dSCédric Le Goater         return;
10918bfffbccSCorey Minyard     }
10928bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10938bfffbccSCorey Minyard }
10948bfffbccSCorey Minyard 
10958bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10968bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1097a580d820SCédric Le Goater                                RspBuffer *rsp)
10988bfffbccSCorey Minyard {
10998bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11008bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11018bfffbccSCorey Minyard     unsigned int val;
11028bfffbccSCorey Minyard 
11038bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11048bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11056acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1106d13ada5dSCédric Le Goater         return;
11078bfffbccSCorey Minyard     }
11088bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11098bfffbccSCorey Minyard     switch (val) {
11108bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11118bfffbccSCorey Minyard         break;
11128bfffbccSCorey Minyard 
11138bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11146acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11158bfffbccSCorey Minyard         break;
11168bfffbccSCorey Minyard 
11178bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11186acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11198bfffbccSCorey Minyard         break;
11208bfffbccSCorey Minyard 
11218bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11226acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11238bfffbccSCorey Minyard         break;
11248bfffbccSCorey Minyard 
11258bfffbccSCorey Minyard     default:
11266acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11278bfffbccSCorey Minyard     }
1128a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11296acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1130d13ada5dSCédric Le Goater         return;
11318bfffbccSCorey Minyard     }
11328bfffbccSCorey Minyard 
11338bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11348bfffbccSCorey Minyard     switch (val) {
11358bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11368bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11378bfffbccSCorey Minyard         break;
11388bfffbccSCorey Minyard 
11398bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11408bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11418bfffbccSCorey Minyard             /* NMI not supported. */
11426acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1143d13ada5dSCédric Le Goater             return;
11448bfffbccSCorey Minyard         }
114537eebb86SCorey Minyard         break;
114637eebb86SCorey Minyard 
11478bfffbccSCorey Minyard     default:
11488bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11496acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1150d13ada5dSCédric Le Goater         return;
11518bfffbccSCorey Minyard     }
11528bfffbccSCorey Minyard 
11538bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11548bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11558bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11568bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11578bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11588bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11598bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11608bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11618bfffbccSCorey Minyard     } else {
11628bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11638bfffbccSCorey Minyard     }
11648bfffbccSCorey Minyard }
11658bfffbccSCorey Minyard 
11668bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
11678bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1168a580d820SCédric Le Goater                                RspBuffer *rsp)
11698bfffbccSCorey Minyard {
1170a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1171a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1172a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1173a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
11748bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11758bfffbccSCorey Minyard         long timeout;
11768bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11778bfffbccSCorey Minyard                    / 100000000);
1178a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1179a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
11808bfffbccSCorey Minyard     } else {
1181a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1182a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
11838bfffbccSCorey Minyard     }
11848bfffbccSCorey Minyard }
11858bfffbccSCorey Minyard 
11868bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11878bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1188a580d820SCédric Le Goater                              RspBuffer *rsp)
11898bfffbccSCorey Minyard {
11908bfffbccSCorey Minyard     unsigned int i;
11918bfffbccSCorey Minyard 
1192a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1193a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1194a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1195a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1196a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11978bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1198a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
11998bfffbccSCorey Minyard     }
12008bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1201a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
12028bfffbccSCorey Minyard     }
12038bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1204a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12058bfffbccSCorey Minyard }
12068bfffbccSCorey Minyard 
12078bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12088bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1209a580d820SCédric Le Goater                             RspBuffer *rsp)
12108bfffbccSCorey Minyard {
1211a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1212a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12138bfffbccSCorey Minyard }
12148bfffbccSCorey Minyard 
12158bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12168bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1217a580d820SCédric Le Goater                     RspBuffer *rsp)
12188bfffbccSCorey Minyard {
12198bfffbccSCorey Minyard     unsigned int pos;
12208bfffbccSCorey Minyard     uint16_t nextrec;
1221a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12228bfffbccSCorey Minyard 
12238bfffbccSCorey Minyard     if (cmd[6]) {
12247f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12256acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12267f996411SCédric Le Goater             return;
12278bfffbccSCorey Minyard         }
12287f996411SCédric Le Goater     }
12297f996411SCédric Le Goater 
12308bfffbccSCorey Minyard     pos = 0;
12318bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12328bfffbccSCorey Minyard                        &pos, &nextrec)) {
12336acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1234d13ada5dSCédric Le Goater         return;
12358bfffbccSCorey Minyard     }
1236a2295f0aSCédric Le Goater 
1237a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1238a2295f0aSCédric Le Goater 
1239a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
12406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1241d13ada5dSCédric Le Goater         return;
12428bfffbccSCorey Minyard     }
12438bfffbccSCorey Minyard 
1244a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1245a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
12468bfffbccSCorey Minyard 
12478bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1248a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12498bfffbccSCorey Minyard     }
12508bfffbccSCorey Minyard 
1251a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
12526acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1253d13ada5dSCédric Le Goater         return;
12548bfffbccSCorey Minyard     }
1255a580d820SCédric Le Goater 
1256a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12578bfffbccSCorey Minyard }
12588bfffbccSCorey Minyard 
12598bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12608bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1261a580d820SCédric Le Goater                     RspBuffer *rsp)
12628bfffbccSCorey Minyard {
12638bfffbccSCorey Minyard     uint16_t recid;
1264a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
12658bfffbccSCorey Minyard 
1266a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
12676acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1268d13ada5dSCédric Le Goater         return;
12698bfffbccSCorey Minyard     }
1270a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1271a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
12728bfffbccSCorey Minyard }
12738bfffbccSCorey Minyard 
12748bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12758bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1276a580d820SCédric Le Goater                           RspBuffer *rsp)
12778bfffbccSCorey Minyard {
12787f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12796acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12807f996411SCédric Le Goater         return;
12817f996411SCédric Le Goater     }
12827f996411SCédric Le Goater 
12838bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
12846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1285d13ada5dSCédric Le Goater         return;
12868bfffbccSCorey Minyard     }
12878bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12888bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12898bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12908bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1291a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
12928bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12938bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1294a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
12958bfffbccSCorey Minyard     } else {
12966acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
12978bfffbccSCorey Minyard         return;
12988bfffbccSCorey Minyard     }
1299d13ada5dSCédric Le Goater }
13008bfffbccSCorey Minyard 
13018bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
13028bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1303a580d820SCédric Le Goater                          RspBuffer *rsp)
13048bfffbccSCorey Minyard {
13058bfffbccSCorey Minyard     unsigned int i, val;
13068bfffbccSCorey Minyard 
1307a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1308a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1309a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13108bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1311a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1312a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13138bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1314a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13158bfffbccSCorey Minyard     }
13168bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1317a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13188bfffbccSCorey Minyard     }
13198bfffbccSCorey Minyard     /* Only support Reserve SEL */
1320a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13218bfffbccSCorey Minyard }
13228bfffbccSCorey Minyard 
13238bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
13248bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1325a580d820SCédric Le Goater                         RspBuffer *rsp)
13268bfffbccSCorey Minyard {
1327a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1328a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
13298bfffbccSCorey Minyard }
13308bfffbccSCorey Minyard 
13318bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
13328bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1333a580d820SCédric Le Goater                           RspBuffer *rsp)
13348bfffbccSCorey Minyard {
13358bfffbccSCorey Minyard     unsigned int val;
13368bfffbccSCorey Minyard 
13378bfffbccSCorey Minyard     if (cmd[6]) {
13387f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
13396acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13407f996411SCédric Le Goater             return;
13417f996411SCédric Le Goater         }
13428bfffbccSCorey Minyard     }
13438bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
13446acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1345d13ada5dSCédric Le Goater         return;
13468bfffbccSCorey Minyard     }
13478bfffbccSCorey Minyard     if (cmd[6] > 15) {
13486acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1349d13ada5dSCédric Le Goater         return;
13508bfffbccSCorey Minyard     }
13518bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
13528bfffbccSCorey Minyard         cmd[7] = 16;
13538bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
13546acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1355d13ada5dSCédric Le Goater         return;
13568bfffbccSCorey Minyard     } else {
13578bfffbccSCorey Minyard         cmd[7] += cmd[6];
13588bfffbccSCorey Minyard     }
13598bfffbccSCorey Minyard 
13608bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
13618bfffbccSCorey Minyard     if (val == 0xffff) {
13628bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
13638bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
13646acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1365d13ada5dSCédric Le Goater         return;
13668bfffbccSCorey Minyard     }
13678bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1368a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1369a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
13708bfffbccSCorey Minyard     } else {
1371a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1372a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
13738bfffbccSCorey Minyard     }
13748bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1375a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
13768bfffbccSCorey Minyard     }
13778bfffbccSCorey Minyard }
13788bfffbccSCorey Minyard 
13798bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13808bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1381a580d820SCédric Le Goater                           RspBuffer *rsp)
13828bfffbccSCorey Minyard {
13838bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
13846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1385d13ada5dSCédric Le Goater         return;
13868bfffbccSCorey Minyard     }
13878bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1388a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1389a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
13908bfffbccSCorey Minyard }
13918bfffbccSCorey Minyard 
13928bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13938bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1394a580d820SCédric Le Goater                       RspBuffer *rsp)
13958bfffbccSCorey Minyard {
13967f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
13976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13987f996411SCédric Le Goater         return;
13997f996411SCédric Le Goater     }
14007f996411SCédric Le Goater 
14018bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
14026acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1403d13ada5dSCédric Le Goater         return;
14048bfffbccSCorey Minyard     }
14058bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
14068bfffbccSCorey Minyard         ibs->sel.next_free = 0;
14078bfffbccSCorey Minyard         ibs->sel.overflow = 0;
14088bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1409a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14108bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
14118bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1412a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14138bfffbccSCorey Minyard     } else {
14146acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
14158bfffbccSCorey Minyard         return;
14168bfffbccSCorey Minyard     }
1417d13ada5dSCédric Le Goater }
14188bfffbccSCorey Minyard 
14198bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
14208bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1421a580d820SCédric Le Goater                          RspBuffer *rsp)
14228bfffbccSCorey Minyard {
14238bfffbccSCorey Minyard     uint32_t val;
14248bfffbccSCorey Minyard     struct ipmi_time now;
14258bfffbccSCorey Minyard 
14268bfffbccSCorey Minyard     ipmi_gettime(&now);
14278bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1428a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1429a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1430a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1431a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
14328bfffbccSCorey Minyard }
14338bfffbccSCorey Minyard 
14348bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
14358bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1436a580d820SCédric Le Goater                          RspBuffer *rsp)
14378bfffbccSCorey Minyard {
14388bfffbccSCorey Minyard     uint32_t val;
14398bfffbccSCorey Minyard     struct ipmi_time now;
14408bfffbccSCorey Minyard 
14418bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
14428bfffbccSCorey Minyard     ipmi_gettime(&now);
14438bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
14448bfffbccSCorey Minyard }
14458bfffbccSCorey Minyard 
14468bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
14478bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1448a580d820SCédric Le Goater                                   RspBuffer *rsp)
14498bfffbccSCorey Minyard {
14508bfffbccSCorey Minyard     IPMISensor *sens;
14518bfffbccSCorey Minyard 
145273d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
14538bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14546acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1455d13ada5dSCédric Le Goater         return;
14568bfffbccSCorey Minyard     }
14578bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14588bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
14598bfffbccSCorey Minyard     case 0: /* Do not change */
14608bfffbccSCorey Minyard         break;
14618bfffbccSCorey Minyard     case 1: /* Enable bits */
14628bfffbccSCorey Minyard         if (cmd_len > 4) {
14638bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
14648bfffbccSCorey Minyard         }
14658bfffbccSCorey Minyard         if (cmd_len > 5) {
14668bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
14678bfffbccSCorey Minyard         }
14688bfffbccSCorey Minyard         if (cmd_len > 6) {
14698bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
14708bfffbccSCorey Minyard         }
14718bfffbccSCorey Minyard         if (cmd_len > 7) {
14728bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
14738bfffbccSCorey Minyard         }
14748bfffbccSCorey Minyard         break;
14758bfffbccSCorey Minyard     case 2: /* Disable bits */
14768bfffbccSCorey Minyard         if (cmd_len > 4) {
14778bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14788bfffbccSCorey Minyard         }
14798bfffbccSCorey Minyard         if (cmd_len > 5) {
14808bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14818bfffbccSCorey Minyard         }
14828bfffbccSCorey Minyard         if (cmd_len > 6) {
14838bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14848bfffbccSCorey Minyard         }
14858bfffbccSCorey Minyard         if (cmd_len > 7) {
14868bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14878bfffbccSCorey Minyard         }
14888bfffbccSCorey Minyard         break;
14898bfffbccSCorey Minyard     case 3:
14906acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1491d13ada5dSCédric Le Goater         return;
14928bfffbccSCorey Minyard     }
14938bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14948bfffbccSCorey Minyard }
14958bfffbccSCorey Minyard 
14968bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14978bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1498a580d820SCédric Le Goater                                   RspBuffer *rsp)
14998bfffbccSCorey Minyard {
15008bfffbccSCorey Minyard     IPMISensor *sens;
15018bfffbccSCorey Minyard 
150273d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15038bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15046acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1505d13ada5dSCédric Le Goater         return;
15068bfffbccSCorey Minyard     }
15078bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1508a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1509a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1510a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1511a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1512a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
15138bfffbccSCorey Minyard }
15148bfffbccSCorey Minyard 
15158bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
15168bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1517a580d820SCédric Le Goater                               RspBuffer *rsp)
15188bfffbccSCorey Minyard {
15198bfffbccSCorey Minyard     IPMISensor *sens;
15208bfffbccSCorey Minyard 
152173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15228bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15236acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1524d13ada5dSCédric Le Goater         return;
15258bfffbccSCorey Minyard     }
15268bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15278bfffbccSCorey Minyard 
15288bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
15298bfffbccSCorey Minyard         /* Just clear everything */
15308bfffbccSCorey Minyard         sens->states = 0;
15318bfffbccSCorey Minyard         return;
15328bfffbccSCorey Minyard     }
1533d13ada5dSCédric Le Goater }
15348bfffbccSCorey Minyard 
15358bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
15368bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1537a580d820SCédric Le Goater                                   RspBuffer *rsp)
15388bfffbccSCorey Minyard {
15398bfffbccSCorey Minyard     IPMISensor *sens;
15408bfffbccSCorey Minyard 
154173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15428bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15436acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1544d13ada5dSCédric Le Goater         return;
15458bfffbccSCorey Minyard     }
15468bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1547a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1548a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1549a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1550a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1551a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1552a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
15538bfffbccSCorey Minyard }
15548bfffbccSCorey Minyard 
15558bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
15568bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1557a580d820SCédric Le Goater                                RspBuffer *rsp)
15588bfffbccSCorey Minyard {
15598bfffbccSCorey Minyard     IPMISensor *sens;
15608bfffbccSCorey Minyard 
156173d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15628bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15636acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1564d13ada5dSCédric Le Goater         return;
15658bfffbccSCorey Minyard     }
15668bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1567a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1568a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1569a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
15708bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1571a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
15728bfffbccSCorey Minyard     }
15738bfffbccSCorey Minyard }
15748bfffbccSCorey Minyard 
1575728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1576728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1577a580d820SCédric Le Goater                             RspBuffer *rsp)
1578728710e1SCédric Le Goater {
1579728710e1SCédric Le Goater     IPMISensor *sens;
1580728710e1SCédric Le Goater 
1581728710e1SCédric Le Goater 
158273d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1583728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15846acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1585728710e1SCédric Le Goater         return;
1586728710e1SCédric Le Goater     }
1587728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1588728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1589728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1590728710e1SCédric Le Goater }
1591728710e1SCédric Le Goater 
1592728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1593728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1594a580d820SCédric Le Goater                             RspBuffer *rsp)
1595728710e1SCédric Le Goater {
1596728710e1SCédric Le Goater     IPMISensor *sens;
1597728710e1SCédric Le Goater 
1598728710e1SCédric Le Goater 
159973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1600728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16016acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1602728710e1SCédric Le Goater         return;
1603728710e1SCédric Le Goater     }
1604728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1605a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1606a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1607728710e1SCédric Le Goater }
1608728710e1SCédric Le Goater 
1609728710e1SCédric Le Goater 
161062a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
16114f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
16124f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
16134f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
16144f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
16158bfffbccSCorey Minyard };
16168bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
161762a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
16188bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
16198bfffbccSCorey Minyard };
16208bfffbccSCorey Minyard 
162162a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
16224f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
16234f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
16244f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
16254f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
16264f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
16274f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
16284f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
16298bfffbccSCorey Minyard };
16308bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
163162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
16328bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
16338bfffbccSCorey Minyard };
16348bfffbccSCorey Minyard 
163562a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
16364f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
16374f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
16384f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
16394f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
16404f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
16414f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
16424f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
16434f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
16444f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
16454f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
16464f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
16474f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
16484f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
16494f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
16504f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
16514f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
16528bfffbccSCorey Minyard };
16538bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
165462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
16558bfffbccSCorey Minyard     .cmd_handlers = app_cmds
16568bfffbccSCorey Minyard };
16578bfffbccSCorey Minyard 
165862a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
16594f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
16604f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
16614f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
16624f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
16634f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
16644f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
16654f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
16664f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
16674f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
16684f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
16694f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 },
16704f298a4bSCédric Le Goater     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time },
16718bfffbccSCorey Minyard };
16728bfffbccSCorey Minyard 
16738bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
167462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
16758bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
16768bfffbccSCorey Minyard };
16778bfffbccSCorey Minyard 
16788bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
16798bfffbccSCorey Minyard {
16808bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
16818bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
16828bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
16838bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
16848bfffbccSCorey Minyard }
16858bfffbccSCorey Minyard 
16868bfffbccSCorey Minyard static const uint8_t init_sdrs[] = {
16878bfffbccSCorey Minyard     /* Watchdog device */
16888bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
16898bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
16908bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16918bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
16928bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
16938bfffbccSCorey Minyard     /* End */
16948bfffbccSCorey Minyard     0xff, 0xff, 0x00, 0x00, 0x00
16958bfffbccSCorey Minyard };
16968bfffbccSCorey Minyard 
1697*4fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
1698*4fa9f08eSCédric Le Goater {
1699*4fa9f08eSCédric Le Goater     unsigned int i;
1700*4fa9f08eSCédric Le Goater     unsigned int recid;
1701*4fa9f08eSCédric Le Goater 
1702*4fa9f08eSCédric Le Goater     for (i = 0;;) {
1703*4fa9f08eSCédric Le Goater         struct ipmi_sdr_header *sdrh;
1704*4fa9f08eSCédric Le Goater         int len;
1705*4fa9f08eSCédric Le Goater         if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) {
1706*4fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
1707*4fa9f08eSCédric Le Goater             return;
1708*4fa9f08eSCédric Le Goater         }
1709*4fa9f08eSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &init_sdrs[i];
1710*4fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
1711*4fa9f08eSCédric Le Goater         recid = ipmi_sdr_recid(sdrh);
1712*4fa9f08eSCédric Le Goater         if (recid == 0xffff) {
1713*4fa9f08eSCédric Le Goater             break;
1714*4fa9f08eSCédric Le Goater         }
1715*4fa9f08eSCédric Le Goater         if ((i + len) > sizeof(init_sdrs)) {
1716*4fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
1717*4fa9f08eSCédric Le Goater             return;
1718*4fa9f08eSCédric Le Goater         }
1719*4fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
1720*4fa9f08eSCédric Le Goater         i += len;
1721*4fa9f08eSCédric Le Goater     }
1722*4fa9f08eSCédric Le Goater }
1723*4fa9f08eSCédric Le Goater 
1724bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1725bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1726bd66bcfcSCorey Minyard     .version_id = 1,
1727bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1728bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1729bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1730bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1731bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1732bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1733bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1734bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1735bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1736bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1737bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1738bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1739bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1740bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1741bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1742bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1743bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1744bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1745bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1746bd66bcfcSCorey Minyard                        IPMIBmcSim),
1747bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1748bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1749bd66bcfcSCorey Minyard     }
1750bd66bcfcSCorey Minyard };
1751bd66bcfcSCorey Minyard 
17520bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
17538bfffbccSCorey Minyard {
17540bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
17558bfffbccSCorey Minyard     unsigned int i;
17568bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
17578bfffbccSCorey Minyard 
17588bfffbccSCorey Minyard     qemu_mutex_init(&ibs->lock);
17598bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
17608bfffbccSCorey Minyard 
17618bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
17628bfffbccSCorey Minyard     ibs->device_id = 0x20;
17638bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1764b7088392SCédric Le Goater     ibs->restart_cause = 0;
17658bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
17668bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
17678bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
17688bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
17698bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
17708bfffbccSCorey Minyard     }
17718bfffbccSCorey Minyard 
1772*4fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
17738bfffbccSCorey Minyard 
177452ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
177552ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
177652ba4d50SCédric Le Goater 
177752ba4d50SCédric Le Goater     if (qemu_uuid_set) {
177852ba4d50SCédric Le Goater         memcpy(&ibs->uuid, qemu_uuid, 16);
177952ba4d50SCédric Le Goater     } else {
178052ba4d50SCédric Le Goater         memset(&ibs->uuid, 0, 16);
178152ba4d50SCédric Le Goater     }
178252ba4d50SCédric Le Goater 
17838bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
17848bfffbccSCorey Minyard     register_cmds(ibs);
17858bfffbccSCorey Minyard 
17868bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1787bd66bcfcSCorey Minyard 
1788bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
17898bfffbccSCorey Minyard }
17908bfffbccSCorey Minyard 
17918bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
17928bfffbccSCorey Minyard {
17930bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
17948bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
17958bfffbccSCorey Minyard 
17960bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
17978bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
17988bfffbccSCorey Minyard }
17998bfffbccSCorey Minyard 
18008bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
18018bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
18028bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
18038bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
18048bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
18058bfffbccSCorey Minyard };
18068bfffbccSCorey Minyard 
18078bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
18088bfffbccSCorey Minyard {
18098bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
18108bfffbccSCorey Minyard }
18118bfffbccSCorey Minyard 
18128bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1813