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"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
318c6fd7f3SCédric Le Goater #include "hw/loader.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
33ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
34d6454270SMarkus Armbruster #include "migration/vmstate.h"
358bfffbccSCorey Minyard
368bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00
378bfffbccSCorey Minyard
388bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00
398bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01
408bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02
41b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09
428bfffbccSCorey Minyard
438bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04
448bfffbccSCorey Minyard
459380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG 0x02
468bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28
478bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29
488bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a
498bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b
508bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d
51728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e
52728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f
53e3f7320cSCédric Le Goater #define IPMI_CMD_SET_SENSOR_READING 0x30
548bfffbccSCorey Minyard
558bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */
568bfffbccSCorey Minyard
578bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01
588bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02
598bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03
6052ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06
6152ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07
6252ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID 0x08
638bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22
648bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24
658bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25
668bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e
678bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f
688bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30
698bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31
708bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33
718bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34
728bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35
738bfffbccSCorey Minyard
748bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a
758bfffbccSCorey Minyard
768bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
788bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22
798bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23
808bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24
818bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25
828bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26
838bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27
848bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28
858bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29
868bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
878bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
888bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C
89540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO 0x10
90540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA 0x11
91540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA 0x12
928bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40
938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
948bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42
958bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43
968bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44
978bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
988bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46
998bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47
1008bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48
1018bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49
1028bfffbccSCorey Minyard
1038bfffbccSCorey Minyard
1048bfffbccSCorey Minyard /* Same as a timespec struct. */
1058bfffbccSCorey Minyard struct ipmi_time {
1068bfffbccSCorey Minyard long tv_sec;
1078bfffbccSCorey Minyard long tv_nsec;
1088bfffbccSCorey Minyard };
1098bfffbccSCorey Minyard
1108bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1118bfffbccSCorey Minyard
1128bfffbccSCorey Minyard typedef struct IPMISel {
1138bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16];
1148bfffbccSCorey Minyard unsigned int next_free;
1158bfffbccSCorey Minyard long time_offset;
1168bfffbccSCorey Minyard uint16_t reservation;
1178bfffbccSCorey Minyard uint8_t last_addition[4];
1188bfffbccSCorey Minyard uint8_t last_clear[4];
1198bfffbccSCorey Minyard uint8_t overflow;
1208bfffbccSCorey Minyard } IPMISel;
1218bfffbccSCorey Minyard
1228bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1238bfffbccSCorey Minyard
1248bfffbccSCorey Minyard typedef struct IPMISdr {
1258bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE];
1268bfffbccSCorey Minyard unsigned int next_free;
1278bfffbccSCorey Minyard uint16_t next_rec_id;
1288bfffbccSCorey Minyard uint16_t reservation;
1298bfffbccSCorey Minyard uint8_t last_addition[4];
1308bfffbccSCorey Minyard uint8_t last_clear[4];
1318bfffbccSCorey Minyard uint8_t overflow;
1328bfffbccSCorey Minyard } IPMISdr;
1338bfffbccSCorey Minyard
134540c07d3SCédric Le Goater typedef struct IPMIFru {
135540c07d3SCédric Le Goater char *filename;
136540c07d3SCédric Le Goater unsigned int nentries;
137540c07d3SCédric Le Goater uint16_t areasize;
138540c07d3SCédric Le Goater uint8_t *data;
139540c07d3SCédric Le Goater } IPMIFru;
140540c07d3SCédric Le Goater
1418bfffbccSCorey Minyard typedef struct IPMISensor {
1428bfffbccSCorey Minyard uint8_t status;
1438bfffbccSCorey Minyard uint8_t reading;
1448bfffbccSCorey Minyard uint16_t states_suppt;
1458bfffbccSCorey Minyard uint16_t assert_suppt;
1468bfffbccSCorey Minyard uint16_t deassert_suppt;
1478bfffbccSCorey Minyard uint16_t states;
1488bfffbccSCorey Minyard uint16_t assert_states;
1498bfffbccSCorey Minyard uint16_t deassert_states;
1508bfffbccSCorey Minyard uint16_t assert_enable;
1518bfffbccSCorey Minyard uint16_t deassert_enable;
1528bfffbccSCorey Minyard uint8_t sensor_type;
1538bfffbccSCorey Minyard uint8_t evt_reading_type_code;
1548bfffbccSCorey Minyard } IPMISensor;
1558bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
1568bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
1578bfffbccSCorey Minyard !!(v))
1588bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
1598bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
1608bfffbccSCorey Minyard ((!!(v)) << 6))
1618bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
1628bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
1638bfffbccSCorey Minyard ((!!(v)) << 7))
1648bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
1658bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1668bfffbccSCorey Minyard (v & 0xc0))
1678bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1688bfffbccSCorey Minyard
1698bfffbccSCorey Minyard #define MAX_SENSORS 20
1708bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1718bfffbccSCorey Minyard
1728bfffbccSCorey Minyard #define MAX_NETFNS 64
1734f298a4bSCédric Le Goater
1748bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1758bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1768bfffbccSCorey Minyard uint8_t len;
1778bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE];
1788bfffbccSCorey Minyard } IPMIRcvBufEntry;
1798bfffbccSCorey Minyard
1808bfffbccSCorey Minyard struct IPMIBmcSim {
1818bfffbccSCorey Minyard IPMIBmc parent;
1828bfffbccSCorey Minyard
1838bfffbccSCorey Minyard QEMUTimer *timer;
1848bfffbccSCorey Minyard
1858bfffbccSCorey Minyard uint8_t bmc_global_enables;
1868bfffbccSCorey Minyard uint8_t msg_flags;
1878bfffbccSCorey Minyard
1888bfffbccSCorey Minyard bool watchdog_initialized;
1898bfffbccSCorey Minyard uint8_t watchdog_use;
1908bfffbccSCorey Minyard uint8_t watchdog_action;
1918bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */
1929e744990SJinhua Cao uint8_t watchdog_expired;
1938bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */
1948bfffbccSCorey Minyard
1958bfffbccSCorey Minyard bool watchdog_running;
1968bfffbccSCorey Minyard bool watchdog_preaction_ran;
1978bfffbccSCorey Minyard int64_t watchdog_expiry;
1988bfffbccSCorey Minyard
1998bfffbccSCorey Minyard uint8_t device_id;
2008bfffbccSCorey Minyard uint8_t ipmi_version;
2018bfffbccSCorey Minyard uint8_t device_rev;
2028bfffbccSCorey Minyard uint8_t fwrev1;
2038bfffbccSCorey Minyard uint8_t fwrev2;
20420b23364SCorey Minyard uint32_t mfg_id;
20520b23364SCorey Minyard uint16_t product_id;
2068bfffbccSCorey Minyard
207b7088392SCédric Le Goater uint8_t restart_cause;
208b7088392SCédric Le Goater
20952ba4d50SCédric Le Goater uint8_t acpi_power_state[2];
2107b0cd78bSCorey Minyard QemuUUID uuid;
21152ba4d50SCédric Le Goater
2128bfffbccSCorey Minyard IPMISel sel;
2138bfffbccSCorey Minyard IPMISdr sdr;
214540c07d3SCédric Le Goater IPMIFru fru;
2158bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS];
2168c6fd7f3SCédric Le Goater char *sdr_filename;
2178bfffbccSCorey Minyard
2188bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */
2198bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2];
2208bfffbccSCorey Minyard
2218bfffbccSCorey Minyard /* We allow one event in the buffer */
2228bfffbccSCorey Minyard uint8_t evtbuf[16];
2238bfffbccSCorey Minyard
2248bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2258bfffbccSCorey Minyard };
2268bfffbccSCorey Minyard
2278bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2318bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2328bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2338bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2348bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2358bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2368bfffbccSCorey Minyard
2378bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
2388bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1
2398bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2
2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3
2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2428bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2438bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2448bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2458bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2468bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT))
2478bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2488bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2498bfffbccSCorey Minyard
2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
2658bfffbccSCorey Minyard
266a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2678bfffbccSCorey Minyard
rsp_buffer_pushmore(RspBuffer * rsp,uint8_t * bytes,unsigned int n)268a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
269a580d820SCédric Le Goater unsigned int n)
270a580d820SCédric Le Goater {
271a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) {
2726acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
273a580d820SCédric Le Goater return;
274a580d820SCédric Le Goater }
275a580d820SCédric Le Goater
276a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n);
277a580d820SCédric Le Goater rsp->len += n;
278a580d820SCédric Le Goater }
2798bfffbccSCorey Minyard
2808bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2818bfffbccSCorey Minyard
ipmi_gettime(struct ipmi_time * time)2828bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2838bfffbccSCorey Minyard {
2848bfffbccSCorey Minyard int64_t stime;
2858bfffbccSCorey Minyard
2868bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2878bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL;
2888bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL;
2898bfffbccSCorey Minyard }
2908bfffbccSCorey Minyard
ipmi_getmonotime(void)2918bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2928bfffbccSCorey Minyard {
2938bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2948bfffbccSCorey Minyard }
2958bfffbccSCorey Minyard
ipmi_timeout(void * opaque)2968bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2978bfffbccSCorey Minyard {
2988bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque;
2998bfffbccSCorey Minyard
3008bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs);
3018bfffbccSCorey Minyard }
3028bfffbccSCorey Minyard
set_timestamp(IPMIBmcSim * ibs,uint8_t * ts)3038bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3048bfffbccSCorey Minyard {
3058bfffbccSCorey Minyard unsigned int val;
3068bfffbccSCorey Minyard struct ipmi_time now;
3078bfffbccSCorey Minyard
3088bfffbccSCorey Minyard ipmi_gettime(&now);
3098bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset;
3108bfffbccSCorey Minyard ts[0] = val & 0xff;
3118bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff;
3128bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff;
3138bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff;
3148bfffbccSCorey Minyard }
3158bfffbccSCorey Minyard
sdr_inc_reservation(IPMISdr * sdr)3168bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3178bfffbccSCorey Minyard {
3188bfffbccSCorey Minyard sdr->reservation++;
3198bfffbccSCorey Minyard if (sdr->reservation == 0) {
3208bfffbccSCorey Minyard sdr->reservation = 1;
3218bfffbccSCorey Minyard }
3228bfffbccSCorey Minyard }
3238bfffbccSCorey Minyard
sdr_add_entry(IPMIBmcSim * ibs,const struct ipmi_sdr_header * sdrh_entry,unsigned int len,uint16_t * recid)324a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
325a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry,
3268bfffbccSCorey Minyard unsigned int len, uint16_t *recid)
3278bfffbccSCorey Minyard {
328a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh =
329a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
330a2295f0aSCédric Le Goater
331a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3328bfffbccSCorey Minyard return 1;
3338bfffbccSCorey Minyard }
3348bfffbccSCorey Minyard
335a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) {
3368bfffbccSCorey Minyard return 1;
3378bfffbccSCorey Minyard }
3388bfffbccSCorey Minyard
3398bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3408bfffbccSCorey Minyard ibs->sdr.overflow = 1;
3418bfffbccSCorey Minyard return 1;
3428bfffbccSCorey Minyard }
3438bfffbccSCorey Minyard
344a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len);
345a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
346a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
347a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3488bfffbccSCorey Minyard
3498bfffbccSCorey Minyard if (recid) {
3508bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id;
3518bfffbccSCorey Minyard }
3528bfffbccSCorey Minyard ibs->sdr.next_rec_id++;
3538bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition);
3548bfffbccSCorey Minyard ibs->sdr.next_free += len;
3558bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr);
3568bfffbccSCorey Minyard return 0;
3578bfffbccSCorey Minyard }
3588bfffbccSCorey Minyard
sdr_find_entry(IPMISdr * sdr,uint16_t recid,unsigned int * retpos,uint16_t * nextrec)3598bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3608bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec)
3618bfffbccSCorey Minyard {
3628bfffbccSCorey Minyard unsigned int pos = *retpos;
3638bfffbccSCorey Minyard
3648bfffbccSCorey Minyard while (pos < sdr->next_free) {
365a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh =
366a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos];
367a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh);
368a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3698bfffbccSCorey Minyard
3708bfffbccSCorey Minyard if (trec == recid) {
3718bfffbccSCorey Minyard if (nextrec) {
3728bfffbccSCorey Minyard if (nextpos >= sdr->next_free) {
3738bfffbccSCorey Minyard *nextrec = 0xffff;
3748bfffbccSCorey Minyard } else {
3758bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] |
3768bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8));
3778bfffbccSCorey Minyard }
3788bfffbccSCorey Minyard }
3798bfffbccSCorey Minyard *retpos = pos;
3808bfffbccSCorey Minyard return 0;
3818bfffbccSCorey Minyard }
3828bfffbccSCorey Minyard pos = nextpos;
3838bfffbccSCorey Minyard }
3848bfffbccSCorey Minyard return 1;
3858bfffbccSCorey Minyard }
3868bfffbccSCorey Minyard
ipmi_bmc_sdr_find(IPMIBmc * b,uint16_t recid,const struct ipmi_sdr_compact ** sdr,uint16_t * nextrec)3877fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
3887fabcdb9SCédric Le Goater const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
3897fabcdb9SCédric Le Goater
3907fabcdb9SCédric Le Goater {
3917fabcdb9SCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
3927fabcdb9SCédric Le Goater unsigned int pos;
3937fabcdb9SCédric Le Goater
3947fabcdb9SCédric Le Goater pos = 0;
3957fabcdb9SCédric Le Goater if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
3967fabcdb9SCédric Le Goater return -1;
3977fabcdb9SCédric Le Goater }
3987fabcdb9SCédric Le Goater
3997fabcdb9SCédric Le Goater *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4007fabcdb9SCédric Le Goater return 0;
4017fabcdb9SCédric Le Goater }
4027fabcdb9SCédric Le Goater
sel_inc_reservation(IPMISel * sel)4038bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4048bfffbccSCorey Minyard {
4058bfffbccSCorey Minyard sel->reservation++;
4068bfffbccSCorey Minyard if (sel->reservation == 0) {
4078bfffbccSCorey Minyard sel->reservation = 1;
4088bfffbccSCorey Minyard }
4098bfffbccSCorey Minyard }
4108bfffbccSCorey Minyard
4118bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
sel_add_event(IPMIBmcSim * ibs,uint8_t * event)4128bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4138bfffbccSCorey Minyard {
4149f7d1d92SCorey Minyard uint8_t ts[4];
4159f7d1d92SCorey Minyard
4168bfffbccSCorey Minyard event[0] = 0xff;
4178bfffbccSCorey Minyard event[1] = 0xff;
4189f7d1d92SCorey Minyard set_timestamp(ibs, ts);
4199f7d1d92SCorey Minyard if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4209f7d1d92SCorey Minyard memcpy(event + 3, ts, 4);
4219f7d1d92SCorey Minyard }
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;
4289f7d1d92SCorey Minyard memcpy(ibs->sel.last_addition, ts, 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
attn_set(IPMIBmcSim * ibs)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
attn_irq_enabled(IPMIBmcSim * ibs)4428bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4438bfffbccSCorey Minyard {
4448bc8af69SCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) &&
4458bc8af69SCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
4468bc8af69SCorey Minyard IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
4478bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4488bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4498bfffbccSCorey Minyard }
4508bfffbccSCorey Minyard
ipmi_bmc_gen_event(IPMIBmc * b,uint8_t * evt,bool log)451cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
452cd60d85eSCédric Le Goater {
453cd60d85eSCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
454cd60d85eSCédric Le Goater IPMIInterface *s = ibs->parent.intf;
455cd60d85eSCédric Le Goater IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
456cd60d85eSCédric Le Goater
457cd60d85eSCédric Le Goater if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
458cd60d85eSCédric Le Goater return;
459cd60d85eSCédric Le Goater }
460cd60d85eSCédric Le Goater
461cd60d85eSCédric Le Goater if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
462cd60d85eSCédric Le Goater sel_add_event(ibs, evt);
463cd60d85eSCédric Le Goater }
464cd60d85eSCédric Le Goater
465cd60d85eSCédric Le Goater if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
466cd60d85eSCédric Le Goater goto out;
467cd60d85eSCédric Le Goater }
468cd60d85eSCédric Le Goater
469cd60d85eSCédric Le Goater memcpy(ibs->evtbuf, evt, 16);
470cd60d85eSCédric Le Goater ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
471cd60d85eSCédric Le Goater k->set_atn(s, 1, attn_irq_enabled(ibs));
472cd60d85eSCédric Le Goater out:
473cd60d85eSCédric Le Goater return;
474cd60d85eSCédric Le Goater }
gen_event(IPMIBmcSim * ibs,unsigned int sens_num,uint8_t deassert,uint8_t evd1,uint8_t evd2,uint8_t evd3)4758bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4768bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3)
4778bfffbccSCorey Minyard {
4788bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
4798bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4808bfffbccSCorey Minyard uint8_t evt[16];
4818bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num;
4828bfffbccSCorey Minyard
4838bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4848bfffbccSCorey Minyard return;
4858bfffbccSCorey Minyard }
4868bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4878bfffbccSCorey Minyard return;
4888bfffbccSCorey Minyard }
4898bfffbccSCorey Minyard
4908bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */
4918bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr;
4928bfffbccSCorey Minyard evt[8] = 0;
4938bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */
4948bfffbccSCorey Minyard evt[10] = sens->sensor_type;
4958bfffbccSCorey Minyard evt[11] = sens_num;
4968bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4978bfffbccSCorey Minyard evt[13] = evd1;
4988bfffbccSCorey Minyard evt[14] = evd2;
4998bfffbccSCorey Minyard evt[15] = evd3;
5008bfffbccSCorey Minyard
5018bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5028bfffbccSCorey Minyard sel_add_event(ibs, evt);
5038bfffbccSCorey Minyard }
5048bfffbccSCorey Minyard
5058bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
506d13ada5dSCédric Le Goater return;
5078bfffbccSCorey Minyard }
5088bfffbccSCorey Minyard
5098bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16);
5108bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5118bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs));
5128bfffbccSCorey Minyard }
5138bfffbccSCorey Minyard
sensor_set_discrete_bit(IPMIBmcSim * ibs,unsigned int sensor,unsigned int bit,unsigned int val,uint8_t evd1,uint8_t evd2,uint8_t evd3)5148bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5158bfffbccSCorey Minyard unsigned int bit, unsigned int val,
5168bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3)
5178bfffbccSCorey Minyard {
5188bfffbccSCorey Minyard IPMISensor *sens;
5198bfffbccSCorey Minyard uint16_t mask;
5208bfffbccSCorey Minyard
5218bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) {
5228bfffbccSCorey Minyard return;
5238bfffbccSCorey Minyard }
5248bfffbccSCorey Minyard if (bit >= 16) {
5258bfffbccSCorey Minyard return;
5268bfffbccSCorey Minyard }
5278bfffbccSCorey Minyard
5288bfffbccSCorey Minyard mask = (1 << bit);
5298bfffbccSCorey Minyard sens = ibs->sensors + sensor;
5308bfffbccSCorey Minyard if (val) {
5318bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt;
5328bfffbccSCorey Minyard if (sens->assert_states & mask) {
5338bfffbccSCorey Minyard return; /* Already asserted */
5348bfffbccSCorey Minyard }
5358bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt;
5368bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) {
5378bfffbccSCorey Minyard /* Send an event on assert */
5388bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5398bfffbccSCorey Minyard }
5408bfffbccSCorey Minyard } else {
5418bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt);
5428bfffbccSCorey Minyard if (sens->deassert_states & mask) {
5438bfffbccSCorey Minyard return; /* Already deasserted */
5448bfffbccSCorey Minyard }
5458bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt;
5468bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) {
5478bfffbccSCorey Minyard /* Send an event on deassert */
5488bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5498bfffbccSCorey Minyard }
5508bfffbccSCorey Minyard }
5518bfffbccSCorey Minyard }
5528bfffbccSCorey Minyard
ipmi_init_sensors_from_sdrs(IPMIBmcSim * s)5538bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5548bfffbccSCorey Minyard {
5558bfffbccSCorey Minyard unsigned int i, pos;
5568bfffbccSCorey Minyard IPMISensor *sens;
5578bfffbccSCorey Minyard
5588bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) {
5598bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens));
5608bfffbccSCorey Minyard }
5618bfffbccSCorey Minyard
5628bfffbccSCorey Minyard pos = 0;
5638bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
564a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr =
565a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
566a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length;
5678bfffbccSCorey Minyard
5688bfffbccSCorey Minyard if (len < 20) {
5698bfffbccSCorey Minyard continue;
5708bfffbccSCorey Minyard }
571a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5728bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */
5738bfffbccSCorey Minyard }
5748bfffbccSCorey Minyard
57573d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) {
5768bfffbccSCorey Minyard continue;
5778bfffbccSCorey Minyard }
578a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number;
5798bfffbccSCorey Minyard
5808bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1);
581a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
582a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
583a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
584a2295f0aSCédric Le Goater sens->deassert_suppt =
585a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
586a2295f0aSCédric Le Goater sens->states_suppt =
587a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
588a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type;
589a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5908bfffbccSCorey Minyard
5918bfffbccSCorey Minyard /* Enable all the events that are supported. */
5928bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt;
5938bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt;
5948bfffbccSCorey Minyard }
5958bfffbccSCorey Minyard }
5968bfffbccSCorey Minyard
ipmi_sim_register_netfn(IPMIBmcSim * s,unsigned int netfn,const IPMINetfn * netfnd)597ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5988bfffbccSCorey Minyard const IPMINetfn *netfnd)
5998bfffbccSCorey Minyard {
60093a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6018bfffbccSCorey Minyard return -1;
6028bfffbccSCorey Minyard }
6038bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd;
6048bfffbccSCorey Minyard return 0;
6058bfffbccSCorey Minyard }
6068bfffbccSCorey Minyard
ipmi_get_handler(IPMIBmcSim * ibs,unsigned int netfn,unsigned int cmd)6074f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6084f298a4bSCédric Le Goater unsigned int netfn,
6094f298a4bSCédric Le Goater unsigned int cmd)
6104f298a4bSCédric Le Goater {
6114f298a4bSCédric Le Goater const IPMICmdHandler *hdl;
6124f298a4bSCédric Le Goater
6134f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6144f298a4bSCédric Le Goater return NULL;
6154f298a4bSCédric Le Goater }
6164f298a4bSCédric Le Goater
6174f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6184f298a4bSCédric Le Goater return NULL;
6194f298a4bSCédric Le Goater }
6204f298a4bSCédric Le Goater
6214f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6224f298a4bSCédric Le Goater if (!hdl->cmd_handler) {
6234f298a4bSCédric Le Goater return NULL;
6244f298a4bSCédric Le Goater }
6254f298a4bSCédric Le Goater
6264f298a4bSCédric Le Goater return hdl;
6274f298a4bSCédric Le Goater }
6284f298a4bSCédric Le Goater
next_timeout(IPMIBmcSim * ibs)6298bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6308bfffbccSCorey Minyard {
6318bfffbccSCorey Minyard int64_t next;
6328bfffbccSCorey Minyard if (ibs->watchdog_running) {
6338bfffbccSCorey Minyard next = ibs->watchdog_expiry;
6348bfffbccSCorey Minyard } else {
6358bfffbccSCorey Minyard /* Wait a minute */
6368bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL;
6378bfffbccSCorey Minyard }
6388bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next);
6398bfffbccSCorey Minyard }
6408bfffbccSCorey Minyard
ipmi_sim_handle_command(IPMIBmc * b,uint8_t * cmd,unsigned int cmd_len,unsigned int max_cmd_len,uint8_t msg_id)6418bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6428bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
6438bfffbccSCorey Minyard unsigned int max_cmd_len,
6448bfffbccSCorey Minyard uint8_t msg_id)
6458bfffbccSCorey Minyard {
6468bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6478bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
6488bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6494f298a4bSCédric Le Goater const IPMICmdHandler *hdl;
650a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6518bfffbccSCorey Minyard
6528bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */
6538bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */
654a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) {
6556acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
656d13ada5dSCédric Le Goater goto out;
657d13ada5dSCédric Le Goater }
658d13ada5dSCédric Le Goater
659a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04);
660a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]);
661a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */
6628bfffbccSCorey Minyard
6638bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */
6648bfffbccSCorey Minyard if (cmd_len < 2) {
6656acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6668bfffbccSCorey Minyard goto out;
6678bfffbccSCorey Minyard }
6688bfffbccSCorey Minyard if (cmd_len > max_cmd_len) {
6696acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6708bfffbccSCorey Minyard goto out;
6718bfffbccSCorey Minyard }
6728bfffbccSCorey Minyard
6738bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) {
6748bfffbccSCorey Minyard /* Only have stuff on LUN 0 */
6756acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6768bfffbccSCorey Minyard goto out;
6778bfffbccSCorey Minyard }
6788bfffbccSCorey Minyard
6794f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6804f298a4bSCédric Le Goater if (!hdl) {
6816acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6828bfffbccSCorey Minyard goto out;
6838bfffbccSCorey Minyard }
6848bfffbccSCorey Minyard
6854f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) {
6866acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6874f298a4bSCédric Le Goater goto out;
6884f298a4bSCédric Le Goater }
6894f298a4bSCédric Le Goater
690a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6918bfffbccSCorey Minyard
6928bfffbccSCorey Minyard out:
693a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6948bfffbccSCorey Minyard
6958bfffbccSCorey Minyard next_timeout(ibs);
6968bfffbccSCorey Minyard }
6978bfffbccSCorey Minyard
ipmi_sim_handle_timeout(IPMIBmcSim * ibs)6988bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
6998bfffbccSCorey Minyard {
7008bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
7018bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7028bfffbccSCorey Minyard
7038bfffbccSCorey Minyard if (!ibs->watchdog_running) {
7048bfffbccSCorey Minyard goto out;
7058bfffbccSCorey Minyard }
7068bfffbccSCorey Minyard
7078bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) {
7088bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7098bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI:
7108bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7118bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0);
7128bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7138bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff);
7148bfffbccSCorey Minyard break;
7158bfffbccSCorey Minyard
7168bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7178bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7188bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs));
7198bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
7208bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff);
7218bfffbccSCorey Minyard break;
7228bfffbccSCorey Minyard
7238bfffbccSCorey Minyard default:
7248bfffbccSCorey Minyard goto do_full_expiry;
7258bfffbccSCorey Minyard }
7268bfffbccSCorey Minyard
7278bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1;
7288bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */
7298bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime();
7308bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7318bfffbccSCorey Minyard goto out;
7328bfffbccSCorey Minyard }
7338bfffbccSCorey Minyard
7348bfffbccSCorey Minyard do_full_expiry:
7358bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7368bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7378bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7388bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE:
7398bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
7408bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff);
7418bfffbccSCorey Minyard break;
7428bfffbccSCorey Minyard
7438bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET:
7448bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
7458bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff);
7468bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7478bfffbccSCorey Minyard break;
7488bfffbccSCorey Minyard
7498bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7508bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7518bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff);
7528bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7538bfffbccSCorey Minyard break;
7548bfffbccSCorey Minyard
7558bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7568bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
7578bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff);
7588bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7598bfffbccSCorey Minyard break;
7608bfffbccSCorey Minyard }
7618bfffbccSCorey Minyard
7628bfffbccSCorey Minyard out:
7638bfffbccSCorey Minyard next_timeout(ibs);
7648bfffbccSCorey Minyard }
7658bfffbccSCorey Minyard
chassis_capabilities(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7668bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7678bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
768a580d820SCédric Le Goater RspBuffer *rsp)
7698bfffbccSCorey Minyard {
770a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
771a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
772a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
773a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
774a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
7758bfffbccSCorey Minyard }
7768bfffbccSCorey Minyard
chassis_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7778bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7788bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
779a580d820SCédric Le Goater RspBuffer *rsp)
7808bfffbccSCorey Minyard {
781a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
782a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
783a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
784a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
7858bfffbccSCorey Minyard }
7868bfffbccSCorey Minyard
chassis_control(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7878bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
789a580d820SCédric Le Goater RspBuffer *rsp)
7908bfffbccSCorey Minyard {
7918bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
7928bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
7938bfffbccSCorey Minyard
7948bfffbccSCorey Minyard switch (cmd[2] & 0xf) {
7958bfffbccSCorey Minyard case 0: /* power down */
7966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
7978bfffbccSCorey Minyard break;
7988bfffbccSCorey Minyard case 1: /* power up */
7996acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8008bfffbccSCorey Minyard break;
8018bfffbccSCorey Minyard case 2: /* power cycle */
8026acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8038bfffbccSCorey Minyard break;
8048bfffbccSCorey Minyard case 3: /* hard reset */
8056acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8068bfffbccSCorey Minyard break;
8078bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */
8086acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8098bfffbccSCorey Minyard break;
8108bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */
8116acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s,
8126acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8138bfffbccSCorey Minyard break;
8148bfffbccSCorey Minyard default:
8156acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8168bfffbccSCorey Minyard return;
8178bfffbccSCorey Minyard }
818d13ada5dSCédric Le Goater }
8198bfffbccSCorey Minyard
chassis_get_sys_restart_cause(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)820b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
821b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
822a580d820SCédric Le Goater RspBuffer *rsp)
823a580d820SCédric Le Goater
824b7088392SCédric Le Goater {
825a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
826a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */
827b7088392SCédric Le Goater }
828b7088392SCédric Le Goater
get_device_id(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8298bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
831a580d820SCédric Le Goater RspBuffer *rsp)
8328bfffbccSCorey Minyard {
833a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id);
834a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf);
835a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
836a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2);
837a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version);
838a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
83920b23364SCorey Minyard rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
84020b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
84120b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
84220b23364SCorey Minyard rsp_buffer_push(rsp, ibs->product_id & 0xff);
84320b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8448bfffbccSCorey Minyard }
8458bfffbccSCorey Minyard
set_global_enables(IPMIBmcSim * ibs,uint8_t val)8468bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8478bfffbccSCorey Minyard {
8488bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8498bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8508bfffbccSCorey Minyard bool irqs_on;
8518bfffbccSCorey Minyard
8528bfffbccSCorey Minyard ibs->bmc_global_enables = val;
8538bfffbccSCorey Minyard
8548bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8558bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8568bfffbccSCorey Minyard
8578bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on);
8588bfffbccSCorey Minyard }
8598bfffbccSCorey Minyard
cold_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8608bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
862a580d820SCédric Le Goater RspBuffer *rsp)
8638bfffbccSCorey Minyard {
8648bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8658bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8668bfffbccSCorey Minyard
8678bfffbccSCorey Minyard /* Disable all interrupts */
8688bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8698bfffbccSCorey Minyard
8708bfffbccSCorey Minyard if (k->reset) {
8718bfffbccSCorey Minyard k->reset(s, true);
8728bfffbccSCorey Minyard }
8738bfffbccSCorey Minyard }
8748bfffbccSCorey Minyard
warm_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8758bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8768bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
877a580d820SCédric Le Goater RspBuffer *rsp)
8788bfffbccSCorey Minyard {
8798bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8808bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8818bfffbccSCorey Minyard
8828bfffbccSCorey Minyard if (k->reset) {
8838bfffbccSCorey Minyard k->reset(s, false);
8848bfffbccSCorey Minyard }
8858bfffbccSCorey Minyard }
set_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)88652ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
88752ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
888a580d820SCédric Le Goater RspBuffer *rsp)
88952ba4d50SCédric Le Goater {
89052ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2];
89152ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3];
89252ba4d50SCédric Le Goater }
89352ba4d50SCédric Le Goater
get_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)89452ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
89552ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
896a580d820SCédric Le Goater RspBuffer *rsp)
89752ba4d50SCédric Le Goater {
898a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
899a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
90052ba4d50SCédric Le Goater }
90152ba4d50SCédric Le Goater
get_device_guid(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)90252ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
90352ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
904a580d820SCédric Le Goater RspBuffer *rsp)
90552ba4d50SCédric Le Goater {
90652ba4d50SCédric Le Goater unsigned int i;
90752ba4d50SCédric Le Goater
9087b0cd78bSCorey Minyard /* An uninitialized uuid is all zeros, use that to know if it is set. */
90952ba4d50SCédric Le Goater for (i = 0; i < 16; i++) {
9107b0cd78bSCorey Minyard if (ibs->uuid.data[i]) {
9117b0cd78bSCorey Minyard goto uuid_set;
9127b0cd78bSCorey Minyard }
9137b0cd78bSCorey Minyard }
9147b0cd78bSCorey Minyard /* No uuid is set, return an error. */
9157b0cd78bSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
9167b0cd78bSCorey Minyard return;
9177b0cd78bSCorey Minyard
9187b0cd78bSCorey Minyard uuid_set:
9197b0cd78bSCorey Minyard for (i = 0; i < 16; i++) {
9207b0cd78bSCorey Minyard rsp_buffer_push(rsp, ibs->uuid.data[i]);
92152ba4d50SCédric Le Goater }
92252ba4d50SCédric Le Goater }
9238bfffbccSCorey Minyard
set_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9248bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9258bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
926a580d820SCédric Le Goater RspBuffer *rsp)
9278bfffbccSCorey Minyard {
9288bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]);
9298bfffbccSCorey Minyard }
9308bfffbccSCorey Minyard
get_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9318bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9328bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
933a580d820SCédric Le Goater RspBuffer *rsp)
9348bfffbccSCorey Minyard {
935a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables);
9368bfffbccSCorey Minyard }
9378bfffbccSCorey Minyard
clr_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9388bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9398bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
940a580d820SCédric Le Goater RspBuffer *rsp)
9418bfffbccSCorey Minyard {
9428bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
9438bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9448bfffbccSCorey Minyard
9458bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2];
9468bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9478bfffbccSCorey Minyard }
9488bfffbccSCorey Minyard
get_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9498bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
951a580d820SCédric Le Goater RspBuffer *rsp)
9528bfffbccSCorey Minyard {
953a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags);
9548bfffbccSCorey Minyard }
9558bfffbccSCorey Minyard
read_evt_msg_buf(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9568bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9578bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
958a580d820SCédric Le Goater RspBuffer *rsp)
9598bfffbccSCorey Minyard {
9608bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
9618bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9628bfffbccSCorey Minyard unsigned int i;
9638bfffbccSCorey Minyard
9648bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9656acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80);
966d13ada5dSCédric Le Goater return;
9678bfffbccSCorey Minyard }
9688bfffbccSCorey Minyard for (i = 0; i < 16; i++) {
969a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]);
9708bfffbccSCorey Minyard }
9718bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9728bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9738bfffbccSCorey Minyard }
9748bfffbccSCorey Minyard
get_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9758bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9768bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
977a580d820SCédric Le Goater RspBuffer *rsp)
9788bfffbccSCorey Minyard {
9798bfffbccSCorey Minyard IPMIRcvBufEntry *msg;
9808bfffbccSCorey Minyard
9818bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9826acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
9838bfffbccSCorey Minyard goto out;
9848bfffbccSCorey Minyard }
985a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */
9868bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs);
987a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len);
9888bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
9898bfffbccSCorey Minyard g_free(msg);
9908bfffbccSCorey Minyard
9918bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9928bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
9938bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9948bfffbccSCorey Minyard
9958bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
9968bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9978bfffbccSCorey Minyard }
9988bfffbccSCorey Minyard
9998bfffbccSCorey Minyard out:
10008bfffbccSCorey Minyard return;
10018bfffbccSCorey Minyard }
10028bfffbccSCorey Minyard
10038bfffbccSCorey Minyard static unsigned char
ipmb_checksum(unsigned char * data,int size,unsigned char csum)10048bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10058bfffbccSCorey Minyard {
10068bfffbccSCorey Minyard for (; size > 0; size--, data++) {
10078bfffbccSCorey Minyard csum += *data;
10088bfffbccSCorey Minyard }
10098bfffbccSCorey Minyard
10108bfffbccSCorey Minyard return -csum;
10118bfffbccSCorey Minyard }
10128bfffbccSCorey Minyard
send_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)10138bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10148bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1015a580d820SCédric Le Goater RspBuffer *rsp)
10168bfffbccSCorey Minyard {
10178bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
10188bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10198bfffbccSCorey Minyard IPMIRcvBufEntry *msg;
10208bfffbccSCorey Minyard uint8_t *buf;
10218bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq;
10228bfffbccSCorey Minyard
10238bfffbccSCorey Minyard if (cmd[2] != 0) {
10248bfffbccSCorey Minyard /* We only handle channel 0 with no options */
10256acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1026d13ada5dSCédric Le Goater return;
10278bfffbccSCorey Minyard }
10288bfffbccSCorey Minyard
10294f298a4bSCédric Le Goater if (cmd_len < 10) {
10306acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10314f298a4bSCédric Le Goater return;
10324f298a4bSCédric Le Goater }
10334f298a4bSCédric Le Goater
10348bfffbccSCorey Minyard if (cmd[3] != 0x40) {
10358bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */
10366acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1037d13ada5dSCédric Le Goater return;
10388bfffbccSCorey Minyard }
10398bfffbccSCorey Minyard
10408bfffbccSCorey Minyard cmd += 3; /* Skip the header. */
10418bfffbccSCorey Minyard cmd_len -= 3;
10428bfffbccSCorey Minyard
10438bfffbccSCorey Minyard /*
10448bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will
10458bfffbccSCorey Minyard * be returned in the response.
10468bfffbccSCorey Minyard */
10478bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10488bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */
1049d13ada5dSCédric Le Goater return; /* No response */
10508bfffbccSCorey Minyard }
10518bfffbccSCorey Minyard
10528bfffbccSCorey Minyard netfn = cmd[1] >> 2;
10538bfffbccSCorey Minyard rqLun = cmd[4] & 0x3;
10548bfffbccSCorey Minyard rsLun = cmd[1] & 0x3;
10558bfffbccSCorey Minyard rqSeq = cmd[4] >> 2;
10568bfffbccSCorey Minyard
10578bfffbccSCorey Minyard if (rqLun != 2) {
10588bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */
1059d13ada5dSCédric Le Goater return;
10608bfffbccSCorey Minyard }
10618bfffbccSCorey Minyard
10628bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg));
10638bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10648bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10658bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */
10668bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun;
10678bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */
10688bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */
10698bfffbccSCorey Minyard msg->len = 6;
10708bfffbccSCorey Minyard
10718bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10728bfffbccSCorey Minyard /* Not a command we handle. */
10738bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD;
10748bfffbccSCorey Minyard goto end_msg;
10758bfffbccSCorey Minyard }
10768bfffbccSCorey Minyard
10778bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */
10788bfffbccSCorey Minyard buf[0] = 0;
10798bfffbccSCorey Minyard buf[1] = 0;
10808bfffbccSCorey Minyard buf[2] = 0;
10818bfffbccSCorey Minyard buf[3] = 0;
10828bfffbccSCorey Minyard buf[4] = 0x51;
10838bfffbccSCorey Minyard buf[5] = 0;
10848bfffbccSCorey Minyard buf[6] = 0;
10858bfffbccSCorey Minyard buf[7] = 0;
10868bfffbccSCorey Minyard buf[8] = 0;
10878bfffbccSCorey Minyard buf[9] = 0;
10888bfffbccSCorey Minyard buf[10] = 0;
10898bfffbccSCorey Minyard msg->len += 11;
10908bfffbccSCorey Minyard
10918bfffbccSCorey Minyard end_msg:
10928bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
10938bfffbccSCorey Minyard msg->len++;
10948bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
10958bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10968bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs));
10978bfffbccSCorey Minyard }
10988bfffbccSCorey Minyard
do_watchdog_reset(IPMIBmcSim * ibs)10998bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11008bfffbccSCorey Minyard {
11018bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11028bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) {
11038bfffbccSCorey Minyard ibs->watchdog_running = 0;
11048bfffbccSCorey Minyard return;
11058bfffbccSCorey Minyard }
11068bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0;
11078bfffbccSCorey Minyard
11088bfffbccSCorey Minyard
11098bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */
11108bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime();
11118bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11128bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11138bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11148bfffbccSCorey Minyard }
11158bfffbccSCorey Minyard ibs->watchdog_running = 1;
11168bfffbccSCorey Minyard }
11178bfffbccSCorey Minyard
reset_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11188bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11198bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1120a580d820SCédric Le Goater RspBuffer *rsp)
11218bfffbccSCorey Minyard {
11228bfffbccSCorey Minyard if (!ibs->watchdog_initialized) {
11236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80);
1124d13ada5dSCédric Le Goater return;
11258bfffbccSCorey Minyard }
11268bfffbccSCorey Minyard do_watchdog_reset(ibs);
11278bfffbccSCorey Minyard }
11288bfffbccSCorey Minyard
set_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11298bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1131a580d820SCédric Le Goater RspBuffer *rsp)
11328bfffbccSCorey Minyard {
11338bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
11348bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11358bfffbccSCorey Minyard unsigned int val;
11368bfffbccSCorey Minyard
11378bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */
11388bfffbccSCorey Minyard if (val == 0 || val > 5) {
11396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1140d13ada5dSCédric Le Goater return;
11418bfffbccSCorey Minyard }
11428bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */
11438bfffbccSCorey Minyard switch (val) {
11448bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE:
11458bfffbccSCorey Minyard break;
11468bfffbccSCorey Minyard
11478bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET:
11486acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11498bfffbccSCorey Minyard break;
11508bfffbccSCorey Minyard
11518bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11526acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11538bfffbccSCorey Minyard break;
11548bfffbccSCorey Minyard
11558bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11566acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11578bfffbccSCorey Minyard break;
11588bfffbccSCorey Minyard
11598bfffbccSCorey Minyard default:
11606acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11618bfffbccSCorey Minyard }
1162a580d820SCédric Le Goater if (rsp->buffer[2]) {
11636acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1164d13ada5dSCédric Le Goater return;
11658bfffbccSCorey Minyard }
11668bfffbccSCorey Minyard
11678bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11688bfffbccSCorey Minyard switch (val) {
11698bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11708bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE:
11718bfffbccSCorey Minyard break;
11728bfffbccSCorey Minyard
11738bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI:
11746af94767SCorey Minyard if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11758bfffbccSCorey Minyard /* NMI not supported. */
11766acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1177d13ada5dSCédric Le Goater return;
11788bfffbccSCorey Minyard }
117937eebb86SCorey Minyard break;
118037eebb86SCorey Minyard
11818bfffbccSCorey Minyard default:
11828bfffbccSCorey Minyard /* We don't support PRE_SMI */
11836acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1184d13ada5dSCédric Le Goater return;
11858bfffbccSCorey Minyard }
11868bfffbccSCorey Minyard
11878bfffbccSCorey Minyard ibs->watchdog_initialized = 1;
11888bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
11898bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
11908bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4];
11918bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5];
11928bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
11938bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
11948bfffbccSCorey Minyard do_watchdog_reset(ibs);
11958bfffbccSCorey Minyard } else {
11968bfffbccSCorey Minyard ibs->watchdog_running = 0;
11978bfffbccSCorey Minyard }
11988bfffbccSCorey Minyard }
11998bfffbccSCorey Minyard
get_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12008bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12018bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1202a580d820SCédric Le Goater RspBuffer *rsp)
12038bfffbccSCorey Minyard {
1204a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use);
1205a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action);
1206a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1207a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired);
1208fb45770bSCorey Minyard rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1209fb45770bSCorey Minyard rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12108bfffbccSCorey Minyard if (ibs->watchdog_running) {
12118bfffbccSCorey Minyard long timeout;
12128bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12138bfffbccSCorey Minyard / 100000000);
1214a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff);
1215a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12168bfffbccSCorey Minyard } else {
1217a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
1218a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
12198bfffbccSCorey Minyard }
12208bfffbccSCorey Minyard }
12218bfffbccSCorey Minyard
get_sdr_rep_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12228bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12238bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1224a580d820SCédric Le Goater RspBuffer *rsp)
12258bfffbccSCorey Minyard {
12268bfffbccSCorey Minyard unsigned int i;
12278bfffbccSCorey Minyard
1228a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1229a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1230a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1231a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1232a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
12338bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1234a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
12358bfffbccSCorey Minyard }
12368bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1237a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
12388bfffbccSCorey Minyard }
12398bfffbccSCorey Minyard /* Only modal support, reserve supported */
1240a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
12418bfffbccSCorey Minyard }
12428bfffbccSCorey Minyard
reserve_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12438bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
12448bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1245a580d820SCédric Le Goater RspBuffer *rsp)
12468bfffbccSCorey Minyard {
1247a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1248a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
12498bfffbccSCorey Minyard }
12508bfffbccSCorey Minyard
get_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12518bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
12528bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1253a580d820SCédric Le Goater RspBuffer *rsp)
12548bfffbccSCorey Minyard {
12558bfffbccSCorey Minyard unsigned int pos;
12568bfffbccSCorey Minyard uint16_t nextrec;
1257a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh;
12588bfffbccSCorey Minyard
12598bfffbccSCorey Minyard if (cmd[6]) {
12607f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
12616acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
12627f996411SCédric Le Goater return;
12638bfffbccSCorey Minyard }
12647f996411SCédric Le Goater }
12657f996411SCédric Le Goater
12668bfffbccSCorey Minyard pos = 0;
12678bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
12688bfffbccSCorey Minyard &pos, &nextrec)) {
12696acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1270d13ada5dSCédric Le Goater return;
12718bfffbccSCorey Minyard }
1272a2295f0aSCédric Le Goater
1273a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1274a2295f0aSCédric Le Goater
1275a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) {
12766acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1277d13ada5dSCédric Le Goater return;
12788bfffbccSCorey Minyard }
12798bfffbccSCorey Minyard
1280a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff);
1281a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
12828bfffbccSCorey Minyard
12838bfffbccSCorey Minyard if (cmd[7] == 0xff) {
1284a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
12858bfffbccSCorey Minyard }
12868bfffbccSCorey Minyard
1287a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
12886acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1289d13ada5dSCédric Le Goater return;
12908bfffbccSCorey Minyard }
1291a580d820SCédric Le Goater
1292a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
12938bfffbccSCorey Minyard }
12948bfffbccSCorey Minyard
add_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12958bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
12968bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1297a580d820SCédric Le Goater RspBuffer *rsp)
12988bfffbccSCorey Minyard {
12998bfffbccSCorey Minyard uint16_t recid;
1300a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13018bfffbccSCorey Minyard
1302a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13036acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1304d13ada5dSCédric Le Goater return;
13058bfffbccSCorey Minyard }
1306a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff);
1307a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13088bfffbccSCorey Minyard }
13098bfffbccSCorey Minyard
clear_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13108bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13118bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1312a580d820SCédric Le Goater RspBuffer *rsp)
13138bfffbccSCorey Minyard {
13147f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13156acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13167f996411SCédric Le Goater return;
13177f996411SCédric Le Goater }
13187f996411SCédric Le Goater
13198bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13206acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1321d13ada5dSCédric Le Goater return;
13228bfffbccSCorey Minyard }
13238bfffbccSCorey Minyard if (cmd[7] == 0xaa) {
13248bfffbccSCorey Minyard ibs->sdr.next_free = 0;
13258bfffbccSCorey Minyard ibs->sdr.overflow = 0;
13268bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear);
1327a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
13288bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr);
13298bfffbccSCorey Minyard } else if (cmd[7] == 0) {
1330a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
13318bfffbccSCorey Minyard } else {
13326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
13338bfffbccSCorey Minyard return;
13348bfffbccSCorey Minyard }
1335d13ada5dSCédric Le Goater }
13368bfffbccSCorey Minyard
get_sel_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13378bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
13388bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1339a580d820SCédric Le Goater RspBuffer *rsp)
13408bfffbccSCorey Minyard {
13418bfffbccSCorey Minyard unsigned int i, val;
13428bfffbccSCorey Minyard
1343a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1344a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1345a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
13468bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1347a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff);
1348a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff);
13498bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1350a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
13518bfffbccSCorey Minyard }
13528bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1353a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
13548bfffbccSCorey Minyard }
13558bfffbccSCorey Minyard /* Only support Reserve SEL */
1356a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
13578bfffbccSCorey Minyard }
13588bfffbccSCorey Minyard
get_fru_area_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1359540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1360540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1361540c07d3SCédric Le Goater RspBuffer *rsp)
1362540c07d3SCédric Le Goater {
1363540c07d3SCédric Le Goater uint8_t fruid;
1364540c07d3SCédric Le Goater uint16_t fru_entry_size;
1365540c07d3SCédric Le Goater
1366540c07d3SCédric Le Goater fruid = cmd[2];
1367540c07d3SCédric Le Goater
1368540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) {
1369540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1370540c07d3SCédric Le Goater return;
1371540c07d3SCédric Le Goater }
1372540c07d3SCédric Le Goater
1373540c07d3SCédric Le Goater fru_entry_size = ibs->fru.areasize;
1374540c07d3SCédric Le Goater
1375540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size & 0xff);
1376540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1377540c07d3SCédric Le Goater rsp_buffer_push(rsp, 0x0);
1378540c07d3SCédric Le Goater }
1379540c07d3SCédric Le Goater
read_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1380540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1381540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1382540c07d3SCédric Le Goater RspBuffer *rsp)
1383540c07d3SCédric Le Goater {
1384540c07d3SCédric Le Goater uint8_t fruid;
1385540c07d3SCédric Le Goater uint16_t offset;
1386540c07d3SCédric Le Goater int i;
1387540c07d3SCédric Le Goater uint8_t *fru_entry;
1388540c07d3SCédric Le Goater unsigned int count;
1389540c07d3SCédric Le Goater
1390540c07d3SCédric Le Goater fruid = cmd[2];
1391540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8);
1392540c07d3SCédric Le Goater
1393540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) {
1394540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1395540c07d3SCédric Le Goater return;
1396540c07d3SCédric Le Goater }
1397540c07d3SCédric Le Goater
1398540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) {
1399540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1400540c07d3SCédric Le Goater return;
1401540c07d3SCédric Le Goater }
1402540c07d3SCédric Le Goater
1403540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1404540c07d3SCédric Le Goater
1405540c07d3SCédric Le Goater count = MIN(cmd[5], ibs->fru.areasize - offset);
1406540c07d3SCédric Le Goater
1407540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff);
1408540c07d3SCédric Le Goater for (i = 0; i < count; i++) {
1409540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry[offset + i]);
1410540c07d3SCédric Le Goater }
1411540c07d3SCédric Le Goater }
1412540c07d3SCédric Le Goater
write_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1413540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1414540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1415540c07d3SCédric Le Goater RspBuffer *rsp)
1416540c07d3SCédric Le Goater {
1417540c07d3SCédric Le Goater uint8_t fruid;
1418540c07d3SCédric Le Goater uint16_t offset;
1419540c07d3SCédric Le Goater uint8_t *fru_entry;
1420540c07d3SCédric Le Goater unsigned int count;
1421540c07d3SCédric Le Goater
1422540c07d3SCédric Le Goater fruid = cmd[2];
1423540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8);
1424540c07d3SCédric Le Goater
1425540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) {
1426540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1427540c07d3SCédric Le Goater return;
1428540c07d3SCédric Le Goater }
1429540c07d3SCédric Le Goater
1430540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) {
1431540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1432540c07d3SCédric Le Goater return;
1433540c07d3SCédric Le Goater }
1434540c07d3SCédric Le Goater
1435540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1436540c07d3SCédric Le Goater
1437540c07d3SCédric Le Goater count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1438540c07d3SCédric Le Goater
1439540c07d3SCédric Le Goater memcpy(fru_entry + offset, cmd + 5, count);
1440540c07d3SCédric Le Goater
1441540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff);
1442540c07d3SCédric Le Goater }
1443540c07d3SCédric Le Goater
reserve_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)14448bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
14458bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1446a580d820SCédric Le Goater RspBuffer *rsp)
14478bfffbccSCorey Minyard {
1448a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1449a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
14508bfffbccSCorey Minyard }
14518bfffbccSCorey Minyard
get_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)14528bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
14538bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1454a580d820SCédric Le Goater RspBuffer *rsp)
14558bfffbccSCorey Minyard {
14568bfffbccSCorey Minyard unsigned int val;
14578bfffbccSCorey Minyard
14588bfffbccSCorey Minyard if (cmd[6]) {
14597f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
14606acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
14617f996411SCédric Le Goater return;
14627f996411SCédric Le Goater }
14638bfffbccSCorey Minyard }
14648bfffbccSCorey Minyard if (ibs->sel.next_free == 0) {
14656acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1466d13ada5dSCédric Le Goater return;
14678bfffbccSCorey Minyard }
14688bfffbccSCorey Minyard if (cmd[6] > 15) {
14696acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1470d13ada5dSCédric Le Goater return;
14718bfffbccSCorey Minyard }
14728bfffbccSCorey Minyard if (cmd[7] == 0xff) {
14738bfffbccSCorey Minyard cmd[7] = 16;
14748bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) {
14756acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1476d13ada5dSCédric Le Goater return;
14778bfffbccSCorey Minyard } else {
14788bfffbccSCorey Minyard cmd[7] += cmd[6];
14798bfffbccSCorey Minyard }
14808bfffbccSCorey Minyard
14818bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8);
14828bfffbccSCorey Minyard if (val == 0xffff) {
14838bfffbccSCorey Minyard val = ibs->sel.next_free - 1;
14848bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) {
14856acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1486d13ada5dSCédric Le Goater return;
14878bfffbccSCorey Minyard }
14888bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) {
1489a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff);
1490a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff);
14918bfffbccSCorey Minyard } else {
1492a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff);
1493a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
14948bfffbccSCorey Minyard }
14958bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) {
1496a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
14978bfffbccSCorey Minyard }
14988bfffbccSCorey Minyard }
14998bfffbccSCorey Minyard
add_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15008bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15018bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1502a580d820SCédric Le Goater RspBuffer *rsp)
15038bfffbccSCorey Minyard {
15048bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) {
15056acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1506d13ada5dSCédric Le Goater return;
15078bfffbccSCorey Minyard }
15088bfffbccSCorey Minyard /* sel_add_event fills in the record number. */
1509a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]);
1510a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]);
15118bfffbccSCorey Minyard }
15128bfffbccSCorey Minyard
clear_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15138bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15148bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1515a580d820SCédric Le Goater RspBuffer *rsp)
15168bfffbccSCorey Minyard {
15177f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15186acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15197f996411SCédric Le Goater return;
15207f996411SCédric Le Goater }
15217f996411SCédric Le Goater
15228bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1524d13ada5dSCédric Le Goater return;
15258bfffbccSCorey Minyard }
15268bfffbccSCorey Minyard if (cmd[7] == 0xaa) {
15278bfffbccSCorey Minyard ibs->sel.next_free = 0;
15288bfffbccSCorey Minyard ibs->sel.overflow = 0;
15298bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear);
1530a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
15318bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel);
15328bfffbccSCorey Minyard } else if (cmd[7] == 0) {
1533a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
15348bfffbccSCorey Minyard } else {
15356acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
15368bfffbccSCorey Minyard return;
15378bfffbccSCorey Minyard }
1538d13ada5dSCédric Le Goater }
15398bfffbccSCorey Minyard
get_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15408bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
15418bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1542a580d820SCédric Le Goater RspBuffer *rsp)
15438bfffbccSCorey Minyard {
15448bfffbccSCorey Minyard uint32_t val;
15458bfffbccSCorey Minyard struct ipmi_time now;
15468bfffbccSCorey Minyard
15478bfffbccSCorey Minyard ipmi_gettime(&now);
15488bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset;
1549a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff);
1550a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff);
1551a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff);
1552a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff);
15538bfffbccSCorey Minyard }
15548bfffbccSCorey Minyard
set_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15558bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
15568bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1557a580d820SCédric Le Goater RspBuffer *rsp)
15588bfffbccSCorey Minyard {
15598bfffbccSCorey Minyard uint32_t val;
15608bfffbccSCorey Minyard struct ipmi_time now;
15618bfffbccSCorey Minyard
15628bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
15638bfffbccSCorey Minyard ipmi_gettime(&now);
15648bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val);
15658bfffbccSCorey Minyard }
15668bfffbccSCorey Minyard
platform_event_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15679380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
15689380d2edSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
15699380d2edSCorey Minyard RspBuffer *rsp)
15709380d2edSCorey Minyard {
15719380d2edSCorey Minyard uint8_t event[16];
15729380d2edSCorey Minyard
15739380d2edSCorey Minyard event[2] = 2; /* System event record */
15749380d2edSCorey Minyard event[7] = cmd[2]; /* Generator ID */
15759380d2edSCorey Minyard event[8] = 0;
15769380d2edSCorey Minyard event[9] = cmd[3]; /* EvMRev */
15779380d2edSCorey Minyard event[10] = cmd[4]; /* Sensor type */
15789380d2edSCorey Minyard event[11] = cmd[5]; /* Sensor number */
15799380d2edSCorey Minyard event[12] = cmd[6]; /* Event dir / Event type */
15809380d2edSCorey Minyard event[13] = cmd[7]; /* Event data 1 */
15819380d2edSCorey Minyard event[14] = cmd[8]; /* Event data 2 */
15829380d2edSCorey Minyard event[15] = cmd[9]; /* Event data 3 */
15839380d2edSCorey Minyard
15849380d2edSCorey Minyard if (sel_add_event(ibs, event)) {
15859380d2edSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
15869380d2edSCorey Minyard }
15879380d2edSCorey Minyard }
15889380d2edSCorey Minyard
set_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15898bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
15908bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1591a580d820SCédric Le Goater RspBuffer *rsp)
15928bfffbccSCorey Minyard {
15938bfffbccSCorey Minyard IPMISensor *sens;
15948bfffbccSCorey Minyard
159573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
15968bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
15976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1598d13ada5dSCédric Le Goater return;
15998bfffbccSCorey Minyard }
16008bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
16018bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) {
16028bfffbccSCorey Minyard case 0: /* Do not change */
16038bfffbccSCorey Minyard break;
16048bfffbccSCorey Minyard case 1: /* Enable bits */
16058bfffbccSCorey Minyard if (cmd_len > 4) {
16068bfffbccSCorey Minyard sens->assert_enable |= cmd[4];
16078bfffbccSCorey Minyard }
16088bfffbccSCorey Minyard if (cmd_len > 5) {
16098bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8;
16108bfffbccSCorey Minyard }
16118bfffbccSCorey Minyard if (cmd_len > 6) {
16128bfffbccSCorey Minyard sens->deassert_enable |= cmd[6];
16138bfffbccSCorey Minyard }
16148bfffbccSCorey Minyard if (cmd_len > 7) {
16158bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8;
16168bfffbccSCorey Minyard }
16178bfffbccSCorey Minyard break;
16188bfffbccSCorey Minyard case 2: /* Disable bits */
16198bfffbccSCorey Minyard if (cmd_len > 4) {
16208bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4];
16218bfffbccSCorey Minyard }
16228bfffbccSCorey Minyard if (cmd_len > 5) {
16238bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8);
16248bfffbccSCorey Minyard }
16258bfffbccSCorey Minyard if (cmd_len > 6) {
16268bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6];
16278bfffbccSCorey Minyard }
16288bfffbccSCorey Minyard if (cmd_len > 7) {
16298bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8);
16308bfffbccSCorey Minyard }
16318bfffbccSCorey Minyard break;
16328bfffbccSCorey Minyard case 3:
16336acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1634d13ada5dSCédric Le Goater return;
16358bfffbccSCorey Minyard }
16368bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
16378bfffbccSCorey Minyard }
16388bfffbccSCorey Minyard
get_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16398bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
16408bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1641a580d820SCédric Le Goater RspBuffer *rsp)
16428bfffbccSCorey Minyard {
16438bfffbccSCorey Minyard IPMISensor *sens;
16448bfffbccSCorey Minyard
164573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
16468bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16476acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1648d13ada5dSCédric Le Goater return;
16498bfffbccSCorey Minyard }
16508bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
1651a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1652a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1653a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1654a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1655a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
16568bfffbccSCorey Minyard }
16578bfffbccSCorey Minyard
rearm_sensor_evts(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16588bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
16598bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1660a580d820SCédric Le Goater RspBuffer *rsp)
16618bfffbccSCorey Minyard {
16628bfffbccSCorey Minyard IPMISensor *sens;
16638bfffbccSCorey Minyard
166473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
16658bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16666acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1667d13ada5dSCédric Le Goater return;
16688bfffbccSCorey Minyard }
16698bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
16708bfffbccSCorey Minyard
16718bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) {
16728bfffbccSCorey Minyard /* Just clear everything */
16738bfffbccSCorey Minyard sens->states = 0;
16748bfffbccSCorey Minyard return;
16758bfffbccSCorey Minyard }
1676d13ada5dSCédric Le Goater }
16778bfffbccSCorey Minyard
get_sensor_evt_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16788bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
16798bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1680a580d820SCédric Le Goater RspBuffer *rsp)
16818bfffbccSCorey Minyard {
16828bfffbccSCorey Minyard IPMISensor *sens;
16838bfffbccSCorey Minyard
168473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
16858bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16866acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1687d13ada5dSCédric Le Goater return;
16888bfffbccSCorey Minyard }
16898bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
1690a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading);
1691a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1692a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff);
1693a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1694a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1695a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
16968bfffbccSCorey Minyard }
16978bfffbccSCorey Minyard
get_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16988bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
16998bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1700a580d820SCédric Le Goater RspBuffer *rsp)
17018bfffbccSCorey Minyard {
17028bfffbccSCorey Minyard IPMISensor *sens;
17038bfffbccSCorey Minyard
170473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
17058bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17066acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1707d13ada5dSCédric Le Goater return;
17088bfffbccSCorey Minyard }
17098bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
1710a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading);
1711a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1712a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff);
17138bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1714a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17158bfffbccSCorey Minyard }
17168bfffbccSCorey Minyard }
17178bfffbccSCorey Minyard
set_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1718728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1719728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1720a580d820SCédric Le Goater RspBuffer *rsp)
1721728710e1SCédric Le Goater {
1722728710e1SCédric Le Goater IPMISensor *sens;
1723728710e1SCédric Le Goater
1724728710e1SCédric Le Goater
172573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
1726728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17276acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1728728710e1SCédric Le Goater return;
1729728710e1SCédric Le Goater }
1730728710e1SCédric Le Goater sens = ibs->sensors + cmd[2];
1731728710e1SCédric Le Goater sens->sensor_type = cmd[3];
1732728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f;
1733728710e1SCédric Le Goater }
1734728710e1SCédric Le Goater
get_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1735728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1736728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1737a580d820SCédric Le Goater RspBuffer *rsp)
1738728710e1SCédric Le Goater {
1739728710e1SCédric Le Goater IPMISensor *sens;
1740728710e1SCédric Le Goater
1741728710e1SCédric Le Goater
174273d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
1743728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17446acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1745728710e1SCédric Le Goater return;
1746728710e1SCédric Le Goater }
1747728710e1SCédric Le Goater sens = ibs->sensors + cmd[2];
1748a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type);
1749a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code);
1750728710e1SCédric Le Goater }
1751728710e1SCédric Le Goater
1752e3f7320cSCédric Le Goater /*
1753e3f7320cSCédric Le Goater * bytes parameter
1754e3f7320cSCédric Le Goater * 1 sensor number
1755e3f7320cSCédric Le Goater * 2 operation (see below for bits meaning)
1756e3f7320cSCédric Le Goater * 3 sensor reading
1757e3f7320cSCédric Le Goater * 4:5 assertion states (optional)
1758e3f7320cSCédric Le Goater * 6:7 deassertion states (optional)
1759e3f7320cSCédric Le Goater * 8:10 event data 1,2,3 (optional)
1760e3f7320cSCédric Le Goater */
set_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1761e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs,
1762e3f7320cSCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1763e3f7320cSCédric Le Goater RspBuffer *rsp)
1764e3f7320cSCédric Le Goater {
1765e3f7320cSCédric Le Goater IPMISensor *sens;
1766e3f7320cSCédric Le Goater uint8_t evd1 = 0;
1767e3f7320cSCédric Le Goater uint8_t evd2 = 0;
1768e3f7320cSCédric Le Goater uint8_t evd3 = 0;
1769e3f7320cSCédric Le Goater uint8_t new_reading = 0;
1770e3f7320cSCédric Le Goater uint16_t new_assert_states = 0;
1771e3f7320cSCédric Le Goater uint16_t new_deassert_states = 0;
1772e3f7320cSCédric Le Goater bool change_reading = false;
1773e3f7320cSCédric Le Goater bool change_assert = false;
1774e3f7320cSCédric Le Goater bool change_deassert = false;
1775e3f7320cSCédric Le Goater enum {
1776e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_NONE,
1777e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_DATA,
1778e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_BMC,
1779e3f7320cSCédric Le Goater } do_gen_event = SENSOR_GEN_EVENT_NONE;
1780e3f7320cSCédric Le Goater
1781e3f7320cSCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
1782e3f7320cSCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1783e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1784e3f7320cSCédric Le Goater return;
1785e3f7320cSCédric Le Goater }
1786e3f7320cSCédric Le Goater
1787e3f7320cSCédric Le Goater sens = ibs->sensors + cmd[2];
1788e3f7320cSCédric Le Goater
1789e3f7320cSCédric Le Goater /* [1:0] Sensor Reading operation */
1790e3f7320cSCédric Le Goater switch ((cmd[3]) & 0x3) {
1791e3f7320cSCédric Le Goater case 0: /* Do not change */
1792e3f7320cSCédric Le Goater break;
1793e3f7320cSCédric Le Goater case 1: /* write given value to sensor reading byte */
1794e3f7320cSCédric Le Goater new_reading = cmd[4];
1795e3f7320cSCédric Le Goater if (sens->reading != new_reading) {
1796e3f7320cSCédric Le Goater change_reading = true;
1797e3f7320cSCédric Le Goater }
1798e3f7320cSCédric Le Goater break;
1799e3f7320cSCédric Le Goater case 2:
1800e3f7320cSCédric Le Goater case 3:
1801e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1802e3f7320cSCédric Le Goater return;
1803e3f7320cSCédric Le Goater }
1804e3f7320cSCédric Le Goater
1805e3f7320cSCédric Le Goater /* [3:2] Deassertion bits operation */
1806e3f7320cSCédric Le Goater switch ((cmd[3] >> 2) & 0x3) {
1807e3f7320cSCédric Le Goater case 0: /* Do not change */
1808e3f7320cSCédric Le Goater break;
1809e3f7320cSCédric Le Goater case 1: /* write given value */
1810e3f7320cSCédric Le Goater if (cmd_len > 7) {
1811e3f7320cSCédric Le Goater new_deassert_states = cmd[7];
1812e3f7320cSCédric Le Goater change_deassert = true;
1813e3f7320cSCédric Le Goater }
1814e3f7320cSCédric Le Goater if (cmd_len > 8) {
1815e3f7320cSCédric Le Goater new_deassert_states |= (cmd[8] << 8);
1816e3f7320cSCédric Le Goater }
1817e3f7320cSCédric Le Goater break;
1818e3f7320cSCédric Le Goater
1819e3f7320cSCédric Le Goater case 2: /* mask on */
1820e3f7320cSCédric Le Goater if (cmd_len > 7) {
1821e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states | cmd[7]);
1822e3f7320cSCédric Le Goater change_deassert = true;
1823e3f7320cSCédric Le Goater }
1824e3f7320cSCédric Le Goater if (cmd_len > 8) {
1825e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1826e3f7320cSCédric Le Goater }
1827e3f7320cSCédric Le Goater break;
1828e3f7320cSCédric Le Goater
1829e3f7320cSCédric Le Goater case 3: /* mask off */
1830e3f7320cSCédric Le Goater if (cmd_len > 7) {
1831e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states & cmd[7]);
1832e3f7320cSCédric Le Goater change_deassert = true;
1833e3f7320cSCédric Le Goater }
1834e3f7320cSCédric Le Goater if (cmd_len > 8) {
1835e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1836e3f7320cSCédric Le Goater }
1837e3f7320cSCédric Le Goater break;
1838e3f7320cSCédric Le Goater }
1839e3f7320cSCédric Le Goater
1840e3f7320cSCédric Le Goater if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1841e3f7320cSCédric Le Goater change_deassert = false;
1842e3f7320cSCédric Le Goater }
1843e3f7320cSCédric Le Goater
1844e3f7320cSCédric Le Goater /* [5:4] Assertion bits operation */
1845e3f7320cSCédric Le Goater switch ((cmd[3] >> 4) & 0x3) {
1846e3f7320cSCédric Le Goater case 0: /* Do not change */
1847e3f7320cSCédric Le Goater break;
1848e3f7320cSCédric Le Goater case 1: /* write given value */
1849e3f7320cSCédric Le Goater if (cmd_len > 5) {
1850e3f7320cSCédric Le Goater new_assert_states = cmd[5];
1851e3f7320cSCédric Le Goater change_assert = true;
1852e3f7320cSCédric Le Goater }
1853e3f7320cSCédric Le Goater if (cmd_len > 6) {
1854e3f7320cSCédric Le Goater new_assert_states |= (cmd[6] << 8);
1855e3f7320cSCédric Le Goater }
1856e3f7320cSCédric Le Goater break;
1857e3f7320cSCédric Le Goater
1858e3f7320cSCédric Le Goater case 2: /* mask on */
1859e3f7320cSCédric Le Goater if (cmd_len > 5) {
1860e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states | cmd[5]);
1861e3f7320cSCédric Le Goater change_assert = true;
1862e3f7320cSCédric Le Goater }
1863e3f7320cSCédric Le Goater if (cmd_len > 6) {
1864e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1865e3f7320cSCédric Le Goater }
1866e3f7320cSCédric Le Goater break;
1867e3f7320cSCédric Le Goater
1868e3f7320cSCédric Le Goater case 3: /* mask off */
1869e3f7320cSCédric Le Goater if (cmd_len > 5) {
1870e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states & cmd[5]);
1871e3f7320cSCédric Le Goater change_assert = true;
1872e3f7320cSCédric Le Goater }
1873e3f7320cSCédric Le Goater if (cmd_len > 6) {
1874e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1875e3f7320cSCédric Le Goater }
1876e3f7320cSCédric Le Goater break;
1877e3f7320cSCédric Le Goater }
1878e3f7320cSCédric Le Goater
1879e3f7320cSCédric Le Goater if (change_assert && (new_assert_states == sens->assert_states)) {
1880e3f7320cSCédric Le Goater change_assert = false;
1881e3f7320cSCédric Le Goater }
1882e3f7320cSCédric Le Goater
1883e3f7320cSCédric Le Goater if (cmd_len > 9) {
1884e3f7320cSCédric Le Goater evd1 = cmd[9];
1885e3f7320cSCédric Le Goater }
1886e3f7320cSCédric Le Goater if (cmd_len > 10) {
1887e3f7320cSCédric Le Goater evd2 = cmd[10];
1888e3f7320cSCédric Le Goater }
1889e3f7320cSCédric Le Goater if (cmd_len > 11) {
1890e3f7320cSCédric Le Goater evd3 = cmd[11];
1891e3f7320cSCédric Le Goater }
1892e3f7320cSCédric Le Goater
1893e3f7320cSCédric Le Goater /* [7:6] Event Data Bytes operation */
1894e3f7320cSCédric Le Goater switch ((cmd[3] >> 6) & 0x3) {
1895e3f7320cSCédric Le Goater case 0: /*
1896e3f7320cSCédric Le Goater * Don’t use Event Data bytes from this command. BMC will
1897e3f7320cSCédric Le Goater * generate it's own Event Data bytes based on its sensor
1898e3f7320cSCédric Le Goater * implementation.
1899e3f7320cSCédric Le Goater */
1900e3f7320cSCédric Le Goater evd1 = evd2 = evd3 = 0x0;
1901e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_BMC;
1902e3f7320cSCédric Le Goater break;
1903e3f7320cSCédric Le Goater case 1: /*
1904e3f7320cSCédric Le Goater * Write given values to event data bytes including bits
1905e3f7320cSCédric Le Goater * [3:0] Event Data 1.
1906e3f7320cSCédric Le Goater */
1907e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA;
1908e3f7320cSCédric Le Goater break;
1909e3f7320cSCédric Le Goater case 2: /*
1910e3f7320cSCédric Le Goater * Write given values to event data bytes excluding bits
1911e3f7320cSCédric Le Goater * [3:0] Event Data 1.
1912e3f7320cSCédric Le Goater */
1913e3f7320cSCédric Le Goater evd1 &= 0xf0;
1914e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA;
1915e3f7320cSCédric Le Goater break;
1916e3f7320cSCédric Le Goater case 3:
1917e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1918e3f7320cSCédric Le Goater return;
1919e3f7320cSCédric Le Goater }
1920e3f7320cSCédric Le Goater
1921e3f7320cSCédric Le Goater /*
1922e3f7320cSCédric Le Goater * Event Data Bytes operation and parameter are inconsistent. The
1923e3f7320cSCédric Le Goater * Specs are not clear on that topic but generating an error seems
1924e3f7320cSCédric Le Goater * correct.
1925e3f7320cSCédric Le Goater */
1926e3f7320cSCédric Le Goater if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
1927e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1928e3f7320cSCédric Le Goater return;
1929e3f7320cSCédric Le Goater }
1930e3f7320cSCédric Le Goater
1931e3f7320cSCédric Le Goater /* commit values */
1932e3f7320cSCédric Le Goater if (change_reading) {
1933e3f7320cSCédric Le Goater sens->reading = new_reading;
1934e3f7320cSCédric Le Goater }
1935e3f7320cSCédric Le Goater
1936e3f7320cSCédric Le Goater if (change_assert) {
1937e3f7320cSCédric Le Goater sens->assert_states = new_assert_states;
1938e3f7320cSCédric Le Goater }
1939e3f7320cSCédric Le Goater
1940e3f7320cSCédric Le Goater if (change_deassert) {
1941e3f7320cSCédric Le Goater sens->deassert_states = new_deassert_states;
1942e3f7320cSCédric Le Goater }
1943e3f7320cSCédric Le Goater
1944e3f7320cSCédric Le Goater /* TODO: handle threshold sensor */
1945e3f7320cSCédric Le Goater if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
1946e3f7320cSCédric Le Goater return;
1947e3f7320cSCédric Le Goater }
1948e3f7320cSCédric Le Goater
1949e3f7320cSCédric Le Goater switch (do_gen_event) {
1950e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_DATA: {
1951e3f7320cSCédric Le Goater unsigned int bit = evd1 & 0xf;
1952e3f7320cSCédric Le Goater uint16_t mask = (1 << bit);
1953e3f7320cSCédric Le Goater
1954e3f7320cSCédric Le Goater if (sens->assert_states & mask & sens->assert_enable) {
1955e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
1956e3f7320cSCédric Le Goater }
1957e3f7320cSCédric Le Goater
1958e3f7320cSCédric Le Goater if (sens->deassert_states & mask & sens->deassert_enable) {
1959e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
1960e3f7320cSCédric Le Goater }
1961e3f7320cSCédric Le Goater break;
1962e3f7320cSCédric Le Goater }
1963e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_BMC:
1964e3f7320cSCédric Le Goater /*
1965e3f7320cSCédric Le Goater * TODO: generate event and event data bytes depending on the
1966e3f7320cSCédric Le Goater * sensor
1967e3f7320cSCédric Le Goater */
1968e3f7320cSCédric Le Goater break;
1969e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_NONE:
1970e3f7320cSCédric Le Goater break;
1971e3f7320cSCédric Le Goater }
1972e3f7320cSCédric Le Goater }
1973728710e1SCédric Le Goater
197462a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
19754f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
19764f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
19774f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
19784f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
19798bfffbccSCorey Minyard };
19808bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
198162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds),
19828bfffbccSCorey Minyard .cmd_handlers = chassis_cmds
19838bfffbccSCorey Minyard };
19848bfffbccSCorey Minyard
198562a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
19869380d2edSCorey Minyard [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
19874f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
19884f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
19894f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
19904f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
19914f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
19924f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
19934f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
1994e3f7320cSCédric Le Goater [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
19958bfffbccSCorey Minyard };
19968bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
199762a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
19988bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds
19998bfffbccSCorey Minyard };
20008bfffbccSCorey Minyard
200162a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
20024f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
20034f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset },
20044f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset },
20054f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
20064f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
20074f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
20084f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
20094f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
20104f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
20114f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
20124f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg },
20134f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
20144f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
20154f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
20164f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
20174f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
20188bfffbccSCorey Minyard };
20198bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
202062a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds),
20218bfffbccSCorey Minyard .cmd_handlers = app_cmds
20228bfffbccSCorey Minyard };
20238bfffbccSCorey Minyard
202462a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
2025540c07d3SCédric Le Goater [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2026540c07d3SCédric Le Goater [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2027540c07d3SCédric Le Goater [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
20284f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
20294f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
20304f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
20314f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr },
20324f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
20334f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
20344f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
20354f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
20364f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
20374f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
20387f11cb65SCorey Minyard [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
20397f11cb65SCorey Minyard [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
20408bfffbccSCorey Minyard };
20418bfffbccSCorey Minyard
20428bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
204362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds),
20448bfffbccSCorey Minyard .cmd_handlers = storage_cmds
20458bfffbccSCorey Minyard };
20468bfffbccSCorey Minyard
register_cmds(IPMIBmcSim * s)20478bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
20488bfffbccSCorey Minyard {
2049ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2050ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2051ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2052ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
20538bfffbccSCorey Minyard }
20548bfffbccSCorey Minyard
20555167560bSCédric Le Goater static uint8_t init_sdrs[] = {
20568bfffbccSCorey Minyard /* Watchdog device */
20578bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
20588bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
20598bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20608bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
20618bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
20628bfffbccSCorey Minyard };
20638bfffbccSCorey Minyard
ipmi_sdr_init(IPMIBmcSim * ibs)20644fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
20654fa9f08eSCédric Le Goater {
20664fa9f08eSCédric Le Goater unsigned int i;
20674fa9f08eSCédric Le Goater int len;
20685167560bSCédric Le Goater size_t sdrs_size;
20695167560bSCédric Le Goater uint8_t *sdrs;
207052fc01d9SCédric Le Goater
20715167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs);
20725167560bSCédric Le Goater sdrs = init_sdrs;
20738c6fd7f3SCédric Le Goater if (ibs->sdr_filename &&
20748c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
20758c6fd7f3SCédric Le Goater NULL)) {
20768c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename);
20778c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs);
20788c6fd7f3SCédric Le Goater sdrs = init_sdrs;
20798c6fd7f3SCédric Le Goater }
20805167560bSCédric Le Goater
20815167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) {
208252fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh;
208352fc01d9SCédric Le Goater
20845167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
20854fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i);
20868c6fd7f3SCédric Le Goater break;
20874fa9f08eSCédric Le Goater }
20885167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i];
20894fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh);
20905167560bSCédric Le Goater if (i + len > sdrs_size) {
20914fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i);
20928c6fd7f3SCédric Le Goater break;
20934fa9f08eSCédric Le Goater }
20944fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL);
20954fa9f08eSCédric Le Goater }
20968c6fd7f3SCédric Le Goater
20978c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) {
20988c6fd7f3SCédric Le Goater g_free(sdrs);
20998c6fd7f3SCédric Le Goater }
21004fa9f08eSCédric Le Goater }
21014fa9f08eSCédric Le Goater
2102bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
2103bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR,
2104bd66bcfcSCorey Minyard .version_id = 1,
2105bd66bcfcSCorey Minyard .minimum_version_id = 1,
2106*09c6ac6dSRichard Henderson .fields = (const VMStateField[]) {
2107bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2108bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2109bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2110bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2111bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2112bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
21139e744990SJinhua Cao VMSTATE_UINT8(watchdog_expired, IPMIBmcSim),
2114bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2115bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2116bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2117bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2118bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2119bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2120bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2121bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2122bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2123bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2124bd66bcfcSCorey Minyard IPMIBmcSim),
2125bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2126bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST()
2127bd66bcfcSCorey Minyard }
2128bd66bcfcSCorey Minyard };
2129bd66bcfcSCorey Minyard
ipmi_fru_init(IPMIFru * fru)2130540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
2131540c07d3SCédric Le Goater {
2132540c07d3SCédric Le Goater int fsize;
2133540c07d3SCédric Le Goater int size = 0;
2134540c07d3SCédric Le Goater
2135540c07d3SCédric Le Goater if (!fru->filename) {
2136540c07d3SCédric Le Goater goto out;
2137540c07d3SCédric Le Goater }
2138540c07d3SCédric Le Goater
2139540c07d3SCédric Le Goater fsize = get_image_size(fru->filename);
2140540c07d3SCédric Le Goater if (fsize > 0) {
2141540c07d3SCédric Le Goater size = QEMU_ALIGN_UP(fsize, fru->areasize);
2142540c07d3SCédric Le Goater fru->data = g_malloc0(size);
2143540c07d3SCédric Le Goater if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2144540c07d3SCédric Le Goater error_report("Could not load file '%s'", fru->filename);
2145540c07d3SCédric Le Goater g_free(fru->data);
2146540c07d3SCédric Le Goater fru->data = NULL;
2147540c07d3SCédric Le Goater }
2148540c07d3SCédric Le Goater }
2149540c07d3SCédric Le Goater
2150540c07d3SCédric Le Goater out:
2151540c07d3SCédric Le Goater if (!fru->data) {
2152540c07d3SCédric Le Goater /* give one default FRU */
2153540c07d3SCédric Le Goater size = fru->areasize;
2154540c07d3SCédric Le Goater fru->data = g_malloc0(size);
2155540c07d3SCédric Le Goater }
2156540c07d3SCédric Le Goater
2157540c07d3SCédric Le Goater fru->nentries = size / fru->areasize;
2158540c07d3SCédric Le Goater }
2159540c07d3SCédric Le Goater
ipmi_sim_realize(DeviceState * dev,Error ** errp)21600bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
21618bfffbccSCorey Minyard {
21620bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev);
21638bfffbccSCorey Minyard unsigned int i;
21648bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
21658bfffbccSCorey Minyard
21668bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs);
21678bfffbccSCorey Minyard
21688bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
21698bfffbccSCorey Minyard ibs->device_id = 0x20;
21708bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */
2171b7088392SCédric Le Goater ibs->restart_cause = 0;
21728bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
21738bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff;
21748bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff;
21758bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff;
21768bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff;
21778bfffbccSCorey Minyard }
21788bfffbccSCorey Minyard
21794fa9f08eSCédric Le Goater ipmi_sdr_init(ibs);
21808bfffbccSCorey Minyard
2181540c07d3SCédric Le Goater ipmi_fru_init(&ibs->fru);
2182540c07d3SCédric Le Goater
218352ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0;
218452ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0;
218552ba4d50SCédric Le Goater
21868bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs);
21878bfffbccSCorey Minyard register_cmds(ibs);
21888bfffbccSCorey Minyard
21898bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
2190bd66bcfcSCorey Minyard
2191bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs);
21928bfffbccSCorey Minyard }
21938bfffbccSCorey Minyard
21948c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = {
2195540c07d3SCédric Le Goater DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2196540c07d3SCédric Le Goater DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
21978c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
219820b23364SCorey Minyard DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
219920b23364SCorey Minyard DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
220020b23364SCorey Minyard DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
220120b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
220220b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
220320b23364SCorey Minyard DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
220420b23364SCorey Minyard DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
22057b0cd78bSCorey Minyard DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
22068c6fd7f3SCédric Le Goater DEFINE_PROP_END_OF_LIST(),
22078c6fd7f3SCédric Le Goater };
22088c6fd7f3SCédric Le Goater
ipmi_sim_class_init(ObjectClass * oc,void * data)22098bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data)
22108bfffbccSCorey Minyard {
22110bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc);
22128bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
22138bfffbccSCorey Minyard
221466abfddbSCorey Minyard dc->hotpluggable = false;
22150bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize;
22164f67d30bSMarc-André Lureau device_class_set_props(dc, ipmi_sim_properties);
22178bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command;
22188bfffbccSCorey Minyard }
22198bfffbccSCorey Minyard
22208bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
22218bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR,
22228bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC,
22238bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim),
22248bfffbccSCorey Minyard .class_init = ipmi_sim_class_init,
22258bfffbccSCorey Minyard };
22268bfffbccSCorey Minyard
ipmi_sim_register_types(void)22278bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
22288bfffbccSCorey Minyard {
22298bfffbccSCorey Minyard type_register_static(&ipmi_sim_type);
22308bfffbccSCorey Minyard }
22318bfffbccSCorey Minyard
22328bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2233