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"
2632cad1ffSPhilippe Mathieu-Daudé #include "system/system.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
737f9e7af4SNicholas Piggin #define IPMI_CMD_GET_CHANNEL_INFO 0x42
748bfffbccSCorey Minyard
758bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a
768bfffbccSCorey Minyard
778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20
788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21
798bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22
808bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23
818bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24
828bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25
838bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26
848bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27
858bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28
868bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29
878bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A
888bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B
898bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C
90540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO 0x10
91540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA 0x11
92540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA 0x12
938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40
948bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41
958bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42
968bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43
978bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44
988bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45
998bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46
1008bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47
1018bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48
1028bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49
1038bfffbccSCorey Minyard
1048bfffbccSCorey Minyard
1058bfffbccSCorey Minyard /* Same as a timespec struct. */
1068bfffbccSCorey Minyard struct ipmi_time {
1078bfffbccSCorey Minyard long tv_sec;
1088bfffbccSCorey Minyard long tv_nsec;
1098bfffbccSCorey Minyard };
1108bfffbccSCorey Minyard
1118bfffbccSCorey Minyard #define MAX_SEL_SIZE 128
1128bfffbccSCorey Minyard
1138bfffbccSCorey Minyard typedef struct IPMISel {
1148bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16];
1158bfffbccSCorey Minyard unsigned int next_free;
1168bfffbccSCorey Minyard long time_offset;
1178bfffbccSCorey Minyard uint16_t reservation;
1188bfffbccSCorey Minyard uint8_t last_addition[4];
1198bfffbccSCorey Minyard uint8_t last_clear[4];
1208bfffbccSCorey Minyard uint8_t overflow;
1218bfffbccSCorey Minyard } IPMISel;
1228bfffbccSCorey Minyard
1238bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384
1248bfffbccSCorey Minyard
1258bfffbccSCorey Minyard typedef struct IPMISdr {
1268bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE];
1278bfffbccSCorey Minyard unsigned int next_free;
1288bfffbccSCorey Minyard uint16_t next_rec_id;
1298bfffbccSCorey Minyard uint16_t reservation;
1308bfffbccSCorey Minyard uint8_t last_addition[4];
1318bfffbccSCorey Minyard uint8_t last_clear[4];
1328bfffbccSCorey Minyard uint8_t overflow;
1338bfffbccSCorey Minyard } IPMISdr;
1348bfffbccSCorey Minyard
135540c07d3SCédric Le Goater typedef struct IPMIFru {
136540c07d3SCédric Le Goater char *filename;
137540c07d3SCédric Le Goater unsigned int nentries;
138540c07d3SCédric Le Goater uint16_t areasize;
139540c07d3SCédric Le Goater uint8_t *data;
140540c07d3SCédric Le Goater } IPMIFru;
141540c07d3SCédric Le Goater
1428bfffbccSCorey Minyard typedef struct IPMISensor {
1438bfffbccSCorey Minyard uint8_t status;
1448bfffbccSCorey Minyard uint8_t reading;
1458bfffbccSCorey Minyard uint16_t states_suppt;
1468bfffbccSCorey Minyard uint16_t assert_suppt;
1478bfffbccSCorey Minyard uint16_t deassert_suppt;
1488bfffbccSCorey Minyard uint16_t states;
1498bfffbccSCorey Minyard uint16_t assert_states;
1508bfffbccSCorey Minyard uint16_t deassert_states;
1518bfffbccSCorey Minyard uint16_t assert_enable;
1528bfffbccSCorey Minyard uint16_t deassert_enable;
1538bfffbccSCorey Minyard uint8_t sensor_type;
1548bfffbccSCorey Minyard uint8_t evt_reading_type_code;
1558bfffbccSCorey Minyard } IPMISensor;
1568bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01)
1578bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \
1588bfffbccSCorey Minyard !!(v))
1598bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40)
1608bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \
1618bfffbccSCorey Minyard ((!!(v)) << 6))
1628bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80)
1638bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \
1648bfffbccSCorey Minyard ((!!(v)) << 7))
1658bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0)
1668bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \
1678bfffbccSCorey Minyard (v & 0xc0))
1688bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1)
1698bfffbccSCorey Minyard
1708bfffbccSCorey Minyard #define MAX_SENSORS 20
1718bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0
1728bfffbccSCorey Minyard
1738bfffbccSCorey Minyard #define MAX_NETFNS 64
1744f298a4bSCédric Le Goater
1758bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry {
1768bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry;
1778bfffbccSCorey Minyard uint8_t len;
1788bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE];
1798bfffbccSCorey Minyard } IPMIRcvBufEntry;
1808bfffbccSCorey Minyard
1818bfffbccSCorey Minyard struct IPMIBmcSim {
1828bfffbccSCorey Minyard IPMIBmc parent;
1838bfffbccSCorey Minyard
1848bfffbccSCorey Minyard QEMUTimer *timer;
1858bfffbccSCorey Minyard
1868bfffbccSCorey Minyard uint8_t bmc_global_enables;
1878bfffbccSCorey Minyard uint8_t msg_flags;
1888bfffbccSCorey Minyard
1898bfffbccSCorey Minyard bool watchdog_initialized;
1908bfffbccSCorey Minyard uint8_t watchdog_use;
1918bfffbccSCorey Minyard uint8_t watchdog_action;
1928bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */
1939e744990SJinhua Cao uint8_t watchdog_expired;
1948bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */
1958bfffbccSCorey Minyard
1968bfffbccSCorey Minyard bool watchdog_running;
1978bfffbccSCorey Minyard bool watchdog_preaction_ran;
1988bfffbccSCorey Minyard int64_t watchdog_expiry;
1998bfffbccSCorey Minyard
2008bfffbccSCorey Minyard uint8_t device_id;
2018bfffbccSCorey Minyard uint8_t ipmi_version;
2028bfffbccSCorey Minyard uint8_t device_rev;
2038bfffbccSCorey Minyard uint8_t fwrev1;
2048bfffbccSCorey Minyard uint8_t fwrev2;
20520b23364SCorey Minyard uint32_t mfg_id;
20620b23364SCorey Minyard uint16_t product_id;
2078bfffbccSCorey Minyard
208b7088392SCédric Le Goater uint8_t restart_cause;
209b7088392SCédric Le Goater
21052ba4d50SCédric Le Goater uint8_t acpi_power_state[2];
2117b0cd78bSCorey Minyard QemuUUID uuid;
21252ba4d50SCédric Le Goater
2138bfffbccSCorey Minyard IPMISel sel;
2148bfffbccSCorey Minyard IPMISdr sdr;
215540c07d3SCédric Le Goater IPMIFru fru;
2168bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS];
2178c6fd7f3SCédric Le Goater char *sdr_filename;
2188bfffbccSCorey Minyard
2198bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */
2208bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2];
2218bfffbccSCorey Minyard
2228bfffbccSCorey Minyard /* We allow one event in the buffer */
2238bfffbccSCorey Minyard uint8_t evtbuf[16];
2248bfffbccSCorey Minyard
2258bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs;
2268bfffbccSCorey Minyard };
2278bfffbccSCorey Minyard
2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3)
2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1)
2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0)
2318bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \
2328bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags)
2338bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \
2348bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags)
2358bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \
2368bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags)
2378bfffbccSCorey Minyard
238dacb3e70SNicholas Piggin #define IPMI_BMC_GLOBAL_ENABLES_SUPPORTED 0x0f
2398bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0
2408bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1
2418bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2
2428bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3
2438bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2448bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2458bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2468bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2478bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2488bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT))
2498bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2508bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2518bfffbccSCorey Minyard
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1
2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2
2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3
2678bfffbccSCorey Minyard
268a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2698bfffbccSCorey Minyard
rsp_buffer_pushmore(RspBuffer * rsp,uint8_t * bytes,unsigned int n)270a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
271a580d820SCédric Le Goater unsigned int n)
272a580d820SCédric Le Goater {
273a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) {
2746acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
275a580d820SCédric Le Goater return;
276a580d820SCédric Le Goater }
277a580d820SCédric Le Goater
278a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n);
279a580d820SCédric Le Goater rsp->len += n;
280a580d820SCédric Le Goater }
2818bfffbccSCorey Minyard
2828bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2838bfffbccSCorey Minyard
ipmi_gettime(struct ipmi_time * time)2848bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2858bfffbccSCorey Minyard {
2868bfffbccSCorey Minyard int64_t stime;
2878bfffbccSCorey Minyard
2888bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2898bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL;
2908bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL;
2918bfffbccSCorey Minyard }
2928bfffbccSCorey Minyard
ipmi_getmonotime(void)2938bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2948bfffbccSCorey Minyard {
2958bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2968bfffbccSCorey Minyard }
2978bfffbccSCorey Minyard
ipmi_timeout(void * opaque)2988bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2998bfffbccSCorey Minyard {
3008bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque;
3018bfffbccSCorey Minyard
3028bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs);
3038bfffbccSCorey Minyard }
3048bfffbccSCorey Minyard
set_timestamp(IPMIBmcSim * ibs,uint8_t * ts)3058bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3068bfffbccSCorey Minyard {
3078bfffbccSCorey Minyard unsigned int val;
3088bfffbccSCorey Minyard struct ipmi_time now;
3098bfffbccSCorey Minyard
3108bfffbccSCorey Minyard ipmi_gettime(&now);
3118bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset;
3128bfffbccSCorey Minyard ts[0] = val & 0xff;
3138bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff;
3148bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff;
3158bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff;
3168bfffbccSCorey Minyard }
3178bfffbccSCorey Minyard
sdr_inc_reservation(IPMISdr * sdr)3188bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3198bfffbccSCorey Minyard {
3208bfffbccSCorey Minyard sdr->reservation++;
3218bfffbccSCorey Minyard if (sdr->reservation == 0) {
3228bfffbccSCorey Minyard sdr->reservation = 1;
3238bfffbccSCorey Minyard }
3248bfffbccSCorey Minyard }
3258bfffbccSCorey Minyard
sdr_add_entry(IPMIBmcSim * ibs,const struct ipmi_sdr_header * sdrh_entry,unsigned int len,uint16_t * recid)326a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
327a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry,
3288bfffbccSCorey Minyard unsigned int len, uint16_t *recid)
3298bfffbccSCorey Minyard {
330a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh =
331a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
332a2295f0aSCédric Le Goater
333a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3348bfffbccSCorey Minyard return 1;
3358bfffbccSCorey Minyard }
3368bfffbccSCorey Minyard
337a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) {
3388bfffbccSCorey Minyard return 1;
3398bfffbccSCorey Minyard }
3408bfffbccSCorey Minyard
3418bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3428bfffbccSCorey Minyard ibs->sdr.overflow = 1;
3438bfffbccSCorey Minyard return 1;
3448bfffbccSCorey Minyard }
3458bfffbccSCorey Minyard
346a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len);
347a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
348a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
349a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3508bfffbccSCorey Minyard
3518bfffbccSCorey Minyard if (recid) {
3528bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id;
3538bfffbccSCorey Minyard }
3548bfffbccSCorey Minyard ibs->sdr.next_rec_id++;
3558bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition);
3568bfffbccSCorey Minyard ibs->sdr.next_free += len;
3578bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr);
3588bfffbccSCorey Minyard return 0;
3598bfffbccSCorey Minyard }
3608bfffbccSCorey Minyard
sdr_find_entry(IPMISdr * sdr,uint16_t recid,unsigned int * retpos,uint16_t * nextrec)3618bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3628bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec)
3638bfffbccSCorey Minyard {
3648bfffbccSCorey Minyard unsigned int pos = *retpos;
3658bfffbccSCorey Minyard
3668bfffbccSCorey Minyard while (pos < sdr->next_free) {
367a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh =
368a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos];
369a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh);
370a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3718bfffbccSCorey Minyard
3728bfffbccSCorey Minyard if (trec == recid) {
3738bfffbccSCorey Minyard if (nextrec) {
3748bfffbccSCorey Minyard if (nextpos >= sdr->next_free) {
3758bfffbccSCorey Minyard *nextrec = 0xffff;
3768bfffbccSCorey Minyard } else {
3778bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] |
3788bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8));
3798bfffbccSCorey Minyard }
3808bfffbccSCorey Minyard }
3818bfffbccSCorey Minyard *retpos = pos;
3828bfffbccSCorey Minyard return 0;
3838bfffbccSCorey Minyard }
3848bfffbccSCorey Minyard pos = nextpos;
3858bfffbccSCorey Minyard }
3868bfffbccSCorey Minyard return 1;
3878bfffbccSCorey Minyard }
3888bfffbccSCorey Minyard
ipmi_bmc_sdr_find(IPMIBmc * b,uint16_t recid,const struct ipmi_sdr_compact ** sdr,uint16_t * nextrec)3897fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
3907fabcdb9SCédric Le Goater const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
3917fabcdb9SCédric Le Goater
3927fabcdb9SCédric Le Goater {
3937fabcdb9SCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
3947fabcdb9SCédric Le Goater unsigned int pos;
3957fabcdb9SCédric Le Goater
3967fabcdb9SCédric Le Goater pos = 0;
3977fabcdb9SCédric Le Goater if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
3987fabcdb9SCédric Le Goater return -1;
3997fabcdb9SCédric Le Goater }
4007fabcdb9SCédric Le Goater
4017fabcdb9SCédric Le Goater *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4027fabcdb9SCédric Le Goater return 0;
4037fabcdb9SCédric Le Goater }
4047fabcdb9SCédric Le Goater
sel_inc_reservation(IPMISel * sel)4058bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4068bfffbccSCorey Minyard {
4078bfffbccSCorey Minyard sel->reservation++;
4088bfffbccSCorey Minyard if (sel->reservation == 0) {
4098bfffbccSCorey Minyard sel->reservation = 1;
4108bfffbccSCorey Minyard }
4118bfffbccSCorey Minyard }
4128bfffbccSCorey Minyard
4138bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
sel_add_event(IPMIBmcSim * ibs,uint8_t * event)4148bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4158bfffbccSCorey Minyard {
4169f7d1d92SCorey Minyard uint8_t ts[4];
4179f7d1d92SCorey Minyard
4188bfffbccSCorey Minyard event[0] = 0xff;
4198bfffbccSCorey Minyard event[1] = 0xff;
4209f7d1d92SCorey Minyard set_timestamp(ibs, ts);
4219f7d1d92SCorey Minyard if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4229f7d1d92SCorey Minyard memcpy(event + 3, ts, 4);
4239f7d1d92SCorey Minyard }
4248bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) {
4258bfffbccSCorey Minyard ibs->sel.overflow = 1;
4268bfffbccSCorey Minyard return 1;
4278bfffbccSCorey Minyard }
4288bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff;
4298bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff;
4309f7d1d92SCorey Minyard memcpy(ibs->sel.last_addition, ts, 4);
4318bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4328bfffbccSCorey Minyard ibs->sel.next_free++;
4338bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel);
4348bfffbccSCorey Minyard return 0;
4358bfffbccSCorey Minyard }
4368bfffbccSCorey Minyard
attn_set(IPMIBmcSim * ibs)4378bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4388bfffbccSCorey Minyard {
4398bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4408bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4418bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4428bfffbccSCorey Minyard }
4438bfffbccSCorey Minyard
attn_irq_enabled(IPMIBmcSim * ibs)4448bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4458bfffbccSCorey Minyard {
4468bc8af69SCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) &&
4478bc8af69SCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
4488bc8af69SCorey Minyard IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
4498bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4508bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4518bfffbccSCorey Minyard }
4528bfffbccSCorey Minyard
ipmi_bmc_gen_event(IPMIBmc * b,uint8_t * evt,bool log)453cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
454cd60d85eSCédric Le Goater {
455cd60d85eSCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
456cd60d85eSCédric Le Goater IPMIInterface *s = ibs->parent.intf;
457cd60d85eSCédric Le Goater IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
458cd60d85eSCédric Le Goater
459cd60d85eSCédric Le Goater if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
460cd60d85eSCédric Le Goater return;
461cd60d85eSCédric Le Goater }
462cd60d85eSCédric Le Goater
463cd60d85eSCédric Le Goater if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
464cd60d85eSCédric Le Goater sel_add_event(ibs, evt);
465cd60d85eSCédric Le Goater }
466cd60d85eSCédric Le Goater
467cd60d85eSCédric Le Goater if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
468abb55b1aSMarkus Armbruster return;
469cd60d85eSCédric Le Goater }
470cd60d85eSCédric Le Goater
471cd60d85eSCédric Le Goater memcpy(ibs->evtbuf, evt, 16);
472cd60d85eSCédric Le Goater ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
473cd60d85eSCédric Le Goater k->set_atn(s, 1, attn_irq_enabled(ibs));
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,bool do_log)5148bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5158bfffbccSCorey Minyard unsigned int bit, unsigned int val,
516d9494ef9SNicholas Piggin uint8_t evd1, uint8_t evd2, uint8_t evd3,
517d9494ef9SNicholas Piggin bool do_log)
5188bfffbccSCorey Minyard {
5198bfffbccSCorey Minyard IPMISensor *sens;
5208bfffbccSCorey Minyard uint16_t mask;
5218bfffbccSCorey Minyard
5228bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) {
5238bfffbccSCorey Minyard return;
5248bfffbccSCorey Minyard }
5258bfffbccSCorey Minyard if (bit >= 16) {
5268bfffbccSCorey Minyard return;
5278bfffbccSCorey Minyard }
5288bfffbccSCorey Minyard
5298bfffbccSCorey Minyard mask = (1 << bit);
5308bfffbccSCorey Minyard sens = ibs->sensors + sensor;
5318bfffbccSCorey Minyard if (val) {
5328bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt;
5338bfffbccSCorey Minyard if (sens->assert_states & mask) {
5348bfffbccSCorey Minyard return; /* Already asserted */
5358bfffbccSCorey Minyard }
5368bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt;
537d9494ef9SNicholas Piggin if (do_log && (sens->assert_enable & mask & sens->assert_states)) {
5388bfffbccSCorey Minyard /* Send an event on assert */
5398bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5408bfffbccSCorey Minyard }
5418bfffbccSCorey Minyard } else {
5428bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt);
5438bfffbccSCorey Minyard if (sens->deassert_states & mask) {
5448bfffbccSCorey Minyard return; /* Already deasserted */
5458bfffbccSCorey Minyard }
5468bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt;
547d9494ef9SNicholas Piggin if (do_log && (sens->deassert_enable & mask & sens->deassert_states)) {
5488bfffbccSCorey Minyard /* Send an event on deassert */
5498bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5508bfffbccSCorey Minyard }
5518bfffbccSCorey Minyard }
5528bfffbccSCorey Minyard }
5538bfffbccSCorey Minyard
ipmi_init_sensors_from_sdrs(IPMIBmcSim * s)5548bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5558bfffbccSCorey Minyard {
5568bfffbccSCorey Minyard unsigned int i, pos;
5578bfffbccSCorey Minyard IPMISensor *sens;
5588bfffbccSCorey Minyard
5598bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) {
5608bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens));
5618bfffbccSCorey Minyard }
5628bfffbccSCorey Minyard
5638bfffbccSCorey Minyard pos = 0;
5648bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
565a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr =
566a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
567a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length;
5688bfffbccSCorey Minyard
5698bfffbccSCorey Minyard if (len < 20) {
5708bfffbccSCorey Minyard continue;
5718bfffbccSCorey Minyard }
572a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5738bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */
5748bfffbccSCorey Minyard }
5758bfffbccSCorey Minyard
57673d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) {
5778bfffbccSCorey Minyard continue;
5788bfffbccSCorey Minyard }
579a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number;
5808bfffbccSCorey Minyard
5818bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1);
582a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
583a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
584a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
585a2295f0aSCédric Le Goater sens->deassert_suppt =
586a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
587a2295f0aSCédric Le Goater sens->states_suppt =
588a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
589a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type;
590a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5918bfffbccSCorey Minyard
5928bfffbccSCorey Minyard /* Enable all the events that are supported. */
5938bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt;
5948bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt;
5958bfffbccSCorey Minyard }
5968bfffbccSCorey Minyard }
5978bfffbccSCorey Minyard
ipmi_sim_register_netfn(IPMIBmcSim * s,unsigned int netfn,const IPMINetfn * netfnd)598ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5998bfffbccSCorey Minyard const IPMINetfn *netfnd)
6008bfffbccSCorey Minyard {
60193a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6028bfffbccSCorey Minyard return -1;
6038bfffbccSCorey Minyard }
6048bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd;
6058bfffbccSCorey Minyard return 0;
6068bfffbccSCorey Minyard }
6078bfffbccSCorey Minyard
ipmi_get_handler(IPMIBmcSim * ibs,unsigned int netfn,unsigned int cmd)6084f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6094f298a4bSCédric Le Goater unsigned int netfn,
6104f298a4bSCédric Le Goater unsigned int cmd)
6114f298a4bSCédric Le Goater {
6124f298a4bSCédric Le Goater const IPMICmdHandler *hdl;
6134f298a4bSCédric Le Goater
6144f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6154f298a4bSCédric Le Goater return NULL;
6164f298a4bSCédric Le Goater }
6174f298a4bSCédric Le Goater
6184f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6194f298a4bSCédric Le Goater return NULL;
6204f298a4bSCédric Le Goater }
6214f298a4bSCédric Le Goater
6224f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6234f298a4bSCédric Le Goater if (!hdl->cmd_handler) {
6244f298a4bSCédric Le Goater return NULL;
6254f298a4bSCédric Le Goater }
6264f298a4bSCédric Le Goater
6274f298a4bSCédric Le Goater return hdl;
6284f298a4bSCédric Le Goater }
6294f298a4bSCédric Le Goater
next_timeout(IPMIBmcSim * ibs)6308bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6318bfffbccSCorey Minyard {
6328bfffbccSCorey Minyard int64_t next;
6338bfffbccSCorey Minyard if (ibs->watchdog_running) {
6348bfffbccSCorey Minyard next = ibs->watchdog_expiry;
6358bfffbccSCorey Minyard } else {
6368bfffbccSCorey Minyard /* Wait a minute */
6378bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL;
6388bfffbccSCorey Minyard }
6398bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next);
6408bfffbccSCorey Minyard }
6418bfffbccSCorey Minyard
ipmi_sim_handle_command(IPMIBmc * b,uint8_t * cmd,unsigned int cmd_len,unsigned int max_cmd_len,uint8_t msg_id)6428bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6438bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
6448bfffbccSCorey Minyard unsigned int max_cmd_len,
6458bfffbccSCorey Minyard uint8_t msg_id)
6468bfffbccSCorey Minyard {
6478bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6488bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
6498bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6504f298a4bSCédric Le Goater const IPMICmdHandler *hdl;
651a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6528bfffbccSCorey Minyard
6538bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */
6548bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */
655a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) {
6566acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
657d13ada5dSCédric Le Goater goto out;
658d13ada5dSCédric Le Goater }
659d13ada5dSCédric Le Goater
660a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04);
661a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]);
662a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */
6638bfffbccSCorey Minyard
6648bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */
6658bfffbccSCorey Minyard if (cmd_len < 2) {
6666acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6678bfffbccSCorey Minyard goto out;
6688bfffbccSCorey Minyard }
6698bfffbccSCorey Minyard if (cmd_len > max_cmd_len) {
6706acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6718bfffbccSCorey Minyard goto out;
6728bfffbccSCorey Minyard }
6738bfffbccSCorey Minyard
6748bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) {
6758bfffbccSCorey Minyard /* Only have stuff on LUN 0 */
6766acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6778bfffbccSCorey Minyard goto out;
6788bfffbccSCorey Minyard }
6798bfffbccSCorey Minyard
6804f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6814f298a4bSCédric Le Goater if (!hdl) {
6826acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6838bfffbccSCorey Minyard goto out;
6848bfffbccSCorey Minyard }
6858bfffbccSCorey Minyard
6864f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) {
6876acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6884f298a4bSCédric Le Goater goto out;
6894f298a4bSCédric Le Goater }
6904f298a4bSCédric Le Goater
691a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6928bfffbccSCorey Minyard
6938bfffbccSCorey Minyard out:
694a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6958bfffbccSCorey Minyard
6968bfffbccSCorey Minyard next_timeout(ibs);
6978bfffbccSCorey Minyard }
6988bfffbccSCorey Minyard
ipmi_sim_handle_timeout(IPMIBmcSim * ibs)6998bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7008bfffbccSCorey Minyard {
7018bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
7028bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
703d9494ef9SNicholas Piggin bool do_log = !IPMI_BMC_WATCHDOG_GET_DONT_LOG(ibs);
7048bfffbccSCorey Minyard
7058bfffbccSCorey Minyard if (!ibs->watchdog_running) {
7068bfffbccSCorey Minyard goto out;
7078bfffbccSCorey Minyard }
7088bfffbccSCorey Minyard
7098bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) {
7108bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7118bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI:
7128bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7138bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0);
7148bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
715d9494ef9SNicholas Piggin 0xc8, (2 << 4) | 0xf, 0xff,
716d9494ef9SNicholas Piggin do_log);
7178bfffbccSCorey Minyard break;
7188bfffbccSCorey Minyard
7198bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7208bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7218bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs));
7228bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
723d9494ef9SNicholas Piggin 0xc8, (3 << 4) | 0xf, 0xff,
724d9494ef9SNicholas Piggin do_log);
7258bfffbccSCorey Minyard break;
7268bfffbccSCorey Minyard
7278bfffbccSCorey Minyard default:
7288bfffbccSCorey Minyard goto do_full_expiry;
7298bfffbccSCorey Minyard }
7308bfffbccSCorey Minyard
7318bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1;
7328bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */
7338bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime();
7348bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7358bfffbccSCorey Minyard goto out;
7368bfffbccSCorey Minyard }
7378bfffbccSCorey Minyard
7388bfffbccSCorey Minyard do_full_expiry:
7398bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7408bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7418bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7428bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE:
7438bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
744d9494ef9SNicholas Piggin 0xc0, ibs->watchdog_use & 0xf, 0xff,
745d9494ef9SNicholas Piggin do_log);
7468bfffbccSCorey Minyard break;
7478bfffbccSCorey Minyard
7488bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET:
7498bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
750d9494ef9SNicholas Piggin 0xc1, ibs->watchdog_use & 0xf, 0xff,
751d9494ef9SNicholas Piggin do_log);
7528bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7538bfffbccSCorey Minyard break;
7548bfffbccSCorey Minyard
7558bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7568bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
757d9494ef9SNicholas Piggin 0xc2, ibs->watchdog_use & 0xf, 0xff,
758d9494ef9SNicholas Piggin do_log);
7598bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7608bfffbccSCorey Minyard break;
7618bfffbccSCorey Minyard
7628bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7638bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
764d9494ef9SNicholas Piggin 0xc3, ibs->watchdog_use & 0xf, 0xff,
765d9494ef9SNicholas Piggin do_log);
7668bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7678bfffbccSCorey Minyard break;
7688bfffbccSCorey Minyard }
7698bfffbccSCorey Minyard
7708bfffbccSCorey Minyard out:
7718bfffbccSCorey Minyard next_timeout(ibs);
7728bfffbccSCorey Minyard }
7738bfffbccSCorey Minyard
chassis_capabilities(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7748bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
776a580d820SCédric Le Goater RspBuffer *rsp)
7778bfffbccSCorey Minyard {
778a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
779a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
780a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
781a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
782a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr);
7838bfffbccSCorey Minyard }
7848bfffbccSCorey Minyard
chassis_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7858bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7868bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
787a580d820SCédric Le Goater RspBuffer *rsp)
7888bfffbccSCorey Minyard {
789a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
790a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
791a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
792a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
7938bfffbccSCorey Minyard }
7948bfffbccSCorey Minyard
chassis_control(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7958bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7968bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
797a580d820SCédric Le Goater RspBuffer *rsp)
7988bfffbccSCorey Minyard {
7998bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8008bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8018bfffbccSCorey Minyard
8028bfffbccSCorey Minyard switch (cmd[2] & 0xf) {
8038bfffbccSCorey Minyard case 0: /* power down */
8046acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8058bfffbccSCorey Minyard break;
8068bfffbccSCorey Minyard case 1: /* power up */
8076acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8088bfffbccSCorey Minyard break;
8098bfffbccSCorey Minyard case 2: /* power cycle */
8106acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8118bfffbccSCorey Minyard break;
8128bfffbccSCorey Minyard case 3: /* hard reset */
8136acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8148bfffbccSCorey Minyard break;
8158bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */
8166acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8178bfffbccSCorey Minyard break;
8188bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */
8196acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s,
8206acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8218bfffbccSCorey Minyard break;
8228bfffbccSCorey Minyard default:
8236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8248bfffbccSCorey Minyard return;
8258bfffbccSCorey Minyard }
826d13ada5dSCédric Le Goater }
8278bfffbccSCorey Minyard
chassis_get_sys_restart_cause(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)828b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
829b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
830a580d820SCédric Le Goater RspBuffer *rsp)
831a580d820SCédric Le Goater
832b7088392SCédric Le Goater {
833a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
834a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */
835b7088392SCédric Le Goater }
836b7088392SCédric Le Goater
get_device_id(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8378bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8388bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
839a580d820SCédric Le Goater RspBuffer *rsp)
8408bfffbccSCorey Minyard {
841a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id);
842a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf);
843a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
844a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2);
845a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version);
846a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
84720b23364SCorey Minyard rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
84820b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
84920b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
85020b23364SCorey Minyard rsp_buffer_push(rsp, ibs->product_id & 0xff);
85120b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8528bfffbccSCorey Minyard }
8538bfffbccSCorey Minyard
set_global_enables(IPMIBmcSim * ibs,uint8_t val)8548bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8558bfffbccSCorey Minyard {
8568bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8578bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8588bfffbccSCorey Minyard bool irqs_on;
8598bfffbccSCorey Minyard
8608bfffbccSCorey Minyard ibs->bmc_global_enables = val;
8618bfffbccSCorey Minyard
8628bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8638bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8648bfffbccSCorey Minyard
8658bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on);
8668bfffbccSCorey Minyard }
8678bfffbccSCorey Minyard
cold_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8688bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8698bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
870a580d820SCédric Le Goater RspBuffer *rsp)
8718bfffbccSCorey Minyard {
8728bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8738bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8748bfffbccSCorey Minyard
8758bfffbccSCorey Minyard /* Disable all interrupts */
8768bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8778bfffbccSCorey Minyard
8788bfffbccSCorey Minyard if (k->reset) {
8798bfffbccSCorey Minyard k->reset(s, true);
8808bfffbccSCorey Minyard }
8818bfffbccSCorey Minyard }
8828bfffbccSCorey Minyard
warm_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8838bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8848bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
885a580d820SCédric Le Goater RspBuffer *rsp)
8868bfffbccSCorey Minyard {
8878bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
8888bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8898bfffbccSCorey Minyard
8908bfffbccSCorey Minyard if (k->reset) {
8918bfffbccSCorey Minyard k->reset(s, false);
8928bfffbccSCorey Minyard }
8938bfffbccSCorey Minyard }
set_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)89452ba4d50SCédric Le Goater static void set_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 {
89852ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2];
89952ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3];
90052ba4d50SCédric Le Goater }
90152ba4d50SCédric Le Goater
get_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)90252ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
90352ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
904a580d820SCédric Le Goater RspBuffer *rsp)
90552ba4d50SCédric Le Goater {
906a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
907a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
90852ba4d50SCédric Le Goater }
90952ba4d50SCédric Le Goater
get_device_guid(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)91052ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
91152ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
912a580d820SCédric Le Goater RspBuffer *rsp)
91352ba4d50SCédric Le Goater {
91452ba4d50SCédric Le Goater unsigned int i;
91552ba4d50SCédric Le Goater
9167b0cd78bSCorey Minyard /* An uninitialized uuid is all zeros, use that to know if it is set. */
91752ba4d50SCédric Le Goater for (i = 0; i < 16; i++) {
9187b0cd78bSCorey Minyard if (ibs->uuid.data[i]) {
9197b0cd78bSCorey Minyard goto uuid_set;
9207b0cd78bSCorey Minyard }
9217b0cd78bSCorey Minyard }
9227b0cd78bSCorey Minyard /* No uuid is set, return an error. */
9237b0cd78bSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
9247b0cd78bSCorey Minyard return;
9257b0cd78bSCorey Minyard
9267b0cd78bSCorey Minyard uuid_set:
9277b0cd78bSCorey Minyard for (i = 0; i < 16; i++) {
9287b0cd78bSCorey Minyard rsp_buffer_push(rsp, ibs->uuid.data[i]);
92952ba4d50SCédric Le Goater }
93052ba4d50SCédric Le Goater }
9318bfffbccSCorey Minyard
set_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9328bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
934a580d820SCédric Le Goater RspBuffer *rsp)
9358bfffbccSCorey Minyard {
936dacb3e70SNicholas Piggin uint8_t val = cmd[2];
937dacb3e70SNicholas Piggin
938dacb3e70SNicholas Piggin if (val & ~IPMI_BMC_GLOBAL_ENABLES_SUPPORTED) {
939dacb3e70SNicholas Piggin rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
940dacb3e70SNicholas Piggin return;
941dacb3e70SNicholas Piggin }
942dacb3e70SNicholas Piggin
943dacb3e70SNicholas Piggin set_global_enables(ibs, val);
9448bfffbccSCorey Minyard }
9458bfffbccSCorey Minyard
get_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9468bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9478bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
948a580d820SCédric Le Goater RspBuffer *rsp)
9498bfffbccSCorey Minyard {
950a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables);
9518bfffbccSCorey Minyard }
9528bfffbccSCorey Minyard
clr_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9538bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9548bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
955a580d820SCédric Le Goater RspBuffer *rsp)
9568bfffbccSCorey Minyard {
9578bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
9588bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9598bfffbccSCorey Minyard
9608bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2];
9618bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9628bfffbccSCorey Minyard }
9638bfffbccSCorey Minyard
get_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9648bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9658bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
966a580d820SCédric Le Goater RspBuffer *rsp)
9678bfffbccSCorey Minyard {
968a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags);
9698bfffbccSCorey Minyard }
9708bfffbccSCorey Minyard
read_evt_msg_buf(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9718bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9728bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
973a580d820SCédric Le Goater RspBuffer *rsp)
9748bfffbccSCorey Minyard {
9758bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
9768bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9778bfffbccSCorey Minyard unsigned int i;
9788bfffbccSCorey Minyard
9798bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9806acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80);
981d13ada5dSCédric Le Goater return;
9828bfffbccSCorey Minyard }
9838bfffbccSCorey Minyard for (i = 0; i < 16; i++) {
984a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]);
9858bfffbccSCorey Minyard }
9868bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9878bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9888bfffbccSCorey Minyard }
9898bfffbccSCorey Minyard
get_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9908bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9918bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
992a580d820SCédric Le Goater RspBuffer *rsp)
9938bfffbccSCorey Minyard {
9948bfffbccSCorey Minyard IPMIRcvBufEntry *msg;
9958bfffbccSCorey Minyard
9968bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
998abb55b1aSMarkus Armbruster return;
9998bfffbccSCorey Minyard }
1000a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */
10018bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs);
1002a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len);
10038bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
10048bfffbccSCorey Minyard g_free(msg);
10058bfffbccSCorey Minyard
10068bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10078bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
10088bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10098bfffbccSCorey Minyard
10108bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10118bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10128bfffbccSCorey Minyard }
10138bfffbccSCorey Minyard }
10148bfffbccSCorey Minyard
10158bfffbccSCorey Minyard static unsigned char
ipmb_checksum(unsigned char * data,int size,unsigned char csum)10168bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10178bfffbccSCorey Minyard {
10188bfffbccSCorey Minyard for (; size > 0; size--, data++) {
10198bfffbccSCorey Minyard csum += *data;
10208bfffbccSCorey Minyard }
10218bfffbccSCorey Minyard
10228bfffbccSCorey Minyard return -csum;
10238bfffbccSCorey Minyard }
10248bfffbccSCorey Minyard
send_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)10258bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1027a580d820SCédric Le Goater RspBuffer *rsp)
10288bfffbccSCorey Minyard {
10298bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
10308bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10318bfffbccSCorey Minyard IPMIRcvBufEntry *msg;
10328bfffbccSCorey Minyard uint8_t *buf;
10338bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq;
10348bfffbccSCorey Minyard
10357f9e7af4SNicholas Piggin if (cmd[2] != IPMI_CHANNEL_IPMB) {
10367f9e7af4SNicholas Piggin /* We only handle channel 0h (IPMB) with no options */
10376acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1038d13ada5dSCédric Le Goater return;
10398bfffbccSCorey Minyard }
10408bfffbccSCorey Minyard
10414f298a4bSCédric Le Goater if (cmd_len < 10) {
10426acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10434f298a4bSCédric Le Goater return;
10444f298a4bSCédric Le Goater }
10454f298a4bSCédric Le Goater
10468bfffbccSCorey Minyard if (cmd[3] != 0x40) {
10478bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */
10486acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1049d13ada5dSCédric Le Goater return;
10508bfffbccSCorey Minyard }
10518bfffbccSCorey Minyard
10528bfffbccSCorey Minyard cmd += 3; /* Skip the header. */
10538bfffbccSCorey Minyard cmd_len -= 3;
10548bfffbccSCorey Minyard
10558bfffbccSCorey Minyard /*
10568bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will
10578bfffbccSCorey Minyard * be returned in the response.
10588bfffbccSCorey Minyard */
10598bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10608bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */
1061d13ada5dSCédric Le Goater return; /* No response */
10628bfffbccSCorey Minyard }
10638bfffbccSCorey Minyard
10648bfffbccSCorey Minyard netfn = cmd[1] >> 2;
10658bfffbccSCorey Minyard rqLun = cmd[4] & 0x3;
10668bfffbccSCorey Minyard rsLun = cmd[1] & 0x3;
10678bfffbccSCorey Minyard rqSeq = cmd[4] >> 2;
10688bfffbccSCorey Minyard
10698bfffbccSCorey Minyard if (rqLun != 2) {
10708bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */
1071d13ada5dSCédric Le Goater return;
10728bfffbccSCorey Minyard }
10738bfffbccSCorey Minyard
10748bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg));
10758bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10768bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10778bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */
10788bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun;
10798bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */
10808bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */
10818bfffbccSCorey Minyard msg->len = 6;
10828bfffbccSCorey Minyard
10838bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10848bfffbccSCorey Minyard /* Not a command we handle. */
10858bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD;
10868bfffbccSCorey Minyard goto end_msg;
10878bfffbccSCorey Minyard }
10888bfffbccSCorey Minyard
10898bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */
10908bfffbccSCorey Minyard buf[0] = 0;
10918bfffbccSCorey Minyard buf[1] = 0;
10928bfffbccSCorey Minyard buf[2] = 0;
10938bfffbccSCorey Minyard buf[3] = 0;
10948bfffbccSCorey Minyard buf[4] = 0x51;
10958bfffbccSCorey Minyard buf[5] = 0;
10968bfffbccSCorey Minyard buf[6] = 0;
10978bfffbccSCorey Minyard buf[7] = 0;
10988bfffbccSCorey Minyard buf[8] = 0;
10998bfffbccSCorey Minyard buf[9] = 0;
11008bfffbccSCorey Minyard buf[10] = 0;
11018bfffbccSCorey Minyard msg->len += 11;
11028bfffbccSCorey Minyard
11038bfffbccSCorey Minyard end_msg:
11048bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
11058bfffbccSCorey Minyard msg->len++;
11068bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
11078bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
11088bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs));
11098bfffbccSCorey Minyard }
11108bfffbccSCorey Minyard
do_watchdog_reset(IPMIBmcSim * ibs)11118bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11128bfffbccSCorey Minyard {
11138bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11148bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) {
11158bfffbccSCorey Minyard ibs->watchdog_running = 0;
11168bfffbccSCorey Minyard return;
11178bfffbccSCorey Minyard }
11188bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0;
11198bfffbccSCorey Minyard
11208bfffbccSCorey Minyard
11218bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */
11228bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime();
11238bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11248bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11258bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11268bfffbccSCorey Minyard }
11278bfffbccSCorey Minyard ibs->watchdog_running = 1;
11288bfffbccSCorey Minyard }
11298bfffbccSCorey Minyard
reset_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11308bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11318bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1132a580d820SCédric Le Goater RspBuffer *rsp)
11338bfffbccSCorey Minyard {
11348bfffbccSCorey Minyard if (!ibs->watchdog_initialized) {
11356acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80);
1136d13ada5dSCédric Le Goater return;
11378bfffbccSCorey Minyard }
11388bfffbccSCorey Minyard do_watchdog_reset(ibs);
11398bfffbccSCorey Minyard }
11408bfffbccSCorey Minyard
set_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11418bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11428bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1143a580d820SCédric Le Goater RspBuffer *rsp)
11448bfffbccSCorey Minyard {
11458bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf;
11468bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11478bfffbccSCorey Minyard unsigned int val;
11488bfffbccSCorey Minyard
11498bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */
11508bfffbccSCorey Minyard if (val == 0 || val > 5) {
11516acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1152d13ada5dSCédric Le Goater return;
11538bfffbccSCorey Minyard }
11548bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */
11558bfffbccSCorey Minyard switch (val) {
11568bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE:
11578bfffbccSCorey Minyard break;
11588bfffbccSCorey Minyard
11598bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET:
11606acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11618bfffbccSCorey Minyard break;
11628bfffbccSCorey Minyard
11638bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11646acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11658bfffbccSCorey Minyard break;
11668bfffbccSCorey Minyard
11678bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11686acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11698bfffbccSCorey Minyard break;
11708bfffbccSCorey Minyard
11718bfffbccSCorey Minyard default:
11726acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11738bfffbccSCorey Minyard }
1174a580d820SCédric Le Goater if (rsp->buffer[2]) {
11756acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1176d13ada5dSCédric Le Goater return;
11778bfffbccSCorey Minyard }
11788bfffbccSCorey Minyard
11798bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11808bfffbccSCorey Minyard switch (val) {
11818bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11828bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE:
11838bfffbccSCorey Minyard break;
11848bfffbccSCorey Minyard
11858bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI:
11866af94767SCorey Minyard if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11878bfffbccSCorey Minyard /* NMI not supported. */
11886acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1189d13ada5dSCédric Le Goater return;
11908bfffbccSCorey Minyard }
119137eebb86SCorey Minyard break;
119237eebb86SCorey Minyard
11938bfffbccSCorey Minyard default:
11948bfffbccSCorey Minyard /* We don't support PRE_SMI */
11956acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1196d13ada5dSCédric Le Goater return;
11978bfffbccSCorey Minyard }
11988bfffbccSCorey Minyard
11998bfffbccSCorey Minyard ibs->watchdog_initialized = 1;
12008bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
12018bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
12028bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4];
12038bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5];
12048bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
12058bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
12068bfffbccSCorey Minyard do_watchdog_reset(ibs);
12078bfffbccSCorey Minyard } else {
12088bfffbccSCorey Minyard ibs->watchdog_running = 0;
12098bfffbccSCorey Minyard }
12108bfffbccSCorey Minyard }
12118bfffbccSCorey Minyard
get_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12128bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12138bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1214a580d820SCédric Le Goater RspBuffer *rsp)
12158bfffbccSCorey Minyard {
1216a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use);
1217a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action);
1218a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1219a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired);
1220fb45770bSCorey Minyard rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1221fb45770bSCorey Minyard rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12228bfffbccSCorey Minyard if (ibs->watchdog_running) {
12238bfffbccSCorey Minyard long timeout;
12248bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12258bfffbccSCorey Minyard / 100000000);
1226a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff);
1227a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12288bfffbccSCorey Minyard } else {
1229a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
1230a580d820SCédric Le Goater rsp_buffer_push(rsp, 0);
12318bfffbccSCorey Minyard }
12328bfffbccSCorey Minyard }
12338bfffbccSCorey Minyard
get_channel_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12347f9e7af4SNicholas Piggin static void get_channel_info(IPMIBmcSim *ibs,
12357f9e7af4SNicholas Piggin uint8_t *cmd, unsigned int cmd_len,
12367f9e7af4SNicholas Piggin RspBuffer *rsp)
12377f9e7af4SNicholas Piggin {
12387f9e7af4SNicholas Piggin IPMIInterface *s = ibs->parent.intf;
12397f9e7af4SNicholas Piggin IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
12407f9e7af4SNicholas Piggin IPMIFwInfo info = {};
12417f9e7af4SNicholas Piggin uint8_t ch = cmd[2] & 0x0f;
12427f9e7af4SNicholas Piggin
12437f9e7af4SNicholas Piggin /* Only define channel 0h (IPMB) and Fh (system interface) */
12447f9e7af4SNicholas Piggin
12457f9e7af4SNicholas Piggin if (ch == 0x0e) { /* "This channel" */
12467f9e7af4SNicholas Piggin ch = IPMI_CHANNEL_SYSTEM;
12477f9e7af4SNicholas Piggin }
12487f9e7af4SNicholas Piggin rsp_buffer_push(rsp, ch);
12497f9e7af4SNicholas Piggin
12507f9e7af4SNicholas Piggin if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) {
12517f9e7af4SNicholas Piggin /* Not a supported channel */
12527f9e7af4SNicholas Piggin rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
12537f9e7af4SNicholas Piggin return;
12547f9e7af4SNicholas Piggin }
12557f9e7af4SNicholas Piggin
12567f9e7af4SNicholas Piggin if (k->get_fwinfo) {
12577f9e7af4SNicholas Piggin k->get_fwinfo(s, &info);
12587f9e7af4SNicholas Piggin }
12597f9e7af4SNicholas Piggin
12607f9e7af4SNicholas Piggin if (ch == IPMI_CHANNEL_IPMB) {
12617f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB);
12627f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
12637f9e7af4SNicholas Piggin } else { /* IPMI_CHANNEL_SYSTEM */
12647f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM);
12657f9e7af4SNicholas Piggin rsp_buffer_push(rsp, info.ipmi_channel_protocol);
12667f9e7af4SNicholas Piggin }
12677f9e7af4SNicholas Piggin
12687f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); /* Session-less */
12697f9e7af4SNicholas Piggin
12707f9e7af4SNicholas Piggin /* IPMI Enterprise Number for Vendor ID */
12717f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0xf2);
12727f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x1b);
12737f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00);
12747f9e7af4SNicholas Piggin
12757f9e7af4SNicholas Piggin if (ch == IPMI_CHANNEL_SYSTEM) {
12767f9e7af4SNicholas Piggin uint8_t irq;
12777f9e7af4SNicholas Piggin
12787f9e7af4SNicholas Piggin if (info.irq_source == IPMI_ISA_IRQ) {
12797f9e7af4SNicholas Piggin irq = info.interrupt_number;
12807f9e7af4SNicholas Piggin } else if (info.irq_source == IPMI_PCI_IRQ) {
12817f9e7af4SNicholas Piggin irq = 0x10 + info.interrupt_number;
12827f9e7af4SNicholas Piggin } else {
12837f9e7af4SNicholas Piggin irq = 0xff; /* no interrupt / unspecified */
12847f9e7af4SNicholas Piggin }
12857f9e7af4SNicholas Piggin
12867f9e7af4SNicholas Piggin /* Both interrupts use the same irq number */
12877f9e7af4SNicholas Piggin rsp_buffer_push(rsp, irq);
12887f9e7af4SNicholas Piggin rsp_buffer_push(rsp, irq);
12897f9e7af4SNicholas Piggin } else {
12907f9e7af4SNicholas Piggin /* Reserved */
12917f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00);
12927f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00);
12937f9e7af4SNicholas Piggin }
12947f9e7af4SNicholas Piggin }
12957f9e7af4SNicholas Piggin
get_sdr_rep_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12968bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12978bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1298a580d820SCédric Le Goater RspBuffer *rsp)
12998bfffbccSCorey Minyard {
13008bfffbccSCorey Minyard unsigned int i;
13018bfffbccSCorey Minyard
1302a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1303a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1304a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1305a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1306a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
13078bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1308a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
13098bfffbccSCorey Minyard }
13108bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1311a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
13128bfffbccSCorey Minyard }
13138bfffbccSCorey Minyard /* Only modal support, reserve supported */
1314a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
13158bfffbccSCorey Minyard }
13168bfffbccSCorey Minyard
reserve_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13178bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
13188bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1319a580d820SCédric Le Goater RspBuffer *rsp)
13208bfffbccSCorey Minyard {
1321a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1322a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
13238bfffbccSCorey Minyard }
13248bfffbccSCorey Minyard
get_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13258bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
13268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1327a580d820SCédric Le Goater RspBuffer *rsp)
13288bfffbccSCorey Minyard {
13298bfffbccSCorey Minyard unsigned int pos;
13308bfffbccSCorey Minyard uint16_t nextrec;
1331a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh;
13328bfffbccSCorey Minyard
13338bfffbccSCorey Minyard if (cmd[6]) {
13347f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13356acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13367f996411SCédric Le Goater return;
13378bfffbccSCorey Minyard }
13387f996411SCédric Le Goater }
13397f996411SCédric Le Goater
13408bfffbccSCorey Minyard pos = 0;
13418bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
13428bfffbccSCorey Minyard &pos, &nextrec)) {
13436acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1344d13ada5dSCédric Le Goater return;
13458bfffbccSCorey Minyard }
1346a2295f0aSCédric Le Goater
1347a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1348a2295f0aSCédric Le Goater
1349a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) {
13506acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1351d13ada5dSCédric Le Goater return;
13528bfffbccSCorey Minyard }
13538bfffbccSCorey Minyard
1354a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff);
1355a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
13568bfffbccSCorey Minyard
13578bfffbccSCorey Minyard if (cmd[7] == 0xff) {
1358a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
13598bfffbccSCorey Minyard }
13608bfffbccSCorey Minyard
1361a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13626acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1363d13ada5dSCédric Le Goater return;
13648bfffbccSCorey Minyard }
1365a580d820SCédric Le Goater
1366a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13678bfffbccSCorey Minyard }
13688bfffbccSCorey Minyard
add_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13698bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13708bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1371a580d820SCédric Le Goater RspBuffer *rsp)
13728bfffbccSCorey Minyard {
13738bfffbccSCorey Minyard uint16_t recid;
1374a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13758bfffbccSCorey Minyard
1376a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13776acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1378d13ada5dSCédric Le Goater return;
13798bfffbccSCorey Minyard }
1380a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff);
1381a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13828bfffbccSCorey Minyard }
13838bfffbccSCorey Minyard
clear_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13848bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13858bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1386a580d820SCédric Le Goater RspBuffer *rsp)
13878bfffbccSCorey Minyard {
13887f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13896acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13907f996411SCédric Le Goater return;
13917f996411SCédric Le Goater }
13927f996411SCédric Le Goater
13938bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13946acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1395d13ada5dSCédric Le Goater return;
13968bfffbccSCorey Minyard }
13978bfffbccSCorey Minyard if (cmd[7] == 0xaa) {
13988bfffbccSCorey Minyard ibs->sdr.next_free = 0;
13998bfffbccSCorey Minyard ibs->sdr.overflow = 0;
14008bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear);
1401a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
14028bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr);
14038bfffbccSCorey Minyard } else if (cmd[7] == 0) {
1404a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
14058bfffbccSCorey Minyard } else {
14066acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
14078bfffbccSCorey Minyard return;
14088bfffbccSCorey Minyard }
1409d13ada5dSCédric Le Goater }
14108bfffbccSCorey Minyard
get_sel_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)14118bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
14128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1413a580d820SCédric Le Goater RspBuffer *rsp)
14148bfffbccSCorey Minyard {
14158bfffbccSCorey Minyard unsigned int i, val;
14168bfffbccSCorey Minyard
1417a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1418a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1419a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
14208bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1421a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff);
1422a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff);
14238bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1424a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
14258bfffbccSCorey Minyard }
14268bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
1427a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
14288bfffbccSCorey Minyard }
14298bfffbccSCorey Minyard /* Only support Reserve SEL */
1430a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
14318bfffbccSCorey Minyard }
14328bfffbccSCorey Minyard
get_fru_area_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1433540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1434540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1435540c07d3SCédric Le Goater RspBuffer *rsp)
1436540c07d3SCédric Le Goater {
1437540c07d3SCédric Le Goater uint8_t fruid;
1438540c07d3SCédric Le Goater uint16_t fru_entry_size;
1439540c07d3SCédric Le Goater
1440540c07d3SCédric Le Goater fruid = cmd[2];
1441540c07d3SCédric Le Goater
1442540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) {
1443540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1444540c07d3SCédric Le Goater return;
1445540c07d3SCédric Le Goater }
1446540c07d3SCédric Le Goater
1447540c07d3SCédric Le Goater fru_entry_size = ibs->fru.areasize;
1448540c07d3SCédric Le Goater
1449540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size & 0xff);
1450540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1451540c07d3SCédric Le Goater rsp_buffer_push(rsp, 0x0);
1452540c07d3SCédric Le Goater }
1453540c07d3SCédric Le Goater
read_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1454540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1455540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1456540c07d3SCédric Le Goater RspBuffer *rsp)
1457540c07d3SCédric Le Goater {
1458540c07d3SCédric Le Goater uint8_t fruid;
1459540c07d3SCédric Le Goater uint16_t offset;
1460540c07d3SCédric Le Goater int i;
1461540c07d3SCédric Le Goater uint8_t *fru_entry;
1462540c07d3SCédric Le Goater unsigned int count;
1463540c07d3SCédric Le Goater
1464540c07d3SCédric Le Goater fruid = cmd[2];
1465540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8);
1466540c07d3SCédric Le Goater
1467540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) {
1468540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1469540c07d3SCédric Le Goater return;
1470540c07d3SCédric Le Goater }
1471540c07d3SCédric Le Goater
1472540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) {
1473540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1474540c07d3SCédric Le Goater return;
1475540c07d3SCédric Le Goater }
1476540c07d3SCédric Le Goater
1477540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1478540c07d3SCédric Le Goater
1479540c07d3SCédric Le Goater count = MIN(cmd[5], ibs->fru.areasize - offset);
1480540c07d3SCédric Le Goater
1481540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff);
1482540c07d3SCédric Le Goater for (i = 0; i < count; i++) {
1483540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry[offset + i]);
1484540c07d3SCédric Le Goater }
1485540c07d3SCédric Le Goater }
1486540c07d3SCédric Le Goater
write_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1487540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1488540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1489540c07d3SCédric Le Goater RspBuffer *rsp)
1490540c07d3SCédric Le Goater {
1491540c07d3SCédric Le Goater uint8_t fruid;
1492540c07d3SCédric Le Goater uint16_t offset;
1493540c07d3SCédric Le Goater uint8_t *fru_entry;
1494540c07d3SCédric Le Goater unsigned int count;
1495540c07d3SCédric Le Goater
1496540c07d3SCédric Le Goater fruid = cmd[2];
1497540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8);
1498540c07d3SCédric Le Goater
1499540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) {
1500540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1501540c07d3SCédric Le Goater return;
1502540c07d3SCédric Le Goater }
1503540c07d3SCédric Le Goater
1504540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) {
1505540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1506540c07d3SCédric Le Goater return;
1507540c07d3SCédric Le Goater }
1508540c07d3SCédric Le Goater
1509540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1510540c07d3SCédric Le Goater
1511540c07d3SCédric Le Goater count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1512540c07d3SCédric Le Goater
1513540c07d3SCédric Le Goater memcpy(fru_entry + offset, cmd + 5, count);
1514540c07d3SCédric Le Goater
1515540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff);
1516540c07d3SCédric Le Goater }
1517540c07d3SCédric Le Goater
reserve_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15188bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
15198bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1520a580d820SCédric Le Goater RspBuffer *rsp)
15218bfffbccSCorey Minyard {
1522a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1523a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
15248bfffbccSCorey Minyard }
15258bfffbccSCorey Minyard
get_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15268bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
15278bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1528a580d820SCédric Le Goater RspBuffer *rsp)
15298bfffbccSCorey Minyard {
15308bfffbccSCorey Minyard unsigned int val;
15318bfffbccSCorey Minyard
15328bfffbccSCorey Minyard if (cmd[6]) {
15337f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15346acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15357f996411SCédric Le Goater return;
15367f996411SCédric Le Goater }
15378bfffbccSCorey Minyard }
15388bfffbccSCorey Minyard if (ibs->sel.next_free == 0) {
15396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1540d13ada5dSCédric Le Goater return;
15418bfffbccSCorey Minyard }
15428bfffbccSCorey Minyard if (cmd[6] > 15) {
15436acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1544d13ada5dSCédric Le Goater return;
15458bfffbccSCorey Minyard }
15468bfffbccSCorey Minyard if (cmd[7] == 0xff) {
15478bfffbccSCorey Minyard cmd[7] = 16;
15488bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) {
15496acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1550d13ada5dSCédric Le Goater return;
15518bfffbccSCorey Minyard } else {
15528bfffbccSCorey Minyard cmd[7] += cmd[6];
15538bfffbccSCorey Minyard }
15548bfffbccSCorey Minyard
15558bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8);
15568bfffbccSCorey Minyard if (val == 0xffff) {
15578bfffbccSCorey Minyard val = ibs->sel.next_free - 1;
15588bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) {
15596acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1560d13ada5dSCédric Le Goater return;
15618bfffbccSCorey Minyard }
15628bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) {
1563a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff);
1564a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff);
15658bfffbccSCorey Minyard } else {
1566a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff);
1567a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15688bfffbccSCorey Minyard }
15698bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) {
1570a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15718bfffbccSCorey Minyard }
15728bfffbccSCorey Minyard }
15738bfffbccSCorey Minyard
add_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15748bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1576a580d820SCédric Le Goater RspBuffer *rsp)
15778bfffbccSCorey Minyard {
15788bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) {
15796acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1580d13ada5dSCédric Le Goater return;
15818bfffbccSCorey Minyard }
15828bfffbccSCorey Minyard /* sel_add_event fills in the record number. */
1583a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]);
1584a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]);
15858bfffbccSCorey Minyard }
15868bfffbccSCorey Minyard
clear_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15878bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1589a580d820SCédric Le Goater RspBuffer *rsp)
15908bfffbccSCorey Minyard {
15917f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15926acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15937f996411SCédric Le Goater return;
15947f996411SCédric Le Goater }
15957f996411SCédric Le Goater
15968bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1598d13ada5dSCédric Le Goater return;
15998bfffbccSCorey Minyard }
16008bfffbccSCorey Minyard if (cmd[7] == 0xaa) {
16018bfffbccSCorey Minyard ibs->sel.next_free = 0;
16028bfffbccSCorey Minyard ibs->sel.overflow = 0;
16038bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear);
1604a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
16058bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel);
16068bfffbccSCorey Minyard } else if (cmd[7] == 0) {
1607a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */
16088bfffbccSCorey Minyard } else {
16096acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
16108bfffbccSCorey Minyard return;
16118bfffbccSCorey Minyard }
1612d13ada5dSCédric Le Goater }
16138bfffbccSCorey Minyard
get_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16148bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
16158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1616a580d820SCédric Le Goater RspBuffer *rsp)
16178bfffbccSCorey Minyard {
16188bfffbccSCorey Minyard uint32_t val;
16198bfffbccSCorey Minyard struct ipmi_time now;
16208bfffbccSCorey Minyard
16218bfffbccSCorey Minyard ipmi_gettime(&now);
16228bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset;
1623a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff);
1624a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff);
1625a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff);
1626a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff);
16278bfffbccSCorey Minyard }
16288bfffbccSCorey Minyard
set_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16298bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
16308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1631a580d820SCédric Le Goater RspBuffer *rsp)
16328bfffbccSCorey Minyard {
16338bfffbccSCorey Minyard uint32_t val;
16348bfffbccSCorey Minyard struct ipmi_time now;
16358bfffbccSCorey Minyard
16368bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
16378bfffbccSCorey Minyard ipmi_gettime(&now);
16388bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val);
16398bfffbccSCorey Minyard }
16408bfffbccSCorey Minyard
platform_event_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16419380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
16429380d2edSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
16439380d2edSCorey Minyard RspBuffer *rsp)
16449380d2edSCorey Minyard {
16459380d2edSCorey Minyard uint8_t event[16];
16469380d2edSCorey Minyard
16479380d2edSCorey Minyard event[2] = 2; /* System event record */
16489380d2edSCorey Minyard event[7] = cmd[2]; /* Generator ID */
16499380d2edSCorey Minyard event[8] = 0;
16509380d2edSCorey Minyard event[9] = cmd[3]; /* EvMRev */
16519380d2edSCorey Minyard event[10] = cmd[4]; /* Sensor type */
16529380d2edSCorey Minyard event[11] = cmd[5]; /* Sensor number */
16539380d2edSCorey Minyard event[12] = cmd[6]; /* Event dir / Event type */
16549380d2edSCorey Minyard event[13] = cmd[7]; /* Event data 1 */
16559380d2edSCorey Minyard event[14] = cmd[8]; /* Event data 2 */
16569380d2edSCorey Minyard event[15] = cmd[9]; /* Event data 3 */
16579380d2edSCorey Minyard
16589380d2edSCorey Minyard if (sel_add_event(ibs, event)) {
16599380d2edSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
16609380d2edSCorey Minyard }
16619380d2edSCorey Minyard }
16629380d2edSCorey Minyard
set_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16638bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
16648bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1665a580d820SCédric Le Goater RspBuffer *rsp)
16668bfffbccSCorey Minyard {
16678bfffbccSCorey Minyard IPMISensor *sens;
16688bfffbccSCorey Minyard
166973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
16708bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16716acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1672d13ada5dSCédric Le Goater return;
16738bfffbccSCorey Minyard }
16748bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
16758bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) {
16768bfffbccSCorey Minyard case 0: /* Do not change */
16778bfffbccSCorey Minyard break;
16788bfffbccSCorey Minyard case 1: /* Enable bits */
16798bfffbccSCorey Minyard if (cmd_len > 4) {
16808bfffbccSCorey Minyard sens->assert_enable |= cmd[4];
16818bfffbccSCorey Minyard }
16828bfffbccSCorey Minyard if (cmd_len > 5) {
16838bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8;
16848bfffbccSCorey Minyard }
16858bfffbccSCorey Minyard if (cmd_len > 6) {
16868bfffbccSCorey Minyard sens->deassert_enable |= cmd[6];
16878bfffbccSCorey Minyard }
16888bfffbccSCorey Minyard if (cmd_len > 7) {
16898bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8;
16908bfffbccSCorey Minyard }
16918bfffbccSCorey Minyard break;
16928bfffbccSCorey Minyard case 2: /* Disable bits */
16938bfffbccSCorey Minyard if (cmd_len > 4) {
16948bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4];
16958bfffbccSCorey Minyard }
16968bfffbccSCorey Minyard if (cmd_len > 5) {
16978bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8);
16988bfffbccSCorey Minyard }
16998bfffbccSCorey Minyard if (cmd_len > 6) {
17008bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6];
17018bfffbccSCorey Minyard }
17028bfffbccSCorey Minyard if (cmd_len > 7) {
17038bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8);
17048bfffbccSCorey Minyard }
17058bfffbccSCorey Minyard break;
17068bfffbccSCorey Minyard case 3:
17076acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1708d13ada5dSCédric Le Goater return;
17098bfffbccSCorey Minyard }
17108bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
17118bfffbccSCorey Minyard }
17128bfffbccSCorey Minyard
get_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17138bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
17148bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1715a580d820SCédric Le Goater RspBuffer *rsp)
17168bfffbccSCorey Minyard {
17178bfffbccSCorey Minyard IPMISensor *sens;
17188bfffbccSCorey Minyard
171973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
17208bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17216acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1722d13ada5dSCédric Le Goater return;
17238bfffbccSCorey Minyard }
17248bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
1725a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1726a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1727a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1728a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1729a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
17308bfffbccSCorey Minyard }
17318bfffbccSCorey Minyard
rearm_sensor_evts(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17328bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
17338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1734a580d820SCédric Le Goater RspBuffer *rsp)
17358bfffbccSCorey Minyard {
17368bfffbccSCorey Minyard IPMISensor *sens;
17378bfffbccSCorey Minyard
173873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
17398bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1741d13ada5dSCédric Le Goater return;
17428bfffbccSCorey Minyard }
17438bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
17448bfffbccSCorey Minyard
17458bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) {
17468bfffbccSCorey Minyard /* Just clear everything */
17478bfffbccSCorey Minyard sens->states = 0;
17488bfffbccSCorey Minyard return;
17498bfffbccSCorey Minyard }
1750d13ada5dSCédric Le Goater }
17518bfffbccSCorey Minyard
get_sensor_evt_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17528bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
17538bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1754a580d820SCédric Le Goater RspBuffer *rsp)
17558bfffbccSCorey Minyard {
17568bfffbccSCorey Minyard IPMISensor *sens;
17578bfffbccSCorey Minyard
175873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
17598bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17606acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1761d13ada5dSCédric Le Goater return;
17628bfffbccSCorey Minyard }
17638bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
1764a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading);
1765a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1766a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff);
1767a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1768a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1769a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
17708bfffbccSCorey Minyard }
17718bfffbccSCorey Minyard
get_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17728bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
17738bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len,
1774a580d820SCédric Le Goater RspBuffer *rsp)
17758bfffbccSCorey Minyard {
17768bfffbccSCorey Minyard IPMISensor *sens;
17778bfffbccSCorey Minyard
177873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
17798bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17806acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1781d13ada5dSCédric Le Goater return;
17828bfffbccSCorey Minyard }
17838bfffbccSCorey Minyard sens = ibs->sensors + cmd[2];
1784a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading);
1785a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1786a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff);
17878bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1788a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17898bfffbccSCorey Minyard }
17908bfffbccSCorey Minyard }
17918bfffbccSCorey Minyard
set_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1792728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1793728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1794a580d820SCédric Le Goater RspBuffer *rsp)
1795728710e1SCédric Le Goater {
1796728710e1SCédric Le Goater IPMISensor *sens;
1797728710e1SCédric Le Goater
1798728710e1SCédric Le Goater
179973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
1800728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
18016acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1802728710e1SCédric Le Goater return;
1803728710e1SCédric Le Goater }
1804728710e1SCédric Le Goater sens = ibs->sensors + cmd[2];
1805728710e1SCédric Le Goater sens->sensor_type = cmd[3];
1806728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f;
1807728710e1SCédric Le Goater }
1808728710e1SCédric Le Goater
get_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1809728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1810728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1811a580d820SCédric Le Goater RspBuffer *rsp)
1812728710e1SCédric Le Goater {
1813728710e1SCédric Le Goater IPMISensor *sens;
1814728710e1SCédric Le Goater
1815728710e1SCédric Le Goater
181673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
1817728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
18186acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1819728710e1SCédric Le Goater return;
1820728710e1SCédric Le Goater }
1821728710e1SCédric Le Goater sens = ibs->sensors + cmd[2];
1822a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type);
1823a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code);
1824728710e1SCédric Le Goater }
1825728710e1SCédric Le Goater
1826e3f7320cSCédric Le Goater /*
1827e3f7320cSCédric Le Goater * bytes parameter
1828e3f7320cSCédric Le Goater * 1 sensor number
1829e3f7320cSCédric Le Goater * 2 operation (see below for bits meaning)
1830e3f7320cSCédric Le Goater * 3 sensor reading
1831e3f7320cSCédric Le Goater * 4:5 assertion states (optional)
1832e3f7320cSCédric Le Goater * 6:7 deassertion states (optional)
1833e3f7320cSCédric Le Goater * 8:10 event data 1,2,3 (optional)
1834e3f7320cSCédric Le Goater */
set_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1835e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs,
1836e3f7320cSCédric Le Goater uint8_t *cmd, unsigned int cmd_len,
1837e3f7320cSCédric Le Goater RspBuffer *rsp)
1838e3f7320cSCédric Le Goater {
1839e3f7320cSCédric Le Goater IPMISensor *sens;
1840e3f7320cSCédric Le Goater uint8_t evd1 = 0;
1841e3f7320cSCédric Le Goater uint8_t evd2 = 0;
1842e3f7320cSCédric Le Goater uint8_t evd3 = 0;
1843e3f7320cSCédric Le Goater uint8_t new_reading = 0;
1844e3f7320cSCédric Le Goater uint16_t new_assert_states = 0;
1845e3f7320cSCédric Le Goater uint16_t new_deassert_states = 0;
1846e3f7320cSCédric Le Goater bool change_reading = false;
1847e3f7320cSCédric Le Goater bool change_assert = false;
1848e3f7320cSCédric Le Goater bool change_deassert = false;
1849e3f7320cSCédric Le Goater enum {
1850e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_NONE,
1851e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_DATA,
1852e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_BMC,
1853e3f7320cSCédric Le Goater } do_gen_event = SENSOR_GEN_EVENT_NONE;
1854e3f7320cSCédric Le Goater
1855e3f7320cSCédric Le Goater if ((cmd[2] >= MAX_SENSORS) ||
1856e3f7320cSCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1857e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1858e3f7320cSCédric Le Goater return;
1859e3f7320cSCédric Le Goater }
1860e3f7320cSCédric Le Goater
1861e3f7320cSCédric Le Goater sens = ibs->sensors + cmd[2];
1862e3f7320cSCédric Le Goater
1863e3f7320cSCédric Le Goater /* [1:0] Sensor Reading operation */
1864e3f7320cSCédric Le Goater switch ((cmd[3]) & 0x3) {
1865e3f7320cSCédric Le Goater case 0: /* Do not change */
1866e3f7320cSCédric Le Goater break;
1867e3f7320cSCédric Le Goater case 1: /* write given value to sensor reading byte */
1868e3f7320cSCédric Le Goater new_reading = cmd[4];
1869e3f7320cSCédric Le Goater if (sens->reading != new_reading) {
1870e3f7320cSCédric Le Goater change_reading = true;
1871e3f7320cSCédric Le Goater }
1872e3f7320cSCédric Le Goater break;
1873e3f7320cSCédric Le Goater case 2:
1874e3f7320cSCédric Le Goater case 3:
1875e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1876e3f7320cSCédric Le Goater return;
1877e3f7320cSCédric Le Goater }
1878e3f7320cSCédric Le Goater
1879e3f7320cSCédric Le Goater /* [3:2] Deassertion bits operation */
1880e3f7320cSCédric Le Goater switch ((cmd[3] >> 2) & 0x3) {
1881e3f7320cSCédric Le Goater case 0: /* Do not change */
1882e3f7320cSCédric Le Goater break;
1883e3f7320cSCédric Le Goater case 1: /* write given value */
1884e3f7320cSCédric Le Goater if (cmd_len > 7) {
1885e3f7320cSCédric Le Goater new_deassert_states = cmd[7];
1886e3f7320cSCédric Le Goater change_deassert = true;
1887e3f7320cSCédric Le Goater }
1888e3f7320cSCédric Le Goater if (cmd_len > 8) {
1889e3f7320cSCédric Le Goater new_deassert_states |= (cmd[8] << 8);
1890e3f7320cSCédric Le Goater }
1891e3f7320cSCédric Le Goater break;
1892e3f7320cSCédric Le Goater
1893e3f7320cSCédric Le Goater case 2: /* mask on */
1894e3f7320cSCédric Le Goater if (cmd_len > 7) {
1895e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states | cmd[7]);
1896e3f7320cSCédric Le Goater change_deassert = true;
1897e3f7320cSCédric Le Goater }
1898e3f7320cSCédric Le Goater if (cmd_len > 8) {
1899e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1900e3f7320cSCédric Le Goater }
1901e3f7320cSCédric Le Goater break;
1902e3f7320cSCédric Le Goater
1903e3f7320cSCédric Le Goater case 3: /* mask off */
1904e3f7320cSCédric Le Goater if (cmd_len > 7) {
1905e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states & cmd[7]);
1906e3f7320cSCédric Le Goater change_deassert = true;
1907e3f7320cSCédric Le Goater }
1908e3f7320cSCédric Le Goater if (cmd_len > 8) {
1909e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1910e3f7320cSCédric Le Goater }
1911e3f7320cSCédric Le Goater break;
1912e3f7320cSCédric Le Goater }
1913e3f7320cSCédric Le Goater
1914e3f7320cSCédric Le Goater if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1915e3f7320cSCédric Le Goater change_deassert = false;
1916e3f7320cSCédric Le Goater }
1917e3f7320cSCédric Le Goater
1918e3f7320cSCédric Le Goater /* [5:4] Assertion bits operation */
1919e3f7320cSCédric Le Goater switch ((cmd[3] >> 4) & 0x3) {
1920e3f7320cSCédric Le Goater case 0: /* Do not change */
1921e3f7320cSCédric Le Goater break;
1922e3f7320cSCédric Le Goater case 1: /* write given value */
1923e3f7320cSCédric Le Goater if (cmd_len > 5) {
1924e3f7320cSCédric Le Goater new_assert_states = cmd[5];
1925e3f7320cSCédric Le Goater change_assert = true;
1926e3f7320cSCédric Le Goater }
1927e3f7320cSCédric Le Goater if (cmd_len > 6) {
1928e3f7320cSCédric Le Goater new_assert_states |= (cmd[6] << 8);
1929e3f7320cSCédric Le Goater }
1930e3f7320cSCédric Le Goater break;
1931e3f7320cSCédric Le Goater
1932e3f7320cSCédric Le Goater case 2: /* mask on */
1933e3f7320cSCédric Le Goater if (cmd_len > 5) {
1934e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states | cmd[5]);
1935e3f7320cSCédric Le Goater change_assert = true;
1936e3f7320cSCédric Le Goater }
1937e3f7320cSCédric Le Goater if (cmd_len > 6) {
1938e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1939e3f7320cSCédric Le Goater }
1940e3f7320cSCédric Le Goater break;
1941e3f7320cSCédric Le Goater
1942e3f7320cSCédric Le Goater case 3: /* mask off */
1943e3f7320cSCédric Le Goater if (cmd_len > 5) {
1944e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states & cmd[5]);
1945e3f7320cSCédric Le Goater change_assert = true;
1946e3f7320cSCédric Le Goater }
1947e3f7320cSCédric Le Goater if (cmd_len > 6) {
1948e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1949e3f7320cSCédric Le Goater }
1950e3f7320cSCédric Le Goater break;
1951e3f7320cSCédric Le Goater }
1952e3f7320cSCédric Le Goater
1953e3f7320cSCédric Le Goater if (change_assert && (new_assert_states == sens->assert_states)) {
1954e3f7320cSCédric Le Goater change_assert = false;
1955e3f7320cSCédric Le Goater }
1956e3f7320cSCédric Le Goater
1957e3f7320cSCédric Le Goater if (cmd_len > 9) {
1958e3f7320cSCédric Le Goater evd1 = cmd[9];
1959e3f7320cSCédric Le Goater }
1960e3f7320cSCédric Le Goater if (cmd_len > 10) {
1961e3f7320cSCédric Le Goater evd2 = cmd[10];
1962e3f7320cSCédric Le Goater }
1963e3f7320cSCédric Le Goater if (cmd_len > 11) {
1964e3f7320cSCédric Le Goater evd3 = cmd[11];
1965e3f7320cSCédric Le Goater }
1966e3f7320cSCédric Le Goater
1967e3f7320cSCédric Le Goater /* [7:6] Event Data Bytes operation */
1968e3f7320cSCédric Le Goater switch ((cmd[3] >> 6) & 0x3) {
1969e3f7320cSCédric Le Goater case 0: /*
1970e3f7320cSCédric Le Goater * Don’t use Event Data bytes from this command. BMC will
1971e3f7320cSCédric Le Goater * generate it's own Event Data bytes based on its sensor
1972e3f7320cSCédric Le Goater * implementation.
1973e3f7320cSCédric Le Goater */
1974e3f7320cSCédric Le Goater evd1 = evd2 = evd3 = 0x0;
1975e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_BMC;
1976e3f7320cSCédric Le Goater break;
1977e3f7320cSCédric Le Goater case 1: /*
1978e3f7320cSCédric Le Goater * Write given values to event data bytes including bits
1979e3f7320cSCédric Le Goater * [3:0] Event Data 1.
1980e3f7320cSCédric Le Goater */
1981e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA;
1982e3f7320cSCédric Le Goater break;
1983e3f7320cSCédric Le Goater case 2: /*
1984e3f7320cSCédric Le Goater * Write given values to event data bytes excluding bits
1985e3f7320cSCédric Le Goater * [3:0] Event Data 1.
1986e3f7320cSCédric Le Goater */
1987e3f7320cSCédric Le Goater evd1 &= 0xf0;
1988e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA;
1989e3f7320cSCédric Le Goater break;
1990e3f7320cSCédric Le Goater case 3:
1991e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1992e3f7320cSCédric Le Goater return;
1993e3f7320cSCédric Le Goater }
1994e3f7320cSCédric Le Goater
1995e3f7320cSCédric Le Goater /*
1996e3f7320cSCédric Le Goater * Event Data Bytes operation and parameter are inconsistent. The
1997e3f7320cSCédric Le Goater * Specs are not clear on that topic but generating an error seems
1998e3f7320cSCédric Le Goater * correct.
1999e3f7320cSCédric Le Goater */
2000e3f7320cSCédric Le Goater if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
2001e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
2002e3f7320cSCédric Le Goater return;
2003e3f7320cSCédric Le Goater }
2004e3f7320cSCédric Le Goater
2005e3f7320cSCédric Le Goater /* commit values */
2006e3f7320cSCédric Le Goater if (change_reading) {
2007e3f7320cSCédric Le Goater sens->reading = new_reading;
2008e3f7320cSCédric Le Goater }
2009e3f7320cSCédric Le Goater
2010e3f7320cSCédric Le Goater if (change_assert) {
2011e3f7320cSCédric Le Goater sens->assert_states = new_assert_states;
2012e3f7320cSCédric Le Goater }
2013e3f7320cSCédric Le Goater
2014e3f7320cSCédric Le Goater if (change_deassert) {
2015e3f7320cSCédric Le Goater sens->deassert_states = new_deassert_states;
2016e3f7320cSCédric Le Goater }
2017e3f7320cSCédric Le Goater
2018e3f7320cSCédric Le Goater /* TODO: handle threshold sensor */
2019e3f7320cSCédric Le Goater if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
2020e3f7320cSCédric Le Goater return;
2021e3f7320cSCédric Le Goater }
2022e3f7320cSCédric Le Goater
2023e3f7320cSCédric Le Goater switch (do_gen_event) {
2024e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_DATA: {
2025e3f7320cSCédric Le Goater unsigned int bit = evd1 & 0xf;
2026e3f7320cSCédric Le Goater uint16_t mask = (1 << bit);
2027e3f7320cSCédric Le Goater
2028e3f7320cSCédric Le Goater if (sens->assert_states & mask & sens->assert_enable) {
2029e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
2030e3f7320cSCédric Le Goater }
2031e3f7320cSCédric Le Goater
2032e3f7320cSCédric Le Goater if (sens->deassert_states & mask & sens->deassert_enable) {
2033e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
2034e3f7320cSCédric Le Goater }
2035e3f7320cSCédric Le Goater break;
2036e3f7320cSCédric Le Goater }
2037e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_BMC:
2038e3f7320cSCédric Le Goater /*
2039e3f7320cSCédric Le Goater * TODO: generate event and event data bytes depending on the
2040e3f7320cSCédric Le Goater * sensor
2041e3f7320cSCédric Le Goater */
2042e3f7320cSCédric Le Goater break;
2043e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_NONE:
2044e3f7320cSCédric Le Goater break;
2045e3f7320cSCédric Le Goater }
2046e3f7320cSCédric Le Goater }
2047728710e1SCédric Le Goater
204862a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
20494f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
20504f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
20514f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
20524f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
20538bfffbccSCorey Minyard };
20548bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
205562a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds),
20568bfffbccSCorey Minyard .cmd_handlers = chassis_cmds
20578bfffbccSCorey Minyard };
20588bfffbccSCorey Minyard
205962a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
20609380d2edSCorey Minyard [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
20614f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
20624f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
20634f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
20644f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
20654f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
20664f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
20674f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
2068e3f7320cSCédric Le Goater [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
20698bfffbccSCorey Minyard };
20708bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
207162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
20728bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds
20738bfffbccSCorey Minyard };
20748bfffbccSCorey Minyard
207562a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
20764f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
20774f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset },
20784f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset },
20794f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
20804f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
20814f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
20824f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
20834f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
20844f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
20854f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
20864f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg },
20874f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
20884f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
20894f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
20904f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
20914f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
20927f9e7af4SNicholas Piggin [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 },
20938bfffbccSCorey Minyard };
20948bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
209562a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds),
20968bfffbccSCorey Minyard .cmd_handlers = app_cmds
20978bfffbccSCorey Minyard };
20988bfffbccSCorey Minyard
209962a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
2100540c07d3SCédric Le Goater [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2101540c07d3SCédric Le Goater [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2102540c07d3SCédric Le Goater [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
21034f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
21044f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
21054f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
21064f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr },
21074f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
21084f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
21094f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
21104f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
21114f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
21124f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
21137f11cb65SCorey Minyard [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
21147f11cb65SCorey Minyard [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
21158bfffbccSCorey Minyard };
21168bfffbccSCorey Minyard
21178bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
211862a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds),
21198bfffbccSCorey Minyard .cmd_handlers = storage_cmds
21208bfffbccSCorey Minyard };
21218bfffbccSCorey Minyard
register_cmds(IPMIBmcSim * s)21228bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
21238bfffbccSCorey Minyard {
2124ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2125ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2126ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2127ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
21288bfffbccSCorey Minyard }
21298bfffbccSCorey Minyard
21305167560bSCédric Le Goater static uint8_t init_sdrs[] = {
21318bfffbccSCorey Minyard /* Watchdog device */
21328bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00,
21338bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
21348bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21358bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
21368bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g',
21378bfffbccSCorey Minyard };
21388bfffbccSCorey Minyard
ipmi_sdr_init(IPMIBmcSim * ibs)21394fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
21404fa9f08eSCédric Le Goater {
21414fa9f08eSCédric Le Goater unsigned int i;
21424fa9f08eSCédric Le Goater int len;
21435167560bSCédric Le Goater size_t sdrs_size;
21445167560bSCédric Le Goater uint8_t *sdrs;
214552fc01d9SCédric Le Goater
21465167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs);
21475167560bSCédric Le Goater sdrs = init_sdrs;
21488c6fd7f3SCédric Le Goater if (ibs->sdr_filename &&
21498c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
21508c6fd7f3SCédric Le Goater NULL)) {
21518c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename);
21528c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs);
21538c6fd7f3SCédric Le Goater sdrs = init_sdrs;
21548c6fd7f3SCédric Le Goater }
21555167560bSCédric Le Goater
21565167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) {
215752fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh;
215852fc01d9SCédric Le Goater
21595167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
21604fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i);
21618c6fd7f3SCédric Le Goater break;
21624fa9f08eSCédric Le Goater }
21635167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i];
21644fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh);
21655167560bSCédric Le Goater if (i + len > sdrs_size) {
21664fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i);
21678c6fd7f3SCédric Le Goater break;
21684fa9f08eSCédric Le Goater }
21694fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL);
21704fa9f08eSCédric Le Goater }
21718c6fd7f3SCédric Le Goater
21728c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) {
21738c6fd7f3SCédric Le Goater g_free(sdrs);
21748c6fd7f3SCédric Le Goater }
21754fa9f08eSCédric Le Goater }
21764fa9f08eSCédric Le Goater
2177bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
2178bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR,
2179bd66bcfcSCorey Minyard .version_id = 1,
2180bd66bcfcSCorey Minyard .minimum_version_id = 1,
218109c6ac6dSRichard Henderson .fields = (const VMStateField[]) {
2182bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2183bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2184bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2185bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2186bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2187bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
21889e744990SJinhua Cao VMSTATE_UINT8(watchdog_expired, IPMIBmcSim),
2189bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2190bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2191bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2192bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2193bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2194bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2195bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2196bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2197bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2198bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2199bd66bcfcSCorey Minyard IPMIBmcSim),
2200bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2201bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST()
2202bd66bcfcSCorey Minyard }
2203bd66bcfcSCorey Minyard };
2204bd66bcfcSCorey Minyard
ipmi_fru_init(IPMIFru * fru)2205540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
2206540c07d3SCédric Le Goater {
2207540c07d3SCédric Le Goater int fsize;
2208540c07d3SCédric Le Goater int size = 0;
2209540c07d3SCédric Le Goater
2210540c07d3SCédric Le Goater if (!fru->filename) {
2211540c07d3SCédric Le Goater goto out;
2212540c07d3SCédric Le Goater }
2213540c07d3SCédric Le Goater
2214540c07d3SCédric Le Goater fsize = get_image_size(fru->filename);
2215540c07d3SCédric Le Goater if (fsize > 0) {
2216540c07d3SCédric Le Goater size = QEMU_ALIGN_UP(fsize, fru->areasize);
2217540c07d3SCédric Le Goater fru->data = g_malloc0(size);
2218540c07d3SCédric Le Goater if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2219540c07d3SCédric Le Goater error_report("Could not load file '%s'", fru->filename);
2220540c07d3SCédric Le Goater g_free(fru->data);
2221540c07d3SCédric Le Goater fru->data = NULL;
2222540c07d3SCédric Le Goater }
2223540c07d3SCédric Le Goater }
2224540c07d3SCédric Le Goater
2225540c07d3SCédric Le Goater out:
2226540c07d3SCédric Le Goater if (!fru->data) {
2227540c07d3SCédric Le Goater /* give one default FRU */
2228540c07d3SCédric Le Goater size = fru->areasize;
2229540c07d3SCédric Le Goater fru->data = g_malloc0(size);
2230540c07d3SCédric Le Goater }
2231540c07d3SCédric Le Goater
2232540c07d3SCédric Le Goater fru->nentries = size / fru->areasize;
2233540c07d3SCédric Le Goater }
2234540c07d3SCédric Le Goater
ipmi_sim_realize(DeviceState * dev,Error ** errp)22350bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
22368bfffbccSCorey Minyard {
22370bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev);
22388bfffbccSCorey Minyard unsigned int i;
22398bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
22408bfffbccSCorey Minyard
22418bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs);
22428bfffbccSCorey Minyard
22438bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
22448bfffbccSCorey Minyard ibs->device_id = 0x20;
22458bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */
2246b7088392SCédric Le Goater ibs->restart_cause = 0;
22478bfffbccSCorey Minyard for (i = 0; i < 4; i++) {
22488bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff;
22498bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff;
22508bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff;
22518bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff;
22528bfffbccSCorey Minyard }
22538bfffbccSCorey Minyard
22544fa9f08eSCédric Le Goater ipmi_sdr_init(ibs);
22558bfffbccSCorey Minyard
2256540c07d3SCédric Le Goater ipmi_fru_init(&ibs->fru);
2257540c07d3SCédric Le Goater
225852ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0;
225952ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0;
226052ba4d50SCédric Le Goater
22618bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs);
22628bfffbccSCorey Minyard register_cmds(ibs);
22638bfffbccSCorey Minyard
22648bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
22658bfffbccSCorey Minyard }
22668bfffbccSCorey Minyard
22672acf1403SRichard Henderson static const Property ipmi_sim_properties[] = {
2268540c07d3SCédric Le Goater DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2269540c07d3SCédric Le Goater DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
22708c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
227120b23364SCorey Minyard DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
227220b23364SCorey Minyard DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
227320b23364SCorey Minyard DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
227420b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
227520b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
227620b23364SCorey Minyard DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
227720b23364SCorey Minyard DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
22787b0cd78bSCorey Minyard DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
22798c6fd7f3SCédric Le Goater };
22808c6fd7f3SCédric Le Goater
ipmi_sim_class_init(ObjectClass * oc,const void * data)2281*12d1a768SPhilippe Mathieu-Daudé static void ipmi_sim_class_init(ObjectClass *oc, const void *data)
22828bfffbccSCorey Minyard {
22830bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc);
22848bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
22858bfffbccSCorey Minyard
228666abfddbSCorey Minyard dc->hotpluggable = false;
22870bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize;
2288d11d904cSCorey Minyard dc->vmsd = &vmstate_ipmi_sim;
22894f67d30bSMarc-André Lureau device_class_set_props(dc, ipmi_sim_properties);
22908bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command;
22918bfffbccSCorey Minyard }
22928bfffbccSCorey Minyard
22938bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
22948bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR,
22958bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC,
22968bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim),
22978bfffbccSCorey Minyard .class_init = ipmi_sim_class_init,
22988bfffbccSCorey Minyard };
22998bfffbccSCorey Minyard
ipmi_sim_register_types(void)23008bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
23018bfffbccSCorey Minyard {
23028bfffbccSCorey Minyard type_register_static(&ipmi_sim_type);
23038bfffbccSCorey Minyard }
23048bfffbccSCorey Minyard
23058bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2306