xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 8c6fd7f341fd7e414171e09618b496de871da718)
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"
30*8c6fd7f3SCédric Le Goater #include "hw/loader.h"
318bfffbccSCorey Minyard 
328bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS            0x00
338bfffbccSCorey Minyard 
348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
358bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS       0x01
368bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL          0x02
37b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE    0x09
388bfffbccSCorey Minyard 
398bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT       0x04
408bfffbccSCorey Minyard 
418bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE    0x28
428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE    0x29
438bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS        0x2a
448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS    0x2b
458bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING       0x2d
46728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE          0x2e
47728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE          0x2f
488bfffbccSCorey Minyard 
498bfffbccSCorey Minyard /* #define IPMI_NETFN_APP             0x06 In ipmi.h */
508bfffbccSCorey Minyard 
518bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID            0x01
528bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET               0x02
538bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET               0x03
5452ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE     0x06
5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE     0x07
5652ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID          0x08
578bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER     0x22
588bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER       0x24
598bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER       0x25
608bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES   0x2e
618bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES   0x2f
628bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS            0x30
638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS            0x31
648bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG                  0x33
658bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG                 0x34
668bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF         0x35
678bfffbccSCorey Minyard 
688bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE            0x0a
698bfffbccSCorey Minyard 
708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO         0x20
718bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO   0x21
728bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP          0x22
738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR                  0x23
748bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR                  0x24
758bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR          0x25
768bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR               0x26
778bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP            0x27
788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME         0x28
798bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME         0x29
808bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE   0x2A
818bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE    0x2B
828bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT           0x2C
838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO             0x40
848bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO       0x41
858bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL              0x42
868bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY            0x43
878bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY            0x44
888bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY    0x45
898bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY         0x46
908bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL                0x47
918bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME             0x48
928bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME             0x49
938bfffbccSCorey Minyard 
948bfffbccSCorey Minyard 
958bfffbccSCorey Minyard /* Same as a timespec struct. */
968bfffbccSCorey Minyard struct ipmi_time {
978bfffbccSCorey Minyard     long tv_sec;
988bfffbccSCorey Minyard     long tv_nsec;
998bfffbccSCorey Minyard };
1008bfffbccSCorey Minyard 
1018bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1028bfffbccSCorey Minyard 
1038bfffbccSCorey Minyard typedef struct IPMISel {
1048bfffbccSCorey Minyard     uint8_t sel[MAX_SEL_SIZE][16];
1058bfffbccSCorey Minyard     unsigned int next_free;
1068bfffbccSCorey Minyard     long time_offset;
1078bfffbccSCorey Minyard     uint16_t reservation;
1088bfffbccSCorey Minyard     uint8_t last_addition[4];
1098bfffbccSCorey Minyard     uint8_t last_clear[4];
1108bfffbccSCorey Minyard     uint8_t overflow;
1118bfffbccSCorey Minyard } IPMISel;
1128bfffbccSCorey Minyard 
1138bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1148bfffbccSCorey Minyard 
1158bfffbccSCorey Minyard typedef struct IPMISdr {
1168bfffbccSCorey Minyard     uint8_t sdr[MAX_SDR_SIZE];
1178bfffbccSCorey Minyard     unsigned int next_free;
1188bfffbccSCorey Minyard     uint16_t next_rec_id;
1198bfffbccSCorey Minyard     uint16_t reservation;
1208bfffbccSCorey Minyard     uint8_t last_addition[4];
1218bfffbccSCorey Minyard     uint8_t last_clear[4];
1228bfffbccSCorey Minyard     uint8_t overflow;
1238bfffbccSCorey Minyard } IPMISdr;
1248bfffbccSCorey Minyard 
1258bfffbccSCorey Minyard typedef struct IPMISensor {
1268bfffbccSCorey Minyard     uint8_t status;
1278bfffbccSCorey Minyard     uint8_t reading;
1288bfffbccSCorey Minyard     uint16_t states_suppt;
1298bfffbccSCorey Minyard     uint16_t assert_suppt;
1308bfffbccSCorey Minyard     uint16_t deassert_suppt;
1318bfffbccSCorey Minyard     uint16_t states;
1328bfffbccSCorey Minyard     uint16_t assert_states;
1338bfffbccSCorey Minyard     uint16_t deassert_states;
1348bfffbccSCorey Minyard     uint16_t assert_enable;
1358bfffbccSCorey Minyard     uint16_t deassert_enable;
1368bfffbccSCorey Minyard     uint8_t  sensor_type;
1378bfffbccSCorey Minyard     uint8_t  evt_reading_type_code;
1388bfffbccSCorey Minyard } IPMISensor;
1398bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s)       ((s)->status & 0x01)
1408bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v)    ((s)->status = (s->status & ~0x01) | \
1418bfffbccSCorey Minyard                                              !!(v))
1428bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s)       ((s)->status & 0x40)
1438bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v)    ((s)->status = (s->status & ~0x40) | \
1448bfffbccSCorey Minyard                                              ((!!(v)) << 6))
1458bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s)     ((s)->status & 0x80)
1468bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v)  ((s)->status = (s->status & ~0x80) | \
1478bfffbccSCorey Minyard                                              ((!!(v)) << 7))
1488bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s)    ((s)->status & 0xc0)
1498bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1508bfffbccSCorey Minyard                                              (v & 0xc0))
1518bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1528bfffbccSCorey Minyard 
1538bfffbccSCorey Minyard #define MAX_SENSORS 20
1548bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1558bfffbccSCorey Minyard 
1568bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim;
157a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer;
1588bfffbccSCorey Minyard 
1598bfffbccSCorey Minyard #define MAX_NETFNS 64
1604f298a4bSCédric Le Goater 
1614f298a4bSCédric Le Goater typedef struct IPMICmdHandler {
1624f298a4bSCédric Le Goater     void (*cmd_handler)(IPMIBmcSim *s,
1638bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
164a580d820SCédric Le Goater                         RspBuffer *rsp);
1654f298a4bSCédric Le Goater     unsigned int cmd_len_min;
1664f298a4bSCédric Le Goater } IPMICmdHandler;
1674f298a4bSCédric Le Goater 
1688bfffbccSCorey Minyard typedef struct IPMINetfn {
1698bfffbccSCorey Minyard     unsigned int cmd_nums;
1708bfffbccSCorey Minyard     const IPMICmdHandler *cmd_handlers;
1718bfffbccSCorey Minyard } IPMINetfn;
1728bfffbccSCorey Minyard 
1738bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1748bfffbccSCorey Minyard     QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1758bfffbccSCorey Minyard     uint8_t len;
1768bfffbccSCorey Minyard     uint8_t buf[MAX_IPMI_MSG_SIZE];
1778bfffbccSCorey Minyard } IPMIRcvBufEntry;
1788bfffbccSCorey Minyard 
1798bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim"
1808bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \
1818bfffbccSCorey Minyard                                         TYPE_IPMI_BMC_SIMULATOR)
1828bfffbccSCorey Minyard struct IPMIBmcSim {
1838bfffbccSCorey Minyard     IPMIBmc parent;
1848bfffbccSCorey Minyard 
1858bfffbccSCorey Minyard     QEMUTimer *timer;
1868bfffbccSCorey Minyard 
1878bfffbccSCorey Minyard     uint8_t bmc_global_enables;
1888bfffbccSCorey Minyard     uint8_t msg_flags;
1898bfffbccSCorey Minyard 
1908bfffbccSCorey Minyard     bool     watchdog_initialized;
1918bfffbccSCorey Minyard     uint8_t  watchdog_use;
1928bfffbccSCorey Minyard     uint8_t  watchdog_action;
1938bfffbccSCorey Minyard     uint8_t  watchdog_pretimeout; /* In seconds */
1948bfffbccSCorey Minyard     bool     watchdog_expired;
1958bfffbccSCorey Minyard     uint16_t watchdog_timeout; /* in 100's of milliseconds */
1968bfffbccSCorey Minyard 
1978bfffbccSCorey Minyard     bool     watchdog_running;
1988bfffbccSCorey Minyard     bool     watchdog_preaction_ran;
1998bfffbccSCorey Minyard     int64_t  watchdog_expiry;
2008bfffbccSCorey Minyard 
2018bfffbccSCorey Minyard     uint8_t device_id;
2028bfffbccSCorey Minyard     uint8_t ipmi_version;
2038bfffbccSCorey Minyard     uint8_t device_rev;
2048bfffbccSCorey Minyard     uint8_t fwrev1;
2058bfffbccSCorey Minyard     uint8_t fwrev2;
2068bfffbccSCorey Minyard     uint8_t mfg_id[3];
2078bfffbccSCorey Minyard     uint8_t product_id[2];
2088bfffbccSCorey Minyard 
209b7088392SCédric Le Goater     uint8_t restart_cause;
210b7088392SCédric Le Goater 
21152ba4d50SCédric Le Goater     uint8_t acpi_power_state[2];
21252ba4d50SCédric Le Goater     uint8_t uuid[16];
21352ba4d50SCédric Le Goater 
2148bfffbccSCorey Minyard     IPMISel sel;
2158bfffbccSCorey Minyard     IPMISdr sdr;
2168bfffbccSCorey Minyard     IPMISensor sensors[MAX_SENSORS];
217*8c6fd7f3SCédric Le Goater     char *sdr_filename;
2188bfffbccSCorey Minyard 
2198bfffbccSCorey Minyard     /* Odd netfns are for responses, so we only need the even ones. */
2208bfffbccSCorey Minyard     const IPMINetfn *netfns[MAX_NETFNS / 2];
2218bfffbccSCorey Minyard 
2228bfffbccSCorey Minyard     /* We allow one event in the buffer */
2238bfffbccSCorey Minyard     uint8_t evtbuf[16];
2248bfffbccSCorey Minyard 
2258bfffbccSCorey Minyard     QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2268bfffbccSCorey Minyard };
2278bfffbccSCorey Minyard 
2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK        (1 << 3)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL                 (1 << 1)
2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE                (1 << 0)
2318bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2328bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2338bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2348bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2358bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2368bfffbccSCorey Minyard     (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2378bfffbccSCorey Minyard 
2388bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2398bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2418bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2428bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2438bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2448bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2458bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2468bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2478bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2488bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2498bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2508bfffbccSCorey Minyard 
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2668bfffbccSCorey Minyard 
267a580d820SCédric Le Goater struct RspBuffer {
268a580d820SCédric Le Goater     uint8_t buffer[MAX_IPMI_MSG_SIZE];
269a580d820SCédric Le Goater     unsigned int len;
270a580d820SCédric Le Goater };
271a580d820SCédric Le Goater 
272a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2738bfffbccSCorey Minyard 
2746acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte)
2756acb971aSCédric Le Goater {
2766acb971aSCédric Le Goater     rsp->buffer[2] = byte;
2776acb971aSCédric Le Goater }
2786acb971aSCédric Le Goater 
2798bfffbccSCorey Minyard /* Add a byte to the response. */
280a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte)
281a580d820SCédric Le Goater {
282a580d820SCédric Le Goater     if (rsp->len >= sizeof(rsp->buffer)) {
2836acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
284a580d820SCédric Le Goater         return;
285a580d820SCédric Le Goater     }
286a580d820SCédric Le Goater     rsp->buffer[rsp->len++] = byte;
287a580d820SCédric Le Goater }
288a580d820SCédric Le Goater 
289a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
290a580d820SCédric Le Goater                                        unsigned int n)
291a580d820SCédric Le Goater {
292a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
2936acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
294a580d820SCédric Le Goater         return;
295a580d820SCédric Le Goater     }
296a580d820SCédric Le Goater 
297a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
298a580d820SCédric Le Goater     rsp->len += n;
299a580d820SCédric Le Goater }
3008bfffbccSCorey Minyard 
3018bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
3028bfffbccSCorey Minyard 
3038bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
3048bfffbccSCorey Minyard {
3058bfffbccSCorey Minyard     int64_t stime;
3068bfffbccSCorey Minyard 
3078bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
3088bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
3098bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
3108bfffbccSCorey Minyard }
3118bfffbccSCorey Minyard 
3128bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
3138bfffbccSCorey Minyard {
3148bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3158bfffbccSCorey Minyard }
3168bfffbccSCorey Minyard 
3178bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
3188bfffbccSCorey Minyard {
3198bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3208bfffbccSCorey Minyard 
3218bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3228bfffbccSCorey Minyard }
3238bfffbccSCorey Minyard 
3248bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3258bfffbccSCorey Minyard {
3268bfffbccSCorey Minyard     unsigned int val;
3278bfffbccSCorey Minyard     struct ipmi_time now;
3288bfffbccSCorey Minyard 
3298bfffbccSCorey Minyard     ipmi_gettime(&now);
3308bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3318bfffbccSCorey Minyard     ts[0] = val & 0xff;
3328bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3338bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3348bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3358bfffbccSCorey Minyard }
3368bfffbccSCorey Minyard 
3378bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3388bfffbccSCorey Minyard {
3398bfffbccSCorey Minyard     sdr->reservation++;
3408bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3418bfffbccSCorey Minyard         sdr->reservation = 1;
3428bfffbccSCorey Minyard     }
3438bfffbccSCorey Minyard }
3448bfffbccSCorey Minyard 
345a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
346a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3478bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3488bfffbccSCorey Minyard {
349a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
350a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
351a2295f0aSCédric Le Goater 
352a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3538bfffbccSCorey Minyard         return 1;
3548bfffbccSCorey Minyard     }
3558bfffbccSCorey Minyard 
356a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3578bfffbccSCorey Minyard         return 1;
3588bfffbccSCorey Minyard     }
3598bfffbccSCorey Minyard 
3608bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3618bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3628bfffbccSCorey Minyard         return 1;
3638bfffbccSCorey Minyard     }
3648bfffbccSCorey Minyard 
365a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
366a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
367a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
368a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3698bfffbccSCorey Minyard 
3708bfffbccSCorey Minyard     if (recid) {
3718bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3728bfffbccSCorey Minyard     }
3738bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3748bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3758bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3768bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3778bfffbccSCorey Minyard     return 0;
3788bfffbccSCorey Minyard }
3798bfffbccSCorey Minyard 
3808bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3818bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3828bfffbccSCorey Minyard {
3838bfffbccSCorey Minyard     unsigned int pos = *retpos;
3848bfffbccSCorey Minyard 
3858bfffbccSCorey Minyard     while (pos < sdr->next_free) {
386a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
387a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
388a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
389a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3908bfffbccSCorey Minyard 
3918bfffbccSCorey Minyard         if (trec == recid) {
3928bfffbccSCorey Minyard             if (nextrec) {
3938bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3948bfffbccSCorey Minyard                     *nextrec = 0xffff;
3958bfffbccSCorey Minyard                 } else {
3968bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3978bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3988bfffbccSCorey Minyard                 }
3998bfffbccSCorey Minyard             }
4008bfffbccSCorey Minyard             *retpos = pos;
4018bfffbccSCorey Minyard             return 0;
4028bfffbccSCorey Minyard         }
4038bfffbccSCorey Minyard         pos = nextpos;
4048bfffbccSCorey Minyard     }
4058bfffbccSCorey Minyard     return 1;
4068bfffbccSCorey Minyard }
4078bfffbccSCorey Minyard 
4088bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4098bfffbccSCorey Minyard {
4108bfffbccSCorey Minyard     sel->reservation++;
4118bfffbccSCorey Minyard     if (sel->reservation == 0) {
4128bfffbccSCorey Minyard         sel->reservation = 1;
4138bfffbccSCorey Minyard     }
4148bfffbccSCorey Minyard }
4158bfffbccSCorey Minyard 
4168bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
4178bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4188bfffbccSCorey Minyard {
4198bfffbccSCorey Minyard     event[0] = 0xff;
4208bfffbccSCorey Minyard     event[1] = 0xff;
4218bfffbccSCorey Minyard     set_timestamp(ibs, event + 3);
4228bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4238bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4248bfffbccSCorey Minyard         return 1;
4258bfffbccSCorey Minyard     }
4268bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4278bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4288bfffbccSCorey Minyard     memcpy(ibs->sel.last_addition, event + 3, 4);
4298bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4308bfffbccSCorey Minyard     ibs->sel.next_free++;
4318bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4328bfffbccSCorey Minyard     return 0;
4338bfffbccSCorey Minyard }
4348bfffbccSCorey Minyard 
4358bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4368bfffbccSCorey Minyard {
4378bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4388bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4398bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4408bfffbccSCorey Minyard }
4418bfffbccSCorey Minyard 
4428bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4438bfffbccSCorey Minyard {
4448bfffbccSCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs))
4458bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4468bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4478bfffbccSCorey Minyard }
4488bfffbccSCorey Minyard 
4498bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4508bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4518bfffbccSCorey Minyard {
4528bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4538bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4548bfffbccSCorey Minyard     uint8_t evt[16];
4558bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4568bfffbccSCorey Minyard 
4578bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4588bfffbccSCorey Minyard         return;
4598bfffbccSCorey Minyard     }
4608bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4618bfffbccSCorey Minyard         return;
4628bfffbccSCorey Minyard     }
4638bfffbccSCorey Minyard 
4648bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4658bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4668bfffbccSCorey Minyard     evt[8] = 0;
4678bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4688bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4698bfffbccSCorey Minyard     evt[11] = sens_num;
4708bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4718bfffbccSCorey Minyard     evt[13] = evd1;
4728bfffbccSCorey Minyard     evt[14] = evd2;
4738bfffbccSCorey Minyard     evt[15] = evd3;
4748bfffbccSCorey Minyard 
4758bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
4768bfffbccSCorey Minyard         sel_add_event(ibs, evt);
4778bfffbccSCorey Minyard     }
4788bfffbccSCorey Minyard 
4798bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
480d13ada5dSCédric Le Goater         return;
4818bfffbccSCorey Minyard     }
4828bfffbccSCorey Minyard 
4838bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
4848bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
4858bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
4868bfffbccSCorey Minyard }
4878bfffbccSCorey Minyard 
4888bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
4898bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
4908bfffbccSCorey Minyard                                     uint8_t evd1, uint8_t evd2, uint8_t evd3)
4918bfffbccSCorey Minyard {
4928bfffbccSCorey Minyard     IPMISensor *sens;
4938bfffbccSCorey Minyard     uint16_t mask;
4948bfffbccSCorey Minyard 
4958bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
4968bfffbccSCorey Minyard         return;
4978bfffbccSCorey Minyard     }
4988bfffbccSCorey Minyard     if (bit >= 16) {
4998bfffbccSCorey Minyard         return;
5008bfffbccSCorey Minyard     }
5018bfffbccSCorey Minyard 
5028bfffbccSCorey Minyard     mask = (1 << bit);
5038bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5048bfffbccSCorey Minyard     if (val) {
5058bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5068bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5078bfffbccSCorey Minyard             return; /* Already asserted */
5088bfffbccSCorey Minyard         }
5098bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
5108bfffbccSCorey Minyard         if (sens->assert_enable & mask & sens->assert_states) {
5118bfffbccSCorey Minyard             /* Send an event on assert */
5128bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5138bfffbccSCorey Minyard         }
5148bfffbccSCorey Minyard     } else {
5158bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5168bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5178bfffbccSCorey Minyard             return; /* Already deasserted */
5188bfffbccSCorey Minyard         }
5198bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
5208bfffbccSCorey Minyard         if (sens->deassert_enable & mask & sens->deassert_states) {
5218bfffbccSCorey Minyard             /* Send an event on deassert */
5228bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5238bfffbccSCorey Minyard         }
5248bfffbccSCorey Minyard     }
5258bfffbccSCorey Minyard }
5268bfffbccSCorey Minyard 
5278bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5288bfffbccSCorey Minyard {
5298bfffbccSCorey Minyard     unsigned int i, pos;
5308bfffbccSCorey Minyard     IPMISensor *sens;
5318bfffbccSCorey Minyard 
5328bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5338bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5348bfffbccSCorey Minyard     }
5358bfffbccSCorey Minyard 
5368bfffbccSCorey Minyard     pos = 0;
5378bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
538a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
539a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
540a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5418bfffbccSCorey Minyard 
5428bfffbccSCorey Minyard         if (len < 20) {
5438bfffbccSCorey Minyard             continue;
5448bfffbccSCorey Minyard         }
545a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5468bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5478bfffbccSCorey Minyard         }
5488bfffbccSCorey Minyard 
54973d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5508bfffbccSCorey Minyard             continue;
5518bfffbccSCorey Minyard         }
552a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5538bfffbccSCorey Minyard 
5548bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
555a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
556a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
557a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
558a2295f0aSCédric Le Goater         sens->deassert_suppt =
559a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
560a2295f0aSCédric Le Goater         sens->states_suppt =
561a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
562a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
563a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5648bfffbccSCorey Minyard 
5658bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5668bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5678bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5688bfffbccSCorey Minyard     }
5698bfffbccSCorey Minyard }
5708bfffbccSCorey Minyard 
5718bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5728bfffbccSCorey Minyard                                const IPMINetfn *netfnd)
5738bfffbccSCorey Minyard {
57493a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
5758bfffbccSCorey Minyard         return -1;
5768bfffbccSCorey Minyard     }
5778bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
5788bfffbccSCorey Minyard     return 0;
5798bfffbccSCorey Minyard }
5808bfffbccSCorey Minyard 
5814f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
5824f298a4bSCédric Le Goater                                               unsigned int netfn,
5834f298a4bSCédric Le Goater                                               unsigned int cmd)
5844f298a4bSCédric Le Goater {
5854f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
5864f298a4bSCédric Le Goater 
5874f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
5884f298a4bSCédric Le Goater         return NULL;
5894f298a4bSCédric Le Goater     }
5904f298a4bSCédric Le Goater 
5914f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
5924f298a4bSCédric Le Goater         return NULL;
5934f298a4bSCédric Le Goater     }
5944f298a4bSCédric Le Goater 
5954f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
5964f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
5974f298a4bSCédric Le Goater         return NULL;
5984f298a4bSCédric Le Goater     }
5994f298a4bSCédric Le Goater 
6004f298a4bSCédric Le Goater     return hdl;
6014f298a4bSCédric Le Goater }
6024f298a4bSCédric Le Goater 
6038bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6048bfffbccSCorey Minyard {
6058bfffbccSCorey Minyard     int64_t next;
6068bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6078bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6088bfffbccSCorey Minyard     } else {
6098bfffbccSCorey Minyard         /* Wait a minute */
6108bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6118bfffbccSCorey Minyard     }
6128bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6138bfffbccSCorey Minyard }
6148bfffbccSCorey Minyard 
6158bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6168bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6178bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6188bfffbccSCorey Minyard                                     uint8_t msg_id)
6198bfffbccSCorey Minyard {
6208bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6218bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6228bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6234f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
624a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6258bfffbccSCorey Minyard 
6268bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6278bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
628a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6296acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
630d13ada5dSCédric Le Goater         goto out;
631d13ada5dSCédric Le Goater     }
632d13ada5dSCédric Le Goater 
633a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
634a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
635a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6368bfffbccSCorey Minyard 
6378bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6388bfffbccSCorey Minyard     if (cmd_len < 2) {
6396acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6408bfffbccSCorey Minyard         goto out;
6418bfffbccSCorey Minyard     }
6428bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6436acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6448bfffbccSCorey Minyard         goto out;
6458bfffbccSCorey Minyard     }
6468bfffbccSCorey Minyard 
6478bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6488bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6496acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6508bfffbccSCorey Minyard         goto out;
6518bfffbccSCorey Minyard     }
6528bfffbccSCorey Minyard 
6534f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6544f298a4bSCédric Le Goater     if (!hdl) {
6556acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6568bfffbccSCorey Minyard         goto out;
6578bfffbccSCorey Minyard     }
6588bfffbccSCorey Minyard 
6594f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
6606acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6614f298a4bSCédric Le Goater         goto out;
6624f298a4bSCédric Le Goater     }
6634f298a4bSCédric Le Goater 
664a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6658bfffbccSCorey Minyard 
6668bfffbccSCorey Minyard  out:
667a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6688bfffbccSCorey Minyard 
6698bfffbccSCorey Minyard     next_timeout(ibs);
6708bfffbccSCorey Minyard }
6718bfffbccSCorey Minyard 
6728bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6738bfffbccSCorey Minyard {
6748bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6758bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6768bfffbccSCorey Minyard 
6778bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
6788bfffbccSCorey Minyard         goto out;
6798bfffbccSCorey Minyard     }
6808bfffbccSCorey Minyard 
6818bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
6828bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
6838bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
6848bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6858bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
6868bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6878bfffbccSCorey Minyard                                     0xc8, (2 << 4) | 0xf, 0xff);
6888bfffbccSCorey Minyard             break;
6898bfffbccSCorey Minyard 
6908bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
6918bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
6928bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
6938bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
6948bfffbccSCorey Minyard                                     0xc8, (3 << 4) | 0xf, 0xff);
6958bfffbccSCorey Minyard             break;
6968bfffbccSCorey Minyard 
6978bfffbccSCorey Minyard         default:
6988bfffbccSCorey Minyard             goto do_full_expiry;
6998bfffbccSCorey Minyard         }
7008bfffbccSCorey Minyard 
7018bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7028bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7038bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7048bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7058bfffbccSCorey Minyard         goto out;
7068bfffbccSCorey Minyard     }
7078bfffbccSCorey Minyard 
7088bfffbccSCorey Minyard  do_full_expiry:
7098bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7108bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7118bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7128bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7138bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7148bfffbccSCorey Minyard                                 0xc0, ibs->watchdog_use & 0xf, 0xff);
7158bfffbccSCorey Minyard         break;
7168bfffbccSCorey Minyard 
7178bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7188bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7198bfffbccSCorey Minyard                                 0xc1, ibs->watchdog_use & 0xf, 0xff);
7208bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7218bfffbccSCorey Minyard         break;
7228bfffbccSCorey Minyard 
7238bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7248bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7258bfffbccSCorey Minyard                                 0xc2, ibs->watchdog_use & 0xf, 0xff);
7268bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7278bfffbccSCorey Minyard         break;
7288bfffbccSCorey Minyard 
7298bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7308bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7318bfffbccSCorey Minyard                                 0xc3, ibs->watchdog_use & 0xf, 0xff);
7328bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7338bfffbccSCorey Minyard         break;
7348bfffbccSCorey Minyard     }
7358bfffbccSCorey Minyard 
7368bfffbccSCorey Minyard  out:
7378bfffbccSCorey Minyard     next_timeout(ibs);
7388bfffbccSCorey Minyard }
7398bfffbccSCorey Minyard 
7408bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7418bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
742a580d820SCédric Le Goater                                  RspBuffer *rsp)
7438bfffbccSCorey Minyard {
744a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
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);
748a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
7498bfffbccSCorey Minyard }
7508bfffbccSCorey Minyard 
7518bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7528bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
753a580d820SCédric Le Goater                            RspBuffer *rsp)
7548bfffbccSCorey Minyard {
755a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
756a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
757a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
758a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7598bfffbccSCorey Minyard }
7608bfffbccSCorey Minyard 
7618bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7628bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
763a580d820SCédric Le Goater                             RspBuffer *rsp)
7648bfffbccSCorey Minyard {
7658bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7668bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7678bfffbccSCorey Minyard 
7688bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
7698bfffbccSCorey Minyard     case 0: /* power down */
7706acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
7718bfffbccSCorey Minyard         break;
7728bfffbccSCorey Minyard     case 1: /* power up */
7736acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
7748bfffbccSCorey Minyard         break;
7758bfffbccSCorey Minyard     case 2: /* power cycle */
7766acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
7778bfffbccSCorey Minyard         break;
7788bfffbccSCorey Minyard     case 3: /* hard reset */
7796acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
7808bfffbccSCorey Minyard         break;
7818bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
7826acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
7838bfffbccSCorey Minyard         break;
7848bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
7856acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
7866acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
7878bfffbccSCorey Minyard         break;
7888bfffbccSCorey Minyard     default:
7896acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
7908bfffbccSCorey Minyard         return;
7918bfffbccSCorey Minyard     }
792d13ada5dSCédric Le Goater }
7938bfffbccSCorey Minyard 
794b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
795b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
796a580d820SCédric Le Goater                            RspBuffer *rsp)
797a580d820SCédric Le Goater 
798b7088392SCédric Le Goater {
799a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
800a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
801b7088392SCédric Le Goater }
802b7088392SCédric Le Goater 
8038bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8048bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
805a580d820SCédric Le Goater                           RspBuffer *rsp)
8068bfffbccSCorey Minyard {
807a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
808a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
809a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
810a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
811a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
812a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
813a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[0]);
814a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[1]);
815a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->mfg_id[2]);
816a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[0]);
817a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->product_id[1]);
8188bfffbccSCorey Minyard }
8198bfffbccSCorey Minyard 
8208bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8218bfffbccSCorey Minyard {
8228bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8238bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8248bfffbccSCorey Minyard     bool irqs_on;
8258bfffbccSCorey Minyard 
8268bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8278bfffbccSCorey Minyard 
8288bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8298bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8308bfffbccSCorey Minyard 
8318bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8328bfffbccSCorey Minyard }
8338bfffbccSCorey Minyard 
8348bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8358bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
836a580d820SCédric Le Goater                        RspBuffer *rsp)
8378bfffbccSCorey Minyard {
8388bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8398bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8408bfffbccSCorey Minyard 
8418bfffbccSCorey Minyard     /* Disable all interrupts */
8428bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8438bfffbccSCorey Minyard 
8448bfffbccSCorey Minyard     if (k->reset) {
8458bfffbccSCorey Minyard         k->reset(s, true);
8468bfffbccSCorey Minyard     }
8478bfffbccSCorey Minyard }
8488bfffbccSCorey Minyard 
8498bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8508bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
851a580d820SCédric Le Goater                        RspBuffer *rsp)
8528bfffbccSCorey Minyard {
8538bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8548bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8558bfffbccSCorey Minyard 
8568bfffbccSCorey Minyard     if (k->reset) {
8578bfffbccSCorey Minyard         k->reset(s, false);
8588bfffbccSCorey Minyard     }
8598bfffbccSCorey Minyard }
86052ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
86152ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
862a580d820SCédric Le Goater                                  RspBuffer *rsp)
86352ba4d50SCédric Le Goater {
86452ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
86552ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
86652ba4d50SCédric Le Goater }
86752ba4d50SCédric Le Goater 
86852ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
86952ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
870a580d820SCédric Le Goater                                  RspBuffer *rsp)
87152ba4d50SCédric Le Goater {
872a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
873a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
87452ba4d50SCédric Le Goater }
87552ba4d50SCédric Le Goater 
87652ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
87752ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
878a580d820SCédric Le Goater                             RspBuffer *rsp)
87952ba4d50SCédric Le Goater {
88052ba4d50SCédric Le Goater     unsigned int i;
88152ba4d50SCédric Le Goater 
88252ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
883a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->uuid[i]);
88452ba4d50SCédric Le Goater     }
88552ba4d50SCédric Le Goater }
8868bfffbccSCorey Minyard 
8878bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
8888bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
889a580d820SCédric Le Goater                                    RspBuffer *rsp)
8908bfffbccSCorey Minyard {
8918bfffbccSCorey Minyard     set_global_enables(ibs, cmd[2]);
8928bfffbccSCorey Minyard }
8938bfffbccSCorey Minyard 
8948bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
8958bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
896a580d820SCédric Le Goater                                    RspBuffer *rsp)
8978bfffbccSCorey Minyard {
898a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
8998bfffbccSCorey Minyard }
9008bfffbccSCorey Minyard 
9018bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9028bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
903a580d820SCédric Le Goater                           RspBuffer *rsp)
9048bfffbccSCorey Minyard {
9058bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9068bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9078bfffbccSCorey Minyard 
9088bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9098bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9108bfffbccSCorey Minyard }
9118bfffbccSCorey Minyard 
9128bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9138bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
914a580d820SCédric Le Goater                           RspBuffer *rsp)
9158bfffbccSCorey Minyard {
916a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9178bfffbccSCorey Minyard }
9188bfffbccSCorey Minyard 
9198bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9208bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
921a580d820SCédric Le Goater                              RspBuffer *rsp)
9228bfffbccSCorey Minyard {
9238bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9248bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9258bfffbccSCorey Minyard     unsigned int i;
9268bfffbccSCorey Minyard 
9278bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9286acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
929d13ada5dSCédric Le Goater         return;
9308bfffbccSCorey Minyard     }
9318bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
932a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9338bfffbccSCorey Minyard     }
9348bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9358bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9368bfffbccSCorey Minyard }
9378bfffbccSCorey Minyard 
9388bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9398bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
940a580d820SCédric Le Goater                     RspBuffer *rsp)
9418bfffbccSCorey Minyard {
9428bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9438bfffbccSCorey Minyard 
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     return;
9648bfffbccSCorey Minyard }
9658bfffbccSCorey Minyard 
9668bfffbccSCorey Minyard static unsigned char
9678bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
9688bfffbccSCorey Minyard {
9698bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
9708bfffbccSCorey Minyard             csum += *data;
9718bfffbccSCorey Minyard     }
9728bfffbccSCorey Minyard 
9738bfffbccSCorey Minyard     return -csum;
9748bfffbccSCorey Minyard }
9758bfffbccSCorey Minyard 
9768bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
9778bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
978a580d820SCédric Le Goater                      RspBuffer *rsp)
9798bfffbccSCorey Minyard {
9808bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9818bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9828bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9838bfffbccSCorey Minyard     uint8_t *buf;
9848bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
9858bfffbccSCorey Minyard 
9868bfffbccSCorey Minyard     if (cmd[2] != 0) {
9878bfffbccSCorey Minyard         /* We only handle channel 0 with no options */
9886acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
989d13ada5dSCédric Le Goater         return;
9908bfffbccSCorey Minyard     }
9918bfffbccSCorey Minyard 
9924f298a4bSCédric Le Goater     if (cmd_len < 10) {
9936acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
9944f298a4bSCédric Le Goater         return;
9954f298a4bSCédric Le Goater     }
9964f298a4bSCédric Le Goater 
9978bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
9988bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
9996acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1000d13ada5dSCédric Le Goater         return;
10018bfffbccSCorey Minyard     }
10028bfffbccSCorey Minyard 
10038bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10048bfffbccSCorey Minyard     cmd_len -= 3;
10058bfffbccSCorey Minyard 
10068bfffbccSCorey Minyard     /*
10078bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10088bfffbccSCorey Minyard      * be returned in the response.
10098bfffbccSCorey Minyard      */
10108bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10118bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1012d13ada5dSCédric Le Goater         return; /* No response */
10138bfffbccSCorey Minyard     }
10148bfffbccSCorey Minyard 
10158bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10168bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10178bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10188bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10198bfffbccSCorey Minyard 
10208bfffbccSCorey Minyard     if (rqLun != 2) {
10218bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1022d13ada5dSCédric Le Goater         return;
10238bfffbccSCorey Minyard     }
10248bfffbccSCorey Minyard 
10258bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10268bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10278bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10288bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10298bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10308bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10318bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10328bfffbccSCorey Minyard     msg->len = 6;
10338bfffbccSCorey Minyard 
10348bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10358bfffbccSCorey Minyard         /* Not a command we handle. */
10368bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10378bfffbccSCorey Minyard         goto end_msg;
10388bfffbccSCorey Minyard     }
10398bfffbccSCorey Minyard 
10408bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10418bfffbccSCorey Minyard     buf[0] = 0;
10428bfffbccSCorey Minyard     buf[1] = 0;
10438bfffbccSCorey Minyard     buf[2] = 0;
10448bfffbccSCorey Minyard     buf[3] = 0;
10458bfffbccSCorey Minyard     buf[4] = 0x51;
10468bfffbccSCorey Minyard     buf[5] = 0;
10478bfffbccSCorey Minyard     buf[6] = 0;
10488bfffbccSCorey Minyard     buf[7] = 0;
10498bfffbccSCorey Minyard     buf[8] = 0;
10508bfffbccSCorey Minyard     buf[9] = 0;
10518bfffbccSCorey Minyard     buf[10] = 0;
10528bfffbccSCorey Minyard     msg->len += 11;
10538bfffbccSCorey Minyard 
10548bfffbccSCorey Minyard  end_msg:
10558bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10568bfffbccSCorey Minyard     msg->len++;
10578bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10588bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10598bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
10608bfffbccSCorey Minyard }
10618bfffbccSCorey Minyard 
10628bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
10638bfffbccSCorey Minyard {
10648bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
10658bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
10668bfffbccSCorey Minyard         ibs->watchdog_running = 0;
10678bfffbccSCorey Minyard         return;
10688bfffbccSCorey Minyard     }
10698bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
10708bfffbccSCorey Minyard 
10718bfffbccSCorey Minyard 
10728bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
10738bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
10748bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
10758bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
10768bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
10778bfffbccSCorey Minyard     }
10788bfffbccSCorey Minyard     ibs->watchdog_running = 1;
10798bfffbccSCorey Minyard }
10808bfffbccSCorey Minyard 
10818bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
10828bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1083a580d820SCédric Le Goater                                  RspBuffer *rsp)
10848bfffbccSCorey Minyard {
10858bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
10866acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1087d13ada5dSCédric Le Goater         return;
10888bfffbccSCorey Minyard     }
10898bfffbccSCorey Minyard     do_watchdog_reset(ibs);
10908bfffbccSCorey Minyard }
10918bfffbccSCorey Minyard 
10928bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
10938bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1094a580d820SCédric Le Goater                                RspBuffer *rsp)
10958bfffbccSCorey Minyard {
10968bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10978bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10988bfffbccSCorey Minyard     unsigned int val;
10998bfffbccSCorey Minyard 
11008bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11018bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11026acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1103d13ada5dSCédric Le Goater         return;
11048bfffbccSCorey Minyard     }
11058bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11068bfffbccSCorey Minyard     switch (val) {
11078bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11088bfffbccSCorey Minyard         break;
11098bfffbccSCorey Minyard 
11108bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11116acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11128bfffbccSCorey Minyard         break;
11138bfffbccSCorey Minyard 
11148bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11156acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11168bfffbccSCorey Minyard         break;
11178bfffbccSCorey Minyard 
11188bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11196acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11208bfffbccSCorey Minyard         break;
11218bfffbccSCorey Minyard 
11228bfffbccSCorey Minyard     default:
11236acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11248bfffbccSCorey Minyard     }
1125a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11266acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1127d13ada5dSCédric Le Goater         return;
11288bfffbccSCorey Minyard     }
11298bfffbccSCorey Minyard 
11308bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11318bfffbccSCorey Minyard     switch (val) {
11328bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11338bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11348bfffbccSCorey Minyard         break;
11358bfffbccSCorey Minyard 
11368bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11378bfffbccSCorey Minyard         if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11388bfffbccSCorey Minyard             /* NMI not supported. */
11396acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1140d13ada5dSCédric Le Goater             return;
11418bfffbccSCorey Minyard         }
114237eebb86SCorey Minyard         break;
114337eebb86SCorey Minyard 
11448bfffbccSCorey Minyard     default:
11458bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11466acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1147d13ada5dSCédric Le Goater         return;
11488bfffbccSCorey Minyard     }
11498bfffbccSCorey Minyard 
11508bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
11518bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11528bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11538bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
11548bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
11558bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11568bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11578bfffbccSCorey Minyard         do_watchdog_reset(ibs);
11588bfffbccSCorey Minyard     } else {
11598bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11608bfffbccSCorey Minyard     }
11618bfffbccSCorey Minyard }
11628bfffbccSCorey Minyard 
11638bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
11648bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1165a580d820SCédric Le Goater                                RspBuffer *rsp)
11668bfffbccSCorey Minyard {
1167a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1168a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1169a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1170a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
11718bfffbccSCorey Minyard     if (ibs->watchdog_running) {
11728bfffbccSCorey Minyard         long timeout;
11738bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
11748bfffbccSCorey Minyard                    / 100000000);
1175a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1176a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
11778bfffbccSCorey Minyard     } else {
1178a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1179a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
11808bfffbccSCorey Minyard     }
11818bfffbccSCorey Minyard }
11828bfffbccSCorey Minyard 
11838bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
11848bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1185a580d820SCédric Le Goater                              RspBuffer *rsp)
11868bfffbccSCorey Minyard {
11878bfffbccSCorey Minyard     unsigned int i;
11888bfffbccSCorey Minyard 
1189a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1190a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1191a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1192a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1193a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
11948bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1195a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
11968bfffbccSCorey Minyard     }
11978bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1198a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
11998bfffbccSCorey Minyard     }
12008bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1201a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12028bfffbccSCorey Minyard }
12038bfffbccSCorey Minyard 
12048bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12058bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1206a580d820SCédric Le Goater                             RspBuffer *rsp)
12078bfffbccSCorey Minyard {
1208a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1209a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12108bfffbccSCorey Minyard }
12118bfffbccSCorey Minyard 
12128bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12138bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1214a580d820SCédric Le Goater                     RspBuffer *rsp)
12158bfffbccSCorey Minyard {
12168bfffbccSCorey Minyard     unsigned int pos;
12178bfffbccSCorey Minyard     uint16_t nextrec;
1218a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
12198bfffbccSCorey Minyard 
12208bfffbccSCorey Minyard     if (cmd[6]) {
12217f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12226acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12237f996411SCédric Le Goater             return;
12248bfffbccSCorey Minyard         }
12257f996411SCédric Le Goater     }
12267f996411SCédric Le Goater 
12278bfffbccSCorey Minyard     pos = 0;
12288bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12298bfffbccSCorey Minyard                        &pos, &nextrec)) {
12306acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1231d13ada5dSCédric Le Goater         return;
12328bfffbccSCorey Minyard     }
1233a2295f0aSCédric Le Goater 
1234a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1235a2295f0aSCédric Le Goater 
1236a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
12376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1238d13ada5dSCédric Le Goater         return;
12398bfffbccSCorey Minyard     }
12408bfffbccSCorey Minyard 
1241a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1242a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
12438bfffbccSCorey Minyard 
12448bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1245a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12468bfffbccSCorey Minyard     }
12478bfffbccSCorey Minyard 
1248a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
12496acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1250d13ada5dSCédric Le Goater         return;
12518bfffbccSCorey Minyard     }
1252a580d820SCédric Le Goater 
1253a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12548bfffbccSCorey Minyard }
12558bfffbccSCorey Minyard 
12568bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12578bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1258a580d820SCédric Le Goater                     RspBuffer *rsp)
12598bfffbccSCorey Minyard {
12608bfffbccSCorey Minyard     uint16_t recid;
1261a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
12628bfffbccSCorey Minyard 
1263a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
12646acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1265d13ada5dSCédric Le Goater         return;
12668bfffbccSCorey Minyard     }
1267a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1268a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
12698bfffbccSCorey Minyard }
12708bfffbccSCorey Minyard 
12718bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
12728bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1273a580d820SCédric Le Goater                           RspBuffer *rsp)
12748bfffbccSCorey Minyard {
12757f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12766acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12777f996411SCédric Le Goater         return;
12787f996411SCédric Le Goater     }
12797f996411SCédric Le Goater 
12808bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
12816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1282d13ada5dSCédric Le Goater         return;
12838bfffbccSCorey Minyard     }
12848bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
12858bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
12868bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
12878bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1288a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
12898bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
12908bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1291a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
12928bfffbccSCorey Minyard     } else {
12936acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
12948bfffbccSCorey Minyard         return;
12958bfffbccSCorey Minyard     }
1296d13ada5dSCédric Le Goater }
12978bfffbccSCorey Minyard 
12988bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
12998bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1300a580d820SCédric Le Goater                          RspBuffer *rsp)
13018bfffbccSCorey Minyard {
13028bfffbccSCorey Minyard     unsigned int i, val;
13038bfffbccSCorey Minyard 
1304a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1305a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1306a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13078bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1308a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1309a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
13108bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1311a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13128bfffbccSCorey Minyard     }
13138bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1314a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13158bfffbccSCorey Minyard     }
13168bfffbccSCorey Minyard     /* Only support Reserve SEL */
1317a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13188bfffbccSCorey Minyard }
13198bfffbccSCorey Minyard 
13208bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
13218bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1322a580d820SCédric Le Goater                         RspBuffer *rsp)
13238bfffbccSCorey Minyard {
1324a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1325a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
13268bfffbccSCorey Minyard }
13278bfffbccSCorey Minyard 
13288bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
13298bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1330a580d820SCédric Le Goater                           RspBuffer *rsp)
13318bfffbccSCorey Minyard {
13328bfffbccSCorey Minyard     unsigned int val;
13338bfffbccSCorey Minyard 
13348bfffbccSCorey Minyard     if (cmd[6]) {
13357f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
13366acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13377f996411SCédric Le Goater             return;
13387f996411SCédric Le Goater         }
13398bfffbccSCorey Minyard     }
13408bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
13416acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1342d13ada5dSCédric Le Goater         return;
13438bfffbccSCorey Minyard     }
13448bfffbccSCorey Minyard     if (cmd[6] > 15) {
13456acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1346d13ada5dSCédric Le Goater         return;
13478bfffbccSCorey Minyard     }
13488bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
13498bfffbccSCorey Minyard         cmd[7] = 16;
13508bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
13516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1352d13ada5dSCédric Le Goater         return;
13538bfffbccSCorey Minyard     } else {
13548bfffbccSCorey Minyard         cmd[7] += cmd[6];
13558bfffbccSCorey Minyard     }
13568bfffbccSCorey Minyard 
13578bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
13588bfffbccSCorey Minyard     if (val == 0xffff) {
13598bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
13608bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
13616acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1362d13ada5dSCédric Le Goater         return;
13638bfffbccSCorey Minyard     }
13648bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1365a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1366a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
13678bfffbccSCorey Minyard     } else {
1368a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1369a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
13708bfffbccSCorey Minyard     }
13718bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1372a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
13738bfffbccSCorey Minyard     }
13748bfffbccSCorey Minyard }
13758bfffbccSCorey Minyard 
13768bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
13778bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1378a580d820SCédric Le Goater                           RspBuffer *rsp)
13798bfffbccSCorey Minyard {
13808bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
13816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1382d13ada5dSCédric Le Goater         return;
13838bfffbccSCorey Minyard     }
13848bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1385a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1386a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
13878bfffbccSCorey Minyard }
13888bfffbccSCorey Minyard 
13898bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
13908bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1391a580d820SCédric Le Goater                       RspBuffer *rsp)
13928bfffbccSCorey Minyard {
13937f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
13946acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13957f996411SCédric Le Goater         return;
13967f996411SCédric Le Goater     }
13977f996411SCédric Le Goater 
13988bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13996acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1400d13ada5dSCédric Le Goater         return;
14018bfffbccSCorey Minyard     }
14028bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
14038bfffbccSCorey Minyard         ibs->sel.next_free = 0;
14048bfffbccSCorey Minyard         ibs->sel.overflow = 0;
14058bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1406a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14078bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
14088bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1409a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14108bfffbccSCorey Minyard     } else {
14116acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
14128bfffbccSCorey Minyard         return;
14138bfffbccSCorey Minyard     }
1414d13ada5dSCédric Le Goater }
14158bfffbccSCorey Minyard 
14168bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
14178bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1418a580d820SCédric Le Goater                          RspBuffer *rsp)
14198bfffbccSCorey Minyard {
14208bfffbccSCorey Minyard     uint32_t val;
14218bfffbccSCorey Minyard     struct ipmi_time now;
14228bfffbccSCorey Minyard 
14238bfffbccSCorey Minyard     ipmi_gettime(&now);
14248bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1425a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1426a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1427a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1428a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
14298bfffbccSCorey Minyard }
14308bfffbccSCorey Minyard 
14318bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
14328bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1433a580d820SCédric Le Goater                          RspBuffer *rsp)
14348bfffbccSCorey Minyard {
14358bfffbccSCorey Minyard     uint32_t val;
14368bfffbccSCorey Minyard     struct ipmi_time now;
14378bfffbccSCorey Minyard 
14388bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
14398bfffbccSCorey Minyard     ipmi_gettime(&now);
14408bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
14418bfffbccSCorey Minyard }
14428bfffbccSCorey Minyard 
14438bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
14448bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1445a580d820SCédric Le Goater                                   RspBuffer *rsp)
14468bfffbccSCorey Minyard {
14478bfffbccSCorey Minyard     IPMISensor *sens;
14488bfffbccSCorey Minyard 
144973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
14508bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
14516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1452d13ada5dSCédric Le Goater         return;
14538bfffbccSCorey Minyard     }
14548bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
14558bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
14568bfffbccSCorey Minyard     case 0: /* Do not change */
14578bfffbccSCorey Minyard         break;
14588bfffbccSCorey Minyard     case 1: /* Enable bits */
14598bfffbccSCorey Minyard         if (cmd_len > 4) {
14608bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
14618bfffbccSCorey Minyard         }
14628bfffbccSCorey Minyard         if (cmd_len > 5) {
14638bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
14648bfffbccSCorey Minyard         }
14658bfffbccSCorey Minyard         if (cmd_len > 6) {
14668bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
14678bfffbccSCorey Minyard         }
14688bfffbccSCorey Minyard         if (cmd_len > 7) {
14698bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
14708bfffbccSCorey Minyard         }
14718bfffbccSCorey Minyard         break;
14728bfffbccSCorey Minyard     case 2: /* Disable bits */
14738bfffbccSCorey Minyard         if (cmd_len > 4) {
14748bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
14758bfffbccSCorey Minyard         }
14768bfffbccSCorey Minyard         if (cmd_len > 5) {
14778bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
14788bfffbccSCorey Minyard         }
14798bfffbccSCorey Minyard         if (cmd_len > 6) {
14808bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
14818bfffbccSCorey Minyard         }
14828bfffbccSCorey Minyard         if (cmd_len > 7) {
14838bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
14848bfffbccSCorey Minyard         }
14858bfffbccSCorey Minyard         break;
14868bfffbccSCorey Minyard     case 3:
14876acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1488d13ada5dSCédric Le Goater         return;
14898bfffbccSCorey Minyard     }
14908bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
14918bfffbccSCorey Minyard }
14928bfffbccSCorey Minyard 
14938bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
14948bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1495a580d820SCédric Le Goater                                   RspBuffer *rsp)
14968bfffbccSCorey Minyard {
14978bfffbccSCorey Minyard     IPMISensor *sens;
14988bfffbccSCorey Minyard 
149973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15008bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15016acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1502d13ada5dSCédric Le Goater         return;
15038bfffbccSCorey Minyard     }
15048bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1505a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1506a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1507a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1508a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1509a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
15108bfffbccSCorey Minyard }
15118bfffbccSCorey Minyard 
15128bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
15138bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1514a580d820SCédric Le Goater                               RspBuffer *rsp)
15158bfffbccSCorey Minyard {
15168bfffbccSCorey Minyard     IPMISensor *sens;
15178bfffbccSCorey Minyard 
151873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15198bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15206acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1521d13ada5dSCédric Le Goater         return;
15228bfffbccSCorey Minyard     }
15238bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
15248bfffbccSCorey Minyard 
15258bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
15268bfffbccSCorey Minyard         /* Just clear everything */
15278bfffbccSCorey Minyard         sens->states = 0;
15288bfffbccSCorey Minyard         return;
15298bfffbccSCorey Minyard     }
1530d13ada5dSCédric Le Goater }
15318bfffbccSCorey Minyard 
15328bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
15338bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1534a580d820SCédric Le Goater                                   RspBuffer *rsp)
15358bfffbccSCorey Minyard {
15368bfffbccSCorey Minyard     IPMISensor *sens;
15378bfffbccSCorey Minyard 
153873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15398bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1541d13ada5dSCédric Le Goater         return;
15428bfffbccSCorey Minyard     }
15438bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1544a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1545a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1546a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1547a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1548a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1549a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
15508bfffbccSCorey Minyard }
15518bfffbccSCorey Minyard 
15528bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
15538bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1554a580d820SCédric Le Goater                                RspBuffer *rsp)
15558bfffbccSCorey Minyard {
15568bfffbccSCorey Minyard     IPMISensor *sens;
15578bfffbccSCorey Minyard 
155873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
15598bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15606acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1561d13ada5dSCédric Le Goater         return;
15628bfffbccSCorey Minyard     }
15638bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1564a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1565a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1566a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
15678bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1568a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
15698bfffbccSCorey Minyard     }
15708bfffbccSCorey Minyard }
15718bfffbccSCorey Minyard 
1572728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1573728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1574a580d820SCédric Le Goater                             RspBuffer *rsp)
1575728710e1SCédric Le Goater {
1576728710e1SCédric Le Goater     IPMISensor *sens;
1577728710e1SCédric Le Goater 
1578728710e1SCédric Le Goater 
157973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1580728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15816acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1582728710e1SCédric Le Goater         return;
1583728710e1SCédric Le Goater     }
1584728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1585728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1586728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1587728710e1SCédric Le Goater }
1588728710e1SCédric Le Goater 
1589728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1590728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1591a580d820SCédric Le Goater                             RspBuffer *rsp)
1592728710e1SCédric Le Goater {
1593728710e1SCédric Le Goater     IPMISensor *sens;
1594728710e1SCédric Le Goater 
1595728710e1SCédric Le Goater 
159673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1597728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15986acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1599728710e1SCédric Le Goater         return;
1600728710e1SCédric Le Goater     }
1601728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1602a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1603a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1604728710e1SCédric Le Goater }
1605728710e1SCédric Le Goater 
1606728710e1SCédric Le Goater 
160762a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
16084f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
16094f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
16104f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
16114f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
16128bfffbccSCorey Minyard };
16138bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
161462a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
16158bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
16168bfffbccSCorey Minyard };
16178bfffbccSCorey Minyard 
161862a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
16194f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
16204f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
16214f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
16224f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
16234f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
16244f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
16254f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
16268bfffbccSCorey Minyard };
16278bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
162862a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
16298bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
16308bfffbccSCorey Minyard };
16318bfffbccSCorey Minyard 
163262a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
16334f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
16344f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
16354f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
16364f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
16374f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
16384f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
16394f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
16404f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
16414f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
16424f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
16434f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
16444f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
16454f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
16464f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
16474f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
16484f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
16498bfffbccSCorey Minyard };
16508bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
165162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
16528bfffbccSCorey Minyard     .cmd_handlers = app_cmds
16538bfffbccSCorey Minyard };
16548bfffbccSCorey Minyard 
165562a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
16564f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
16574f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
16584f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
16594f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
16604f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
16614f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
16624f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
16634f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
16644f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
16654f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
16664f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 },
16674f298a4bSCédric Le Goater     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time },
16688bfffbccSCorey Minyard };
16698bfffbccSCorey Minyard 
16708bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
167162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
16728bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
16738bfffbccSCorey Minyard };
16748bfffbccSCorey Minyard 
16758bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
16768bfffbccSCorey Minyard {
16778bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
16788bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
16798bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
16808bfffbccSCorey Minyard     ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
16818bfffbccSCorey Minyard }
16828bfffbccSCorey Minyard 
16835167560bSCédric Le Goater static uint8_t init_sdrs[] = {
16848bfffbccSCorey Minyard     /* Watchdog device */
16858bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
16868bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
16878bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16888bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
16898bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
16908bfffbccSCorey Minyard };
16918bfffbccSCorey Minyard 
16924fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
16934fa9f08eSCédric Le Goater {
16944fa9f08eSCédric Le Goater     unsigned int i;
16954fa9f08eSCédric Le Goater     int len;
16965167560bSCédric Le Goater     size_t sdrs_size;
16975167560bSCédric Le Goater     uint8_t *sdrs;
169852fc01d9SCédric Le Goater 
16995167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
17005167560bSCédric Le Goater     sdrs = init_sdrs;
1701*8c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
1702*8c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
1703*8c6fd7f3SCédric Le Goater                              NULL)) {
1704*8c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
1705*8c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
1706*8c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
1707*8c6fd7f3SCédric Le Goater     }
17085167560bSCédric Le Goater 
17095167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
171052fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
171152fc01d9SCédric Le Goater 
17125167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
17134fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
1714*8c6fd7f3SCédric Le Goater             break;
17154fa9f08eSCédric Le Goater         }
17165167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
17174fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
17185167560bSCédric Le Goater         if (i + len > sdrs_size) {
17194fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
1720*8c6fd7f3SCédric Le Goater             break;
17214fa9f08eSCédric Le Goater         }
17224fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
17234fa9f08eSCédric Le Goater     }
1724*8c6fd7f3SCédric Le Goater 
1725*8c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
1726*8c6fd7f3SCédric Le Goater         g_free(sdrs);
1727*8c6fd7f3SCédric Le Goater     }
17284fa9f08eSCédric Le Goater }
17294fa9f08eSCédric Le Goater 
1730bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
1731bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
1732bd66bcfcSCorey Minyard     .version_id = 1,
1733bd66bcfcSCorey Minyard     .minimum_version_id = 1,
1734bd66bcfcSCorey Minyard     .fields      = (VMStateField[]) {
1735bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
1736bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
1737bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
1738bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
1739bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
1740bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
1741bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_expired, IPMIBmcSim),
1742bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
1743bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
1744bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
1745bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
1746bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
1747bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
1748bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
1749bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
1750bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
1751bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
1752bd66bcfcSCorey Minyard                        IPMIBmcSim),
1753bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
1754bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
1755bd66bcfcSCorey Minyard     }
1756bd66bcfcSCorey Minyard };
1757bd66bcfcSCorey Minyard 
17580bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
17598bfffbccSCorey Minyard {
17600bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
17618bfffbccSCorey Minyard     unsigned int i;
17628bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
17638bfffbccSCorey Minyard 
17648bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
17658bfffbccSCorey Minyard 
17668bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
17678bfffbccSCorey Minyard     ibs->device_id = 0x20;
17688bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
1769b7088392SCédric Le Goater     ibs->restart_cause = 0;
17708bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
17718bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
17728bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
17738bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
17748bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
17758bfffbccSCorey Minyard     }
17768bfffbccSCorey Minyard 
17774fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
17788bfffbccSCorey Minyard 
177952ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
178052ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
178152ba4d50SCédric Le Goater 
178252ba4d50SCédric Le Goater     if (qemu_uuid_set) {
17839c5ce8dbSFam Zheng         memcpy(&ibs->uuid, &qemu_uuid, 16);
178452ba4d50SCédric Le Goater     } else {
178552ba4d50SCédric Le Goater         memset(&ibs->uuid, 0, 16);
178652ba4d50SCédric Le Goater     }
178752ba4d50SCédric Le Goater 
17888bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
17898bfffbccSCorey Minyard     register_cmds(ibs);
17908bfffbccSCorey Minyard 
17918bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
1792bd66bcfcSCorey Minyard 
1793bd66bcfcSCorey Minyard     vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
17948bfffbccSCorey Minyard }
17958bfffbccSCorey Minyard 
1796*8c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = {
1797*8c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
1798*8c6fd7f3SCédric Le Goater     DEFINE_PROP_END_OF_LIST(),
1799*8c6fd7f3SCédric Le Goater };
1800*8c6fd7f3SCédric Le Goater 
18018bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
18028bfffbccSCorey Minyard {
18030bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
18048bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
18058bfffbccSCorey Minyard 
180666abfddbSCorey Minyard     dc->hotpluggable = false;
18070bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
1808*8c6fd7f3SCédric Le Goater     dc->props = ipmi_sim_properties;
18098bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
18108bfffbccSCorey Minyard }
18118bfffbccSCorey Minyard 
18128bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
18138bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
18148bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
18158bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
18168bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
18178bfffbccSCorey Minyard };
18188bfffbccSCorey Minyard 
18198bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
18208bfffbccSCorey Minyard {
18218bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
18228bfffbccSCorey Minyard }
18238bfffbccSCorey Minyard 
18248bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
1825