18bfffbccSCorey Minyard /* 28bfffbccSCorey Minyard * IPMI BMC emulation 38bfffbccSCorey Minyard * 48bfffbccSCorey Minyard * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC 58bfffbccSCorey Minyard * 68bfffbccSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 78bfffbccSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 88bfffbccSCorey Minyard * in the Software without restriction, including without limitation the rights 98bfffbccSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108bfffbccSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 118bfffbccSCorey Minyard * furnished to do so, subject to the following conditions: 128bfffbccSCorey Minyard * 138bfffbccSCorey Minyard * The above copyright notice and this permission notice shall be included in 148bfffbccSCorey Minyard * all copies or substantial portions of the Software. 158bfffbccSCorey Minyard * 168bfffbccSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178bfffbccSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188bfffbccSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198bfffbccSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208bfffbccSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218bfffbccSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228bfffbccSCorey Minyard * THE SOFTWARE. 238bfffbccSCorey Minyard */ 248bfffbccSCorey Minyard 250430891cSPeter Maydell #include "qemu/osdep.h" 2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h" 278bfffbccSCorey Minyard #include "qemu/timer.h" 288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 298bfffbccSCorey Minyard #include "qemu/error-report.h" 308c6fd7f3SCédric Le Goater #include "hw/loader.h" 318bfffbccSCorey Minyard 328bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 338bfffbccSCorey Minyard 348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 358bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 368bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 37b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 388bfffbccSCorey Minyard 398bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 408bfffbccSCorey Minyard 418bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 438bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 458bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 46728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e 47728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f 488bfffbccSCorey Minyard 498bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 508bfffbccSCorey Minyard 518bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 528bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 538bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 5452ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06 5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07 5652ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID 0x08 578bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 588bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 598bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 608bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 618bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 628bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 648bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 658bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 668bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 678bfffbccSCorey Minyard 688bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 698bfffbccSCorey Minyard 708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 718bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 728bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 748bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 758bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 768bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 778bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 798bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 808bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 818bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 828bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 83540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO 0x10 84540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA 0x11 85540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA 0x12 868bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 878bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 888bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 898bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 908bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 918bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 928bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 938bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 948bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 958bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 968bfffbccSCorey Minyard 978bfffbccSCorey Minyard 988bfffbccSCorey Minyard /* Same as a timespec struct. */ 998bfffbccSCorey Minyard struct ipmi_time { 1008bfffbccSCorey Minyard long tv_sec; 1018bfffbccSCorey Minyard long tv_nsec; 1028bfffbccSCorey Minyard }; 1038bfffbccSCorey Minyard 1048bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 1058bfffbccSCorey Minyard 1068bfffbccSCorey Minyard typedef struct IPMISel { 1078bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 1088bfffbccSCorey Minyard unsigned int next_free; 1098bfffbccSCorey Minyard long time_offset; 1108bfffbccSCorey Minyard uint16_t reservation; 1118bfffbccSCorey Minyard uint8_t last_addition[4]; 1128bfffbccSCorey Minyard uint8_t last_clear[4]; 1138bfffbccSCorey Minyard uint8_t overflow; 1148bfffbccSCorey Minyard } IPMISel; 1158bfffbccSCorey Minyard 1168bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1178bfffbccSCorey Minyard 1188bfffbccSCorey Minyard typedef struct IPMISdr { 1198bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1208bfffbccSCorey Minyard unsigned int next_free; 1218bfffbccSCorey Minyard uint16_t next_rec_id; 1228bfffbccSCorey Minyard uint16_t reservation; 1238bfffbccSCorey Minyard uint8_t last_addition[4]; 1248bfffbccSCorey Minyard uint8_t last_clear[4]; 1258bfffbccSCorey Minyard uint8_t overflow; 1268bfffbccSCorey Minyard } IPMISdr; 1278bfffbccSCorey Minyard 128540c07d3SCédric Le Goater typedef struct IPMIFru { 129540c07d3SCédric Le Goater char *filename; 130540c07d3SCédric Le Goater unsigned int nentries; 131540c07d3SCédric Le Goater uint16_t areasize; 132540c07d3SCédric Le Goater uint8_t *data; 133540c07d3SCédric Le Goater } IPMIFru; 134540c07d3SCédric Le Goater 1358bfffbccSCorey Minyard typedef struct IPMISensor { 1368bfffbccSCorey Minyard uint8_t status; 1378bfffbccSCorey Minyard uint8_t reading; 1388bfffbccSCorey Minyard uint16_t states_suppt; 1398bfffbccSCorey Minyard uint16_t assert_suppt; 1408bfffbccSCorey Minyard uint16_t deassert_suppt; 1418bfffbccSCorey Minyard uint16_t states; 1428bfffbccSCorey Minyard uint16_t assert_states; 1438bfffbccSCorey Minyard uint16_t deassert_states; 1448bfffbccSCorey Minyard uint16_t assert_enable; 1458bfffbccSCorey Minyard uint16_t deassert_enable; 1468bfffbccSCorey Minyard uint8_t sensor_type; 1478bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1488bfffbccSCorey Minyard } IPMISensor; 1498bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1508bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1518bfffbccSCorey Minyard !!(v)) 1528bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1538bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1548bfffbccSCorey Minyard ((!!(v)) << 6)) 1558bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1568bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1578bfffbccSCorey Minyard ((!!(v)) << 7)) 1588bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1598bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1608bfffbccSCorey Minyard (v & 0xc0)) 1618bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1628bfffbccSCorey Minyard 1638bfffbccSCorey Minyard #define MAX_SENSORS 20 1648bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1658bfffbccSCorey Minyard 1668bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 167a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer; 1688bfffbccSCorey Minyard 1698bfffbccSCorey Minyard #define MAX_NETFNS 64 1704f298a4bSCédric Le Goater 1714f298a4bSCédric Le Goater typedef struct IPMICmdHandler { 1724f298a4bSCédric Le Goater void (*cmd_handler)(IPMIBmcSim *s, 1738bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 174a580d820SCédric Le Goater RspBuffer *rsp); 1754f298a4bSCédric Le Goater unsigned int cmd_len_min; 1764f298a4bSCédric Le Goater } IPMICmdHandler; 1774f298a4bSCédric Le Goater 1788bfffbccSCorey Minyard typedef struct IPMINetfn { 1798bfffbccSCorey Minyard unsigned int cmd_nums; 1808bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1818bfffbccSCorey Minyard } IPMINetfn; 1828bfffbccSCorey Minyard 1838bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1848bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1858bfffbccSCorey Minyard uint8_t len; 1868bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1878bfffbccSCorey Minyard } IPMIRcvBufEntry; 1888bfffbccSCorey Minyard 1898bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1908bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1918bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1928bfffbccSCorey Minyard struct IPMIBmcSim { 1938bfffbccSCorey Minyard IPMIBmc parent; 1948bfffbccSCorey Minyard 1958bfffbccSCorey Minyard QEMUTimer *timer; 1968bfffbccSCorey Minyard 1978bfffbccSCorey Minyard uint8_t bmc_global_enables; 1988bfffbccSCorey Minyard uint8_t msg_flags; 1998bfffbccSCorey Minyard 2008bfffbccSCorey Minyard bool watchdog_initialized; 2018bfffbccSCorey Minyard uint8_t watchdog_use; 2028bfffbccSCorey Minyard uint8_t watchdog_action; 2038bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 2048bfffbccSCorey Minyard bool watchdog_expired; 2058bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 2068bfffbccSCorey Minyard 2078bfffbccSCorey Minyard bool watchdog_running; 2088bfffbccSCorey Minyard bool watchdog_preaction_ran; 2098bfffbccSCorey Minyard int64_t watchdog_expiry; 2108bfffbccSCorey Minyard 2118bfffbccSCorey Minyard uint8_t device_id; 2128bfffbccSCorey Minyard uint8_t ipmi_version; 2138bfffbccSCorey Minyard uint8_t device_rev; 2148bfffbccSCorey Minyard uint8_t fwrev1; 2158bfffbccSCorey Minyard uint8_t fwrev2; 2168bfffbccSCorey Minyard uint8_t mfg_id[3]; 2178bfffbccSCorey Minyard uint8_t product_id[2]; 2188bfffbccSCorey Minyard 219b7088392SCédric Le Goater uint8_t restart_cause; 220b7088392SCédric Le Goater 22152ba4d50SCédric Le Goater uint8_t acpi_power_state[2]; 22252ba4d50SCédric Le Goater uint8_t uuid[16]; 22352ba4d50SCédric Le Goater 2248bfffbccSCorey Minyard IPMISel sel; 2258bfffbccSCorey Minyard IPMISdr sdr; 226540c07d3SCédric Le Goater IPMIFru fru; 2278bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 2288c6fd7f3SCédric Le Goater char *sdr_filename; 2298bfffbccSCorey Minyard 2308bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2318bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2328bfffbccSCorey Minyard 2338bfffbccSCorey Minyard /* We allow one event in the buffer */ 2348bfffbccSCorey Minyard uint8_t evtbuf[16]; 2358bfffbccSCorey Minyard 2368bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2378bfffbccSCorey Minyard }; 2388bfffbccSCorey Minyard 2398bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2408bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2428bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2438bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2448bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2458bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2468bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2478bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2488bfffbccSCorey Minyard 2498bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2508bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2518bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2528bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2538bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2548bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2558bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2568bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2578bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2588bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2598bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2608bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2618bfffbccSCorey Minyard 2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2678bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2688bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2698bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2708bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2718bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2728bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2738bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2748bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2758bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2768bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2778bfffbccSCorey Minyard 278a580d820SCédric Le Goater struct RspBuffer { 279a580d820SCédric Le Goater uint8_t buffer[MAX_IPMI_MSG_SIZE]; 280a580d820SCédric Le Goater unsigned int len; 281a580d820SCédric Le Goater }; 282a580d820SCédric Le Goater 283a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { } 2848bfffbccSCorey Minyard 2856acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte) 2866acb971aSCédric Le Goater { 2876acb971aSCédric Le Goater rsp->buffer[2] = byte; 2886acb971aSCédric Le Goater } 2896acb971aSCédric Le Goater 2908bfffbccSCorey Minyard /* Add a byte to the response. */ 291a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte) 292a580d820SCédric Le Goater { 293a580d820SCédric Le Goater if (rsp->len >= sizeof(rsp->buffer)) { 2946acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 295a580d820SCédric Le Goater return; 296a580d820SCédric Le Goater } 297a580d820SCédric Le Goater rsp->buffer[rsp->len++] = byte; 298a580d820SCédric Le Goater } 299a580d820SCédric Le Goater 300a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes, 301a580d820SCédric Le Goater unsigned int n) 302a580d820SCédric Le Goater { 303a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) { 3046acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 305a580d820SCédric Le Goater return; 306a580d820SCédric Le Goater } 307a580d820SCédric Le Goater 308a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n); 309a580d820SCédric Le Goater rsp->len += n; 310a580d820SCédric Le Goater } 3118bfffbccSCorey Minyard 3128bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 3138bfffbccSCorey Minyard 3148bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 3158bfffbccSCorey Minyard { 3168bfffbccSCorey Minyard int64_t stime; 3178bfffbccSCorey Minyard 3188bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 3198bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 3208bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 3218bfffbccSCorey Minyard } 3228bfffbccSCorey Minyard 3238bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 3248bfffbccSCorey Minyard { 3258bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3268bfffbccSCorey Minyard } 3278bfffbccSCorey Minyard 3288bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 3298bfffbccSCorey Minyard { 3308bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3318bfffbccSCorey Minyard 3328bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3338bfffbccSCorey Minyard } 3348bfffbccSCorey Minyard 3358bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3368bfffbccSCorey Minyard { 3378bfffbccSCorey Minyard unsigned int val; 3388bfffbccSCorey Minyard struct ipmi_time now; 3398bfffbccSCorey Minyard 3408bfffbccSCorey Minyard ipmi_gettime(&now); 3418bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3428bfffbccSCorey Minyard ts[0] = val & 0xff; 3438bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3448bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3458bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3468bfffbccSCorey Minyard } 3478bfffbccSCorey Minyard 3488bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3498bfffbccSCorey Minyard { 3508bfffbccSCorey Minyard sdr->reservation++; 3518bfffbccSCorey Minyard if (sdr->reservation == 0) { 3528bfffbccSCorey Minyard sdr->reservation = 1; 3538bfffbccSCorey Minyard } 3548bfffbccSCorey Minyard } 3558bfffbccSCorey Minyard 356a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 357a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3588bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3598bfffbccSCorey Minyard { 360a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 361a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 362a2295f0aSCédric Le Goater 363a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3648bfffbccSCorey Minyard return 1; 3658bfffbccSCorey Minyard } 3668bfffbccSCorey Minyard 367a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3688bfffbccSCorey Minyard return 1; 3698bfffbccSCorey Minyard } 3708bfffbccSCorey Minyard 3718bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3728bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3738bfffbccSCorey Minyard return 1; 3748bfffbccSCorey Minyard } 3758bfffbccSCorey Minyard 376a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 377a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 378a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 379a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3808bfffbccSCorey Minyard 3818bfffbccSCorey Minyard if (recid) { 3828bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3838bfffbccSCorey Minyard } 3848bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3858bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3868bfffbccSCorey Minyard ibs->sdr.next_free += len; 3878bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3888bfffbccSCorey Minyard return 0; 3898bfffbccSCorey Minyard } 3908bfffbccSCorey Minyard 3918bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3928bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3938bfffbccSCorey Minyard { 3948bfffbccSCorey Minyard unsigned int pos = *retpos; 3958bfffbccSCorey Minyard 3968bfffbccSCorey Minyard while (pos < sdr->next_free) { 397a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 398a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 399a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 400a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 4018bfffbccSCorey Minyard 4028bfffbccSCorey Minyard if (trec == recid) { 4038bfffbccSCorey Minyard if (nextrec) { 4048bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 4058bfffbccSCorey Minyard *nextrec = 0xffff; 4068bfffbccSCorey Minyard } else { 4078bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 4088bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 4098bfffbccSCorey Minyard } 4108bfffbccSCorey Minyard } 4118bfffbccSCorey Minyard *retpos = pos; 4128bfffbccSCorey Minyard return 0; 4138bfffbccSCorey Minyard } 4148bfffbccSCorey Minyard pos = nextpos; 4158bfffbccSCorey Minyard } 4168bfffbccSCorey Minyard return 1; 4178bfffbccSCorey Minyard } 4188bfffbccSCorey Minyard 4197fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid, 4207fabcdb9SCédric Le Goater const struct ipmi_sdr_compact **sdr, uint16_t *nextrec) 4217fabcdb9SCédric Le Goater 4227fabcdb9SCédric Le Goater { 4237fabcdb9SCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 4247fabcdb9SCédric Le Goater unsigned int pos; 4257fabcdb9SCédric Le Goater 4267fabcdb9SCédric Le Goater pos = 0; 4277fabcdb9SCédric Le Goater if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) { 4287fabcdb9SCédric Le Goater return -1; 4297fabcdb9SCédric Le Goater } 4307fabcdb9SCédric Le Goater 4317fabcdb9SCédric Le Goater *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos]; 4327fabcdb9SCédric Le Goater return 0; 4337fabcdb9SCédric Le Goater } 4347fabcdb9SCédric Le Goater 4358bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 4368bfffbccSCorey Minyard { 4378bfffbccSCorey Minyard sel->reservation++; 4388bfffbccSCorey Minyard if (sel->reservation == 0) { 4398bfffbccSCorey Minyard sel->reservation = 1; 4408bfffbccSCorey Minyard } 4418bfffbccSCorey Minyard } 4428bfffbccSCorey Minyard 4438bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4448bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4458bfffbccSCorey Minyard { 4468bfffbccSCorey Minyard event[0] = 0xff; 4478bfffbccSCorey Minyard event[1] = 0xff; 4488bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 4498bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4508bfffbccSCorey Minyard ibs->sel.overflow = 1; 4518bfffbccSCorey Minyard return 1; 4528bfffbccSCorey Minyard } 4538bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4548bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4558bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 4568bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4578bfffbccSCorey Minyard ibs->sel.next_free++; 4588bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4598bfffbccSCorey Minyard return 0; 4608bfffbccSCorey Minyard } 4618bfffbccSCorey Minyard 4628bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4638bfffbccSCorey Minyard { 4648bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4658bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4668bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4678bfffbccSCorey Minyard } 4688bfffbccSCorey Minyard 4698bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4708bfffbccSCorey Minyard { 4718bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4728bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4738bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4748bfffbccSCorey Minyard } 4758bfffbccSCorey Minyard 476cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log) 477cd60d85eSCédric Le Goater { 478cd60d85eSCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 479cd60d85eSCédric Le Goater IPMIInterface *s = ibs->parent.intf; 480cd60d85eSCédric Le Goater IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 481cd60d85eSCédric Le Goater 482cd60d85eSCédric Le Goater if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 483cd60d85eSCédric Le Goater return; 484cd60d85eSCédric Le Goater } 485cd60d85eSCédric Le Goater 486cd60d85eSCédric Le Goater if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 487cd60d85eSCédric Le Goater sel_add_event(ibs, evt); 488cd60d85eSCédric Le Goater } 489cd60d85eSCédric Le Goater 490cd60d85eSCédric Le Goater if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 491cd60d85eSCédric Le Goater goto out; 492cd60d85eSCédric Le Goater } 493cd60d85eSCédric Le Goater 494cd60d85eSCédric Le Goater memcpy(ibs->evtbuf, evt, 16); 495cd60d85eSCédric Le Goater ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 496cd60d85eSCédric Le Goater k->set_atn(s, 1, attn_irq_enabled(ibs)); 497cd60d85eSCédric Le Goater out: 498cd60d85eSCédric Le Goater return; 499cd60d85eSCédric Le Goater } 5008bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 5018bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 5028bfffbccSCorey Minyard { 5038bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 5048bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 5058bfffbccSCorey Minyard uint8_t evt[16]; 5068bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 5078bfffbccSCorey Minyard 5088bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 5098bfffbccSCorey Minyard return; 5108bfffbccSCorey Minyard } 5118bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 5128bfffbccSCorey Minyard return; 5138bfffbccSCorey Minyard } 5148bfffbccSCorey Minyard 5158bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 5168bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 5178bfffbccSCorey Minyard evt[8] = 0; 5188bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 5198bfffbccSCorey Minyard evt[10] = sens->sensor_type; 5208bfffbccSCorey Minyard evt[11] = sens_num; 5218bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 5228bfffbccSCorey Minyard evt[13] = evd1; 5238bfffbccSCorey Minyard evt[14] = evd2; 5248bfffbccSCorey Minyard evt[15] = evd3; 5258bfffbccSCorey Minyard 5268bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 5278bfffbccSCorey Minyard sel_add_event(ibs, evt); 5288bfffbccSCorey Minyard } 5298bfffbccSCorey Minyard 5308bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 531d13ada5dSCédric Le Goater return; 5328bfffbccSCorey Minyard } 5338bfffbccSCorey Minyard 5348bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 5358bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 5368bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 5378bfffbccSCorey Minyard } 5388bfffbccSCorey Minyard 5398bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 5408bfffbccSCorey Minyard unsigned int bit, unsigned int val, 5418bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 5428bfffbccSCorey Minyard { 5438bfffbccSCorey Minyard IPMISensor *sens; 5448bfffbccSCorey Minyard uint16_t mask; 5458bfffbccSCorey Minyard 5468bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 5478bfffbccSCorey Minyard return; 5488bfffbccSCorey Minyard } 5498bfffbccSCorey Minyard if (bit >= 16) { 5508bfffbccSCorey Minyard return; 5518bfffbccSCorey Minyard } 5528bfffbccSCorey Minyard 5538bfffbccSCorey Minyard mask = (1 << bit); 5548bfffbccSCorey Minyard sens = ibs->sensors + sensor; 5558bfffbccSCorey Minyard if (val) { 5568bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5578bfffbccSCorey Minyard if (sens->assert_states & mask) { 5588bfffbccSCorey Minyard return; /* Already asserted */ 5598bfffbccSCorey Minyard } 5608bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 5618bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 5628bfffbccSCorey Minyard /* Send an event on assert */ 5638bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5648bfffbccSCorey Minyard } 5658bfffbccSCorey Minyard } else { 5668bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5678bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5688bfffbccSCorey Minyard return; /* Already deasserted */ 5698bfffbccSCorey Minyard } 5708bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5718bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5728bfffbccSCorey Minyard /* Send an event on deassert */ 5738bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5748bfffbccSCorey Minyard } 5758bfffbccSCorey Minyard } 5768bfffbccSCorey Minyard } 5778bfffbccSCorey Minyard 5788bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5798bfffbccSCorey Minyard { 5808bfffbccSCorey Minyard unsigned int i, pos; 5818bfffbccSCorey Minyard IPMISensor *sens; 5828bfffbccSCorey Minyard 5838bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5848bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5858bfffbccSCorey Minyard } 5868bfffbccSCorey Minyard 5878bfffbccSCorey Minyard pos = 0; 5888bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 589a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 590a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 591a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5928bfffbccSCorey Minyard 5938bfffbccSCorey Minyard if (len < 20) { 5948bfffbccSCorey Minyard continue; 5958bfffbccSCorey Minyard } 596a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5978bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5988bfffbccSCorey Minyard } 5998bfffbccSCorey Minyard 60073d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 6018bfffbccSCorey Minyard continue; 6028bfffbccSCorey Minyard } 603a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 6048bfffbccSCorey Minyard 6058bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 606a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 607a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 608a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 609a2295f0aSCédric Le Goater sens->deassert_suppt = 610a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 611a2295f0aSCédric Le Goater sens->states_suppt = 612a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 613a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 614a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 6158bfffbccSCorey Minyard 6168bfffbccSCorey Minyard /* Enable all the events that are supported. */ 6178bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 6188bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 6198bfffbccSCorey Minyard } 6208bfffbccSCorey Minyard } 6218bfffbccSCorey Minyard 6228bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 6238bfffbccSCorey Minyard const IPMINetfn *netfnd) 6248bfffbccSCorey Minyard { 62593a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 6268bfffbccSCorey Minyard return -1; 6278bfffbccSCorey Minyard } 6288bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 6298bfffbccSCorey Minyard return 0; 6308bfffbccSCorey Minyard } 6318bfffbccSCorey Minyard 6324f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 6334f298a4bSCédric Le Goater unsigned int netfn, 6344f298a4bSCédric Le Goater unsigned int cmd) 6354f298a4bSCédric Le Goater { 6364f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 6374f298a4bSCédric Le Goater 6384f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 6394f298a4bSCédric Le Goater return NULL; 6404f298a4bSCédric Le Goater } 6414f298a4bSCédric Le Goater 6424f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 6434f298a4bSCédric Le Goater return NULL; 6444f298a4bSCédric Le Goater } 6454f298a4bSCédric Le Goater 6464f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 6474f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 6484f298a4bSCédric Le Goater return NULL; 6494f298a4bSCédric Le Goater } 6504f298a4bSCédric Le Goater 6514f298a4bSCédric Le Goater return hdl; 6524f298a4bSCédric Le Goater } 6534f298a4bSCédric Le Goater 6548bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 6558bfffbccSCorey Minyard { 6568bfffbccSCorey Minyard int64_t next; 6578bfffbccSCorey Minyard if (ibs->watchdog_running) { 6588bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6598bfffbccSCorey Minyard } else { 6608bfffbccSCorey Minyard /* Wait a minute */ 6618bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6628bfffbccSCorey Minyard } 6638bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6648bfffbccSCorey Minyard } 6658bfffbccSCorey Minyard 6668bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6678bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6688bfffbccSCorey Minyard unsigned int max_cmd_len, 6698bfffbccSCorey Minyard uint8_t msg_id) 6708bfffbccSCorey Minyard { 6718bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6728bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6738bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6744f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 675a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6768bfffbccSCorey Minyard 6778bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6788bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 679a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 6806acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 681d13ada5dSCédric Le Goater goto out; 682d13ada5dSCédric Le Goater } 683d13ada5dSCédric Le Goater 684a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 685a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 686a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6878bfffbccSCorey Minyard 6888bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6898bfffbccSCorey Minyard if (cmd_len < 2) { 6906acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6918bfffbccSCorey Minyard goto out; 6928bfffbccSCorey Minyard } 6938bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6946acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 6958bfffbccSCorey Minyard goto out; 6968bfffbccSCorey Minyard } 6978bfffbccSCorey Minyard 6988bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6998bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 7006acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN); 7018bfffbccSCorey Minyard goto out; 7028bfffbccSCorey Minyard } 7038bfffbccSCorey Minyard 7044f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 7054f298a4bSCédric Le Goater if (!hdl) { 7066acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD); 7078bfffbccSCorey Minyard goto out; 7088bfffbccSCorey Minyard } 7098bfffbccSCorey Minyard 7104f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 7116acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 7124f298a4bSCédric Le Goater goto out; 7134f298a4bSCédric Le Goater } 7144f298a4bSCédric Le Goater 715a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 7168bfffbccSCorey Minyard 7178bfffbccSCorey Minyard out: 718a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 7198bfffbccSCorey Minyard 7208bfffbccSCorey Minyard next_timeout(ibs); 7218bfffbccSCorey Minyard } 7228bfffbccSCorey Minyard 7238bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 7248bfffbccSCorey Minyard { 7258bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7268bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7278bfffbccSCorey Minyard 7288bfffbccSCorey Minyard if (!ibs->watchdog_running) { 7298bfffbccSCorey Minyard goto out; 7308bfffbccSCorey Minyard } 7318bfffbccSCorey Minyard 7328bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 7338bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 7348bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 7358bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7368bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 7378bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 7388bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 7398bfffbccSCorey Minyard break; 7408bfffbccSCorey Minyard 7418bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 7428bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7438bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 7448bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 7458bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 7468bfffbccSCorey Minyard break; 7478bfffbccSCorey Minyard 7488bfffbccSCorey Minyard default: 7498bfffbccSCorey Minyard goto do_full_expiry; 7508bfffbccSCorey Minyard } 7518bfffbccSCorey Minyard 7528bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 7538bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 7548bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 7558bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 7568bfffbccSCorey Minyard goto out; 7578bfffbccSCorey Minyard } 7588bfffbccSCorey Minyard 7598bfffbccSCorey Minyard do_full_expiry: 7608bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7618bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7628bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7638bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7648bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 7658bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 7668bfffbccSCorey Minyard break; 7678bfffbccSCorey Minyard 7688bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7698bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 7708bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 7718bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7728bfffbccSCorey Minyard break; 7738bfffbccSCorey Minyard 7748bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7758bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7768bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 7778bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7788bfffbccSCorey Minyard break; 7798bfffbccSCorey Minyard 7808bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7818bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7828bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7838bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7848bfffbccSCorey Minyard break; 7858bfffbccSCorey Minyard } 7868bfffbccSCorey Minyard 7878bfffbccSCorey Minyard out: 7888bfffbccSCorey Minyard next_timeout(ibs); 7898bfffbccSCorey Minyard } 7908bfffbccSCorey Minyard 7918bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7928bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 793a580d820SCédric Le Goater RspBuffer *rsp) 7948bfffbccSCorey Minyard { 795a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 796a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 797a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 798a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 799a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 8008bfffbccSCorey Minyard } 8018bfffbccSCorey Minyard 8028bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 8038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 804a580d820SCédric Le Goater RspBuffer *rsp) 8058bfffbccSCorey Minyard { 806a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 807a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 808a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 809a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 8108bfffbccSCorey Minyard } 8118bfffbccSCorey Minyard 8128bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 8138bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 814a580d820SCédric Le Goater RspBuffer *rsp) 8158bfffbccSCorey Minyard { 8168bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8178bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8188bfffbccSCorey Minyard 8198bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 8208bfffbccSCorey Minyard case 0: /* power down */ 8216acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0)); 8228bfffbccSCorey Minyard break; 8238bfffbccSCorey Minyard case 1: /* power up */ 8246acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0)); 8258bfffbccSCorey Minyard break; 8268bfffbccSCorey Minyard case 2: /* power cycle */ 8276acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0)); 8288bfffbccSCorey Minyard break; 8298bfffbccSCorey Minyard case 3: /* hard reset */ 8306acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0)); 8318bfffbccSCorey Minyard break; 8328bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 8336acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0)); 8348bfffbccSCorey Minyard break; 8358bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 8366acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, 8376acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0)); 8388bfffbccSCorey Minyard break; 8398bfffbccSCorey Minyard default: 8406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 8418bfffbccSCorey Minyard return; 8428bfffbccSCorey Minyard } 843d13ada5dSCédric Le Goater } 8448bfffbccSCorey Minyard 845b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 846b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 847a580d820SCédric Le Goater RspBuffer *rsp) 848a580d820SCédric Le Goater 849b7088392SCédric Le Goater { 850a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 851a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 852b7088392SCédric Le Goater } 853b7088392SCédric Le Goater 8548bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 8558bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 856a580d820SCédric Le Goater RspBuffer *rsp) 8578bfffbccSCorey Minyard { 858a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 859a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 860a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 861a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 862a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 863a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 864a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[0]); 865a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[1]); 866a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[2]); 867a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[0]); 868a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[1]); 8698bfffbccSCorey Minyard } 8708bfffbccSCorey Minyard 8718bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8728bfffbccSCorey Minyard { 8738bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8748bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8758bfffbccSCorey Minyard bool irqs_on; 8768bfffbccSCorey Minyard 8778bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8788bfffbccSCorey Minyard 8798bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8808bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8818bfffbccSCorey Minyard 8828bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8838bfffbccSCorey Minyard } 8848bfffbccSCorey Minyard 8858bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8868bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 887a580d820SCédric Le Goater RspBuffer *rsp) 8888bfffbccSCorey Minyard { 8898bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8908bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8918bfffbccSCorey Minyard 8928bfffbccSCorey Minyard /* Disable all interrupts */ 8938bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8948bfffbccSCorey Minyard 8958bfffbccSCorey Minyard if (k->reset) { 8968bfffbccSCorey Minyard k->reset(s, true); 8978bfffbccSCorey Minyard } 8988bfffbccSCorey Minyard } 8998bfffbccSCorey Minyard 9008bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 9018bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 902a580d820SCédric Le Goater RspBuffer *rsp) 9038bfffbccSCorey Minyard { 9048bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9058bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9068bfffbccSCorey Minyard 9078bfffbccSCorey Minyard if (k->reset) { 9088bfffbccSCorey Minyard k->reset(s, false); 9098bfffbccSCorey Minyard } 9108bfffbccSCorey Minyard } 91152ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 91252ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 913a580d820SCédric Le Goater RspBuffer *rsp) 91452ba4d50SCédric Le Goater { 91552ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 91652ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 91752ba4d50SCédric Le Goater } 91852ba4d50SCédric Le Goater 91952ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 92052ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 921a580d820SCédric Le Goater RspBuffer *rsp) 92252ba4d50SCédric Le Goater { 923a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 924a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 92552ba4d50SCédric Le Goater } 92652ba4d50SCédric Le Goater 92752ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 92852ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 929a580d820SCédric Le Goater RspBuffer *rsp) 93052ba4d50SCédric Le Goater { 93152ba4d50SCédric Le Goater unsigned int i; 93252ba4d50SCédric Le Goater 93352ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 934a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->uuid[i]); 93552ba4d50SCédric Le Goater } 93652ba4d50SCédric Le Goater } 9378bfffbccSCorey Minyard 9388bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 9398bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 940a580d820SCédric Le Goater RspBuffer *rsp) 9418bfffbccSCorey Minyard { 9428bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 9438bfffbccSCorey Minyard } 9448bfffbccSCorey Minyard 9458bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 9468bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 947a580d820SCédric Le Goater RspBuffer *rsp) 9488bfffbccSCorey Minyard { 949a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 9508bfffbccSCorey Minyard } 9518bfffbccSCorey Minyard 9528bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 9538bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 954a580d820SCédric Le Goater RspBuffer *rsp) 9558bfffbccSCorey Minyard { 9568bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9578bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9588bfffbccSCorey Minyard 9598bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9608bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9618bfffbccSCorey Minyard } 9628bfffbccSCorey Minyard 9638bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9648bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 965a580d820SCédric Le Goater RspBuffer *rsp) 9668bfffbccSCorey Minyard { 967a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9688bfffbccSCorey Minyard } 9698bfffbccSCorey Minyard 9708bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9718bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 972a580d820SCédric Le Goater RspBuffer *rsp) 9738bfffbccSCorey Minyard { 9748bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9758bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9768bfffbccSCorey Minyard unsigned int i; 9778bfffbccSCorey Minyard 9788bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 9796acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 980d13ada5dSCédric Le Goater return; 9818bfffbccSCorey Minyard } 9828bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 983a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 9848bfffbccSCorey Minyard } 9858bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9868bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9878bfffbccSCorey Minyard } 9888bfffbccSCorey Minyard 9898bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9908bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 991a580d820SCédric Le Goater RspBuffer *rsp) 9928bfffbccSCorey Minyard { 9938bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9948bfffbccSCorey Minyard 9958bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ 9978bfffbccSCorey Minyard goto out; 9988bfffbccSCorey Minyard } 999a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 10008bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 1001a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 10028bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 10038bfffbccSCorey Minyard g_free(msg); 10048bfffbccSCorey Minyard 10058bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 10068bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10078bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10088bfffbccSCorey Minyard 10098bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10108bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 10118bfffbccSCorey Minyard } 10128bfffbccSCorey Minyard 10138bfffbccSCorey Minyard out: 10148bfffbccSCorey Minyard return; 10158bfffbccSCorey Minyard } 10168bfffbccSCorey Minyard 10178bfffbccSCorey Minyard static unsigned char 10188bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 10198bfffbccSCorey Minyard { 10208bfffbccSCorey Minyard for (; size > 0; size--, data++) { 10218bfffbccSCorey Minyard csum += *data; 10228bfffbccSCorey Minyard } 10238bfffbccSCorey Minyard 10248bfffbccSCorey Minyard return -csum; 10258bfffbccSCorey Minyard } 10268bfffbccSCorey Minyard 10278bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 10288bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1029a580d820SCédric Le Goater RspBuffer *rsp) 10308bfffbccSCorey Minyard { 10318bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10328bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10338bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 10348bfffbccSCorey Minyard uint8_t *buf; 10358bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 10368bfffbccSCorey Minyard 10378bfffbccSCorey Minyard if (cmd[2] != 0) { 10388bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 10396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1040d13ada5dSCédric Le Goater return; 10418bfffbccSCorey Minyard } 10428bfffbccSCorey Minyard 10434f298a4bSCédric Le Goater if (cmd_len < 10) { 10446acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 10454f298a4bSCédric Le Goater return; 10464f298a4bSCédric Le Goater } 10474f298a4bSCédric Le Goater 10488bfffbccSCorey Minyard if (cmd[3] != 0x40) { 10498bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 10506acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */ 1051d13ada5dSCédric Le Goater return; 10528bfffbccSCorey Minyard } 10538bfffbccSCorey Minyard 10548bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10558bfffbccSCorey Minyard cmd_len -= 3; 10568bfffbccSCorey Minyard 10578bfffbccSCorey Minyard /* 10588bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10598bfffbccSCorey Minyard * be returned in the response. 10608bfffbccSCorey Minyard */ 10618bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10628bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1063d13ada5dSCédric Le Goater return; /* No response */ 10648bfffbccSCorey Minyard } 10658bfffbccSCorey Minyard 10668bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10678bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10688bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10698bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10708bfffbccSCorey Minyard 10718bfffbccSCorey Minyard if (rqLun != 2) { 10728bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1073d13ada5dSCédric Le Goater return; 10748bfffbccSCorey Minyard } 10758bfffbccSCorey Minyard 10768bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10778bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10788bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10798bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10808bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10818bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10828bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10838bfffbccSCorey Minyard msg->len = 6; 10848bfffbccSCorey Minyard 10858bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10868bfffbccSCorey Minyard /* Not a command we handle. */ 10878bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10888bfffbccSCorey Minyard goto end_msg; 10898bfffbccSCorey Minyard } 10908bfffbccSCorey Minyard 10918bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10928bfffbccSCorey Minyard buf[0] = 0; 10938bfffbccSCorey Minyard buf[1] = 0; 10948bfffbccSCorey Minyard buf[2] = 0; 10958bfffbccSCorey Minyard buf[3] = 0; 10968bfffbccSCorey Minyard buf[4] = 0x51; 10978bfffbccSCorey Minyard buf[5] = 0; 10988bfffbccSCorey Minyard buf[6] = 0; 10998bfffbccSCorey Minyard buf[7] = 0; 11008bfffbccSCorey Minyard buf[8] = 0; 11018bfffbccSCorey Minyard buf[9] = 0; 11028bfffbccSCorey Minyard buf[10] = 0; 11038bfffbccSCorey Minyard msg->len += 11; 11048bfffbccSCorey Minyard 11058bfffbccSCorey Minyard end_msg: 11068bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 11078bfffbccSCorey Minyard msg->len++; 11088bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 11098bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 11108bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 11118bfffbccSCorey Minyard } 11128bfffbccSCorey Minyard 11138bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 11148bfffbccSCorey Minyard { 11158bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 11168bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 11178bfffbccSCorey Minyard ibs->watchdog_running = 0; 11188bfffbccSCorey Minyard return; 11198bfffbccSCorey Minyard } 11208bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 11218bfffbccSCorey Minyard 11228bfffbccSCorey Minyard 11238bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 11248bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 11258bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 11268bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 11278bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 11288bfffbccSCorey Minyard } 11298bfffbccSCorey Minyard ibs->watchdog_running = 1; 11308bfffbccSCorey Minyard } 11318bfffbccSCorey Minyard 11328bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 11338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1134a580d820SCédric Le Goater RspBuffer *rsp) 11358bfffbccSCorey Minyard { 11368bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 11376acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1138d13ada5dSCédric Le Goater return; 11398bfffbccSCorey Minyard } 11408bfffbccSCorey Minyard do_watchdog_reset(ibs); 11418bfffbccSCorey Minyard } 11428bfffbccSCorey Minyard 11438bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 11448bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1145a580d820SCédric Le Goater RspBuffer *rsp) 11468bfffbccSCorey Minyard { 11478bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 11488bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 11498bfffbccSCorey Minyard unsigned int val; 11508bfffbccSCorey Minyard 11518bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 11528bfffbccSCorey Minyard if (val == 0 || val > 5) { 11536acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1154d13ada5dSCédric Le Goater return; 11558bfffbccSCorey Minyard } 11568bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11578bfffbccSCorey Minyard switch (val) { 11588bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11598bfffbccSCorey Minyard break; 11608bfffbccSCorey Minyard 11618bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11626acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1)); 11638bfffbccSCorey Minyard break; 11648bfffbccSCorey Minyard 11658bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11666acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1)); 11678bfffbccSCorey Minyard break; 11688bfffbccSCorey Minyard 11698bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11706acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1)); 11718bfffbccSCorey Minyard break; 11728bfffbccSCorey Minyard 11738bfffbccSCorey Minyard default: 11746acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 11758bfffbccSCorey Minyard } 1176a580d820SCédric Le Goater if (rsp->buffer[2]) { 11776acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1178d13ada5dSCédric Le Goater return; 11798bfffbccSCorey Minyard } 11808bfffbccSCorey Minyard 11818bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11828bfffbccSCorey Minyard switch (val) { 11838bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11848bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11858bfffbccSCorey Minyard break; 11868bfffbccSCorey Minyard 11878bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11888bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11898bfffbccSCorey Minyard /* NMI not supported. */ 11906acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1191d13ada5dSCédric Le Goater return; 11928bfffbccSCorey Minyard } 119337eebb86SCorey Minyard break; 119437eebb86SCorey Minyard 11958bfffbccSCorey Minyard default: 11968bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1198d13ada5dSCédric Le Goater return; 11998bfffbccSCorey Minyard } 12008bfffbccSCorey Minyard 12018bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 12028bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 12038bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 12048bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 12058bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 12068bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 12078bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 12088bfffbccSCorey Minyard do_watchdog_reset(ibs); 12098bfffbccSCorey Minyard } else { 12108bfffbccSCorey Minyard ibs->watchdog_running = 0; 12118bfffbccSCorey Minyard } 12128bfffbccSCorey Minyard } 12138bfffbccSCorey Minyard 12148bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 12158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1216a580d820SCédric Le Goater RspBuffer *rsp) 12178bfffbccSCorey Minyard { 1218a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1219a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1220a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1221a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 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 12348bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 12358bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1236a580d820SCédric Le Goater RspBuffer *rsp) 12378bfffbccSCorey Minyard { 12388bfffbccSCorey Minyard unsigned int i; 12398bfffbccSCorey Minyard 1240a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1241a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1242a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1243a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1244a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 12458bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1246a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 12478bfffbccSCorey Minyard } 12488bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1249a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 12508bfffbccSCorey Minyard } 12518bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1252a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 12538bfffbccSCorey Minyard } 12548bfffbccSCorey Minyard 12558bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 12568bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1257a580d820SCédric Le Goater RspBuffer *rsp) 12588bfffbccSCorey Minyard { 1259a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1260a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 12618bfffbccSCorey Minyard } 12628bfffbccSCorey Minyard 12638bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 12648bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1265a580d820SCédric Le Goater RspBuffer *rsp) 12668bfffbccSCorey Minyard { 12678bfffbccSCorey Minyard unsigned int pos; 12688bfffbccSCorey Minyard uint16_t nextrec; 1269a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 12708bfffbccSCorey Minyard 12718bfffbccSCorey Minyard if (cmd[6]) { 12727f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 12736acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 12747f996411SCédric Le Goater return; 12758bfffbccSCorey Minyard } 12767f996411SCédric Le Goater } 12777f996411SCédric Le Goater 12788bfffbccSCorey Minyard pos = 0; 12798bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 12808bfffbccSCorey Minyard &pos, &nextrec)) { 12816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1282d13ada5dSCédric Le Goater return; 12838bfffbccSCorey Minyard } 1284a2295f0aSCédric Le Goater 1285a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1286a2295f0aSCédric Le Goater 1287a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 12886acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE); 1289d13ada5dSCédric Le Goater return; 12908bfffbccSCorey Minyard } 12918bfffbccSCorey Minyard 1292a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1293a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 12948bfffbccSCorey Minyard 12958bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1296a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 12978bfffbccSCorey Minyard } 12988bfffbccSCorey Minyard 1299a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 13006acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES); 1301d13ada5dSCédric Le Goater return; 13028bfffbccSCorey Minyard } 1303a580d820SCédric Le Goater 1304a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 13058bfffbccSCorey Minyard } 13068bfffbccSCorey Minyard 13078bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 13088bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1309a580d820SCédric Le Goater RspBuffer *rsp) 13108bfffbccSCorey Minyard { 13118bfffbccSCorey Minyard uint16_t recid; 1312a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 13138bfffbccSCorey Minyard 1314a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 13156acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1316d13ada5dSCédric Le Goater return; 13178bfffbccSCorey Minyard } 1318a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1319a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 13208bfffbccSCorey Minyard } 13218bfffbccSCorey Minyard 13228bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 13238bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1324a580d820SCédric Le Goater RspBuffer *rsp) 13258bfffbccSCorey Minyard { 13267f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 13276acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13287f996411SCédric Le Goater return; 13297f996411SCédric Le Goater } 13307f996411SCédric Le Goater 13318bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1333d13ada5dSCédric Le Goater return; 13348bfffbccSCorey Minyard } 13358bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 13368bfffbccSCorey Minyard ibs->sdr.next_free = 0; 13378bfffbccSCorey Minyard ibs->sdr.overflow = 0; 13388bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1339a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13408bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 13418bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1342a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13438bfffbccSCorey Minyard } else { 13446acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 13458bfffbccSCorey Minyard return; 13468bfffbccSCorey Minyard } 1347d13ada5dSCédric Le Goater } 13488bfffbccSCorey Minyard 13498bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 13508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1351a580d820SCédric Le Goater RspBuffer *rsp) 13528bfffbccSCorey Minyard { 13538bfffbccSCorey Minyard unsigned int i, val; 13548bfffbccSCorey Minyard 1355a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1356a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1357a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 13588bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1359a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1360a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 13618bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1362a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 13638bfffbccSCorey Minyard } 13648bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1365a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 13668bfffbccSCorey Minyard } 13678bfffbccSCorey Minyard /* Only support Reserve SEL */ 1368a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 13698bfffbccSCorey Minyard } 13708bfffbccSCorey Minyard 1371540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs, 1372540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1373540c07d3SCédric Le Goater RspBuffer *rsp) 1374540c07d3SCédric Le Goater { 1375540c07d3SCédric Le Goater uint8_t fruid; 1376540c07d3SCédric Le Goater uint16_t fru_entry_size; 1377540c07d3SCédric Le Goater 1378540c07d3SCédric Le Goater fruid = cmd[2]; 1379540c07d3SCédric Le Goater 1380540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1381540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1382540c07d3SCédric Le Goater return; 1383540c07d3SCédric Le Goater } 1384540c07d3SCédric Le Goater 1385540c07d3SCédric Le Goater fru_entry_size = ibs->fru.areasize; 1386540c07d3SCédric Le Goater 1387540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size & 0xff); 1388540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff); 1389540c07d3SCédric Le Goater rsp_buffer_push(rsp, 0x0); 1390540c07d3SCédric Le Goater } 1391540c07d3SCédric Le Goater 1392540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs, 1393540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1394540c07d3SCédric Le Goater RspBuffer *rsp) 1395540c07d3SCédric Le Goater { 1396540c07d3SCédric Le Goater uint8_t fruid; 1397540c07d3SCédric Le Goater uint16_t offset; 1398540c07d3SCédric Le Goater int i; 1399540c07d3SCédric Le Goater uint8_t *fru_entry; 1400540c07d3SCédric Le Goater unsigned int count; 1401540c07d3SCédric Le Goater 1402540c07d3SCédric Le Goater fruid = cmd[2]; 1403540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1404540c07d3SCédric Le Goater 1405540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1406540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1407540c07d3SCédric Le Goater return; 1408540c07d3SCédric Le Goater } 1409540c07d3SCédric Le Goater 1410540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1411540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1412540c07d3SCédric Le Goater return; 1413540c07d3SCédric Le Goater } 1414540c07d3SCédric Le Goater 1415540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1416540c07d3SCédric Le Goater 1417540c07d3SCédric Le Goater count = MIN(cmd[5], ibs->fru.areasize - offset); 1418540c07d3SCédric Le Goater 1419540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1420540c07d3SCédric Le Goater for (i = 0; i < count; i++) { 1421540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry[offset + i]); 1422540c07d3SCédric Le Goater } 1423540c07d3SCédric Le Goater } 1424540c07d3SCédric Le Goater 1425540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs, 1426540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1427540c07d3SCédric Le Goater RspBuffer *rsp) 1428540c07d3SCédric Le Goater { 1429540c07d3SCédric Le Goater uint8_t fruid; 1430540c07d3SCédric Le Goater uint16_t offset; 1431540c07d3SCédric Le Goater uint8_t *fru_entry; 1432540c07d3SCédric Le Goater unsigned int count; 1433540c07d3SCédric Le Goater 1434540c07d3SCédric Le Goater fruid = cmd[2]; 1435540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1436540c07d3SCédric Le Goater 1437540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1438540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1439540c07d3SCédric Le Goater return; 1440540c07d3SCédric Le Goater } 1441540c07d3SCédric Le Goater 1442540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 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 = &ibs->fru.data[fruid * ibs->fru.areasize]; 1448540c07d3SCédric Le Goater 1449540c07d3SCédric Le Goater count = MIN(cmd_len - 5, ibs->fru.areasize - offset); 1450540c07d3SCédric Le Goater 1451540c07d3SCédric Le Goater memcpy(fru_entry + offset, cmd + 5, count); 1452540c07d3SCédric Le Goater 1453540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1454540c07d3SCédric Le Goater } 1455540c07d3SCédric Le Goater 14568bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 14578bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1458a580d820SCédric Le Goater RspBuffer *rsp) 14598bfffbccSCorey Minyard { 1460a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1461a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 14628bfffbccSCorey Minyard } 14638bfffbccSCorey Minyard 14648bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 14658bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1466a580d820SCédric Le Goater RspBuffer *rsp) 14678bfffbccSCorey Minyard { 14688bfffbccSCorey Minyard unsigned int val; 14698bfffbccSCorey Minyard 14708bfffbccSCorey Minyard if (cmd[6]) { 14717f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 14726acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 14737f996411SCédric Le Goater return; 14747f996411SCédric Le Goater } 14758bfffbccSCorey Minyard } 14768bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 14776acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1478d13ada5dSCédric Le Goater return; 14798bfffbccSCorey Minyard } 14808bfffbccSCorey Minyard if (cmd[6] > 15) { 14816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1482d13ada5dSCédric Le Goater return; 14838bfffbccSCorey Minyard } 14848bfffbccSCorey Minyard if (cmd[7] == 0xff) { 14858bfffbccSCorey Minyard cmd[7] = 16; 14868bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 14876acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1488d13ada5dSCédric Le Goater return; 14898bfffbccSCorey Minyard } else { 14908bfffbccSCorey Minyard cmd[7] += cmd[6]; 14918bfffbccSCorey Minyard } 14928bfffbccSCorey Minyard 14938bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 14948bfffbccSCorey Minyard if (val == 0xffff) { 14958bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 14968bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 14976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1498d13ada5dSCédric Le Goater return; 14998bfffbccSCorey Minyard } 15008bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1501a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1502a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 15038bfffbccSCorey Minyard } else { 1504a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1505a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 15068bfffbccSCorey Minyard } 15078bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1508a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 15098bfffbccSCorey Minyard } 15108bfffbccSCorey Minyard } 15118bfffbccSCorey Minyard 15128bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 15138bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1514a580d820SCédric Le Goater RspBuffer *rsp) 15158bfffbccSCorey Minyard { 15168bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 15176acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 1518d13ada5dSCédric Le Goater return; 15198bfffbccSCorey Minyard } 15208bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1521a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1522a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 15238bfffbccSCorey Minyard } 15248bfffbccSCorey Minyard 15258bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 15268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1527a580d820SCédric Le Goater RspBuffer *rsp) 15288bfffbccSCorey Minyard { 15297f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 15306acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 15317f996411SCédric Le Goater return; 15327f996411SCédric Le Goater } 15337f996411SCédric Le Goater 15348bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 15356acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1536d13ada5dSCédric Le Goater return; 15378bfffbccSCorey Minyard } 15388bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 15398bfffbccSCorey Minyard ibs->sel.next_free = 0; 15408bfffbccSCorey Minyard ibs->sel.overflow = 0; 15418bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1542a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 15438bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 15448bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1545a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 15468bfffbccSCorey Minyard } else { 15476acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 15488bfffbccSCorey Minyard return; 15498bfffbccSCorey Minyard } 1550d13ada5dSCédric Le Goater } 15518bfffbccSCorey Minyard 15528bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 15538bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1554a580d820SCédric Le Goater RspBuffer *rsp) 15558bfffbccSCorey Minyard { 15568bfffbccSCorey Minyard uint32_t val; 15578bfffbccSCorey Minyard struct ipmi_time now; 15588bfffbccSCorey Minyard 15598bfffbccSCorey Minyard ipmi_gettime(&now); 15608bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1561a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1562a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1563a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1564a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 15658bfffbccSCorey Minyard } 15668bfffbccSCorey Minyard 15678bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 15688bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1569a580d820SCédric Le Goater RspBuffer *rsp) 15708bfffbccSCorey Minyard { 15718bfffbccSCorey Minyard uint32_t val; 15728bfffbccSCorey Minyard struct ipmi_time now; 15738bfffbccSCorey Minyard 15748bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 15758bfffbccSCorey Minyard ipmi_gettime(&now); 15768bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 15778bfffbccSCorey Minyard } 15788bfffbccSCorey Minyard 15798bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 15808bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1581a580d820SCédric Le Goater RspBuffer *rsp) 15828bfffbccSCorey Minyard { 15838bfffbccSCorey Minyard IPMISensor *sens; 15848bfffbccSCorey Minyard 158573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15868bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15876acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1588d13ada5dSCédric Le Goater return; 15898bfffbccSCorey Minyard } 15908bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15918bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 15928bfffbccSCorey Minyard case 0: /* Do not change */ 15938bfffbccSCorey Minyard break; 15948bfffbccSCorey Minyard case 1: /* Enable bits */ 15958bfffbccSCorey Minyard if (cmd_len > 4) { 15968bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 15978bfffbccSCorey Minyard } 15988bfffbccSCorey Minyard if (cmd_len > 5) { 15998bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 16008bfffbccSCorey Minyard } 16018bfffbccSCorey Minyard if (cmd_len > 6) { 16028bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 16038bfffbccSCorey Minyard } 16048bfffbccSCorey Minyard if (cmd_len > 7) { 16058bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 16068bfffbccSCorey Minyard } 16078bfffbccSCorey Minyard break; 16088bfffbccSCorey Minyard case 2: /* Disable bits */ 16098bfffbccSCorey Minyard if (cmd_len > 4) { 16108bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 16118bfffbccSCorey Minyard } 16128bfffbccSCorey Minyard if (cmd_len > 5) { 16138bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 16148bfffbccSCorey Minyard } 16158bfffbccSCorey Minyard if (cmd_len > 6) { 16168bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 16178bfffbccSCorey Minyard } 16188bfffbccSCorey Minyard if (cmd_len > 7) { 16198bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 16208bfffbccSCorey Minyard } 16218bfffbccSCorey Minyard break; 16228bfffbccSCorey Minyard case 3: 16236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1624d13ada5dSCédric Le Goater return; 16258bfffbccSCorey Minyard } 16268bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 16278bfffbccSCorey Minyard } 16288bfffbccSCorey Minyard 16298bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 16308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1631a580d820SCédric Le Goater RspBuffer *rsp) 16328bfffbccSCorey Minyard { 16338bfffbccSCorey Minyard IPMISensor *sens; 16348bfffbccSCorey Minyard 163573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16368bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16376acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1638d13ada5dSCédric Le Goater return; 16398bfffbccSCorey Minyard } 16408bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1641a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1642a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1643a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1644a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1645a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 16468bfffbccSCorey Minyard } 16478bfffbccSCorey Minyard 16488bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 16498bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1650a580d820SCédric Le Goater RspBuffer *rsp) 16518bfffbccSCorey Minyard { 16528bfffbccSCorey Minyard IPMISensor *sens; 16538bfffbccSCorey Minyard 165473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16558bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16566acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1657d13ada5dSCédric Le Goater return; 16588bfffbccSCorey Minyard } 16598bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 16608bfffbccSCorey Minyard 16618bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 16628bfffbccSCorey Minyard /* Just clear everything */ 16638bfffbccSCorey Minyard sens->states = 0; 16648bfffbccSCorey Minyard return; 16658bfffbccSCorey Minyard } 1666d13ada5dSCédric Le Goater } 16678bfffbccSCorey Minyard 16688bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 16698bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1670a580d820SCédric Le Goater RspBuffer *rsp) 16718bfffbccSCorey Minyard { 16728bfffbccSCorey Minyard IPMISensor *sens; 16738bfffbccSCorey Minyard 167473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16758bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16766acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1677d13ada5dSCédric Le Goater return; 16788bfffbccSCorey Minyard } 16798bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1680a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1681a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1682a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1683a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1684a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1685a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 16868bfffbccSCorey Minyard } 16878bfffbccSCorey Minyard 16888bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 16898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1690a580d820SCédric Le Goater RspBuffer *rsp) 16918bfffbccSCorey Minyard { 16928bfffbccSCorey Minyard IPMISensor *sens; 16938bfffbccSCorey Minyard 169473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16958bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1697d13ada5dSCédric Le Goater return; 16988bfffbccSCorey Minyard } 16998bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1700a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1701a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1702a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 17038bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1704a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 17058bfffbccSCorey Minyard } 17068bfffbccSCorey Minyard } 17078bfffbccSCorey Minyard 1708728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1709728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1710a580d820SCédric Le Goater RspBuffer *rsp) 1711728710e1SCédric Le Goater { 1712728710e1SCédric Le Goater IPMISensor *sens; 1713728710e1SCédric Le Goater 1714728710e1SCédric Le Goater 171573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1716728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17176acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1718728710e1SCédric Le Goater return; 1719728710e1SCédric Le Goater } 1720728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1721728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1722728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1723728710e1SCédric Le Goater } 1724728710e1SCédric Le Goater 1725728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1726728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1727a580d820SCédric Le Goater RspBuffer *rsp) 1728728710e1SCédric Le Goater { 1729728710e1SCédric Le Goater IPMISensor *sens; 1730728710e1SCédric Le Goater 1731728710e1SCédric Le Goater 173273d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1733728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17346acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1735728710e1SCédric Le Goater return; 1736728710e1SCédric Le Goater } 1737728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1738a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1739a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1740728710e1SCédric Le Goater } 1741728710e1SCédric Le Goater 1742728710e1SCédric Le Goater 174362a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 17444f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 17454f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 17464f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 17474f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 17488bfffbccSCorey Minyard }; 17498bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 175062a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 17518bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 17528bfffbccSCorey Minyard }; 17538bfffbccSCorey Minyard 175462a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 17554f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 17564f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 17574f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 17584f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 17594f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 17604f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 17614f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 17628bfffbccSCorey Minyard }; 17638bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 176462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 17658bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 17668bfffbccSCorey Minyard }; 17678bfffbccSCorey Minyard 176862a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 17694f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 17704f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 17714f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 17724f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 17734f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 17744f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 17754f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 17764f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 17774f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 17784f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 17794f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 17804f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 17814f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 17824f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 17834f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 17844f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 17858bfffbccSCorey Minyard }; 17868bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 178762a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 17888bfffbccSCorey Minyard .cmd_handlers = app_cmds 17898bfffbccSCorey Minyard }; 17908bfffbccSCorey Minyard 179162a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 1792540c07d3SCédric Le Goater [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 }, 1793540c07d3SCédric Le Goater [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 }, 1794540c07d3SCédric Le Goater [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 }, 17954f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 17964f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 17974f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 17984f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 17994f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 18004f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 18014f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 18024f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 18034f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 18044f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 1805*7f11cb65SCorey Minyard [IPMI_CMD_GET_SEL_TIME] = { get_sel_time }, 1806*7f11cb65SCorey Minyard [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 }, 18078bfffbccSCorey Minyard }; 18088bfffbccSCorey Minyard 18098bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 181062a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 18118bfffbccSCorey Minyard .cmd_handlers = storage_cmds 18128bfffbccSCorey Minyard }; 18138bfffbccSCorey Minyard 18148bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 18158bfffbccSCorey Minyard { 18168bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 18178bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 18188bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 18198bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 18208bfffbccSCorey Minyard } 18218bfffbccSCorey Minyard 18225167560bSCédric Le Goater static uint8_t init_sdrs[] = { 18238bfffbccSCorey Minyard /* Watchdog device */ 18248bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 18258bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 18268bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18278bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 18288bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 18298bfffbccSCorey Minyard }; 18308bfffbccSCorey Minyard 18314fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs) 18324fa9f08eSCédric Le Goater { 18334fa9f08eSCédric Le Goater unsigned int i; 18344fa9f08eSCédric Le Goater int len; 18355167560bSCédric Le Goater size_t sdrs_size; 18365167560bSCédric Le Goater uint8_t *sdrs; 183752fc01d9SCédric Le Goater 18385167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs); 18395167560bSCédric Le Goater sdrs = init_sdrs; 18408c6fd7f3SCédric Le Goater if (ibs->sdr_filename && 18418c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size, 18428c6fd7f3SCédric Le Goater NULL)) { 18438c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename); 18448c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs); 18458c6fd7f3SCédric Le Goater sdrs = init_sdrs; 18468c6fd7f3SCédric Le Goater } 18475167560bSCédric Le Goater 18485167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) { 184952fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh; 185052fc01d9SCédric Le Goater 18515167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) { 18524fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 18538c6fd7f3SCédric Le Goater break; 18544fa9f08eSCédric Le Goater } 18555167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i]; 18564fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh); 18575167560bSCédric Le Goater if (i + len > sdrs_size) { 18584fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 18598c6fd7f3SCédric Le Goater break; 18604fa9f08eSCédric Le Goater } 18614fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 18624fa9f08eSCédric Le Goater } 18638c6fd7f3SCédric Le Goater 18648c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) { 18658c6fd7f3SCédric Le Goater g_free(sdrs); 18668c6fd7f3SCédric Le Goater } 18674fa9f08eSCédric Le Goater } 18684fa9f08eSCédric Le Goater 1869bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1870bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1871bd66bcfcSCorey Minyard .version_id = 1, 1872bd66bcfcSCorey Minyard .minimum_version_id = 1, 1873bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1874bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1875bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1876bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1877bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1878bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1879bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1880bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1881bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1882bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1883bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1884bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1885bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1886bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1887bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1888bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1889bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1890bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1891bd66bcfcSCorey Minyard IPMIBmcSim), 1892bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1893bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1894bd66bcfcSCorey Minyard } 1895bd66bcfcSCorey Minyard }; 1896bd66bcfcSCorey Minyard 1897540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru) 1898540c07d3SCédric Le Goater { 1899540c07d3SCédric Le Goater int fsize; 1900540c07d3SCédric Le Goater int size = 0; 1901540c07d3SCédric Le Goater 1902540c07d3SCédric Le Goater if (!fru->filename) { 1903540c07d3SCédric Le Goater goto out; 1904540c07d3SCédric Le Goater } 1905540c07d3SCédric Le Goater 1906540c07d3SCédric Le Goater fsize = get_image_size(fru->filename); 1907540c07d3SCédric Le Goater if (fsize > 0) { 1908540c07d3SCédric Le Goater size = QEMU_ALIGN_UP(fsize, fru->areasize); 1909540c07d3SCédric Le Goater fru->data = g_malloc0(size); 1910540c07d3SCédric Le Goater if (load_image_size(fru->filename, fru->data, fsize) != fsize) { 1911540c07d3SCédric Le Goater error_report("Could not load file '%s'", fru->filename); 1912540c07d3SCédric Le Goater g_free(fru->data); 1913540c07d3SCédric Le Goater fru->data = NULL; 1914540c07d3SCédric Le Goater } 1915540c07d3SCédric Le Goater } 1916540c07d3SCédric Le Goater 1917540c07d3SCédric Le Goater out: 1918540c07d3SCédric Le Goater if (!fru->data) { 1919540c07d3SCédric Le Goater /* give one default FRU */ 1920540c07d3SCédric Le Goater size = fru->areasize; 1921540c07d3SCédric Le Goater fru->data = g_malloc0(size); 1922540c07d3SCédric Le Goater } 1923540c07d3SCédric Le Goater 1924540c07d3SCédric Le Goater fru->nentries = size / fru->areasize; 1925540c07d3SCédric Le Goater } 1926540c07d3SCédric Le Goater 19270bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp) 19288bfffbccSCorey Minyard { 19290bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev); 19308bfffbccSCorey Minyard unsigned int i; 19318bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 19328bfffbccSCorey Minyard 19338bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 19348bfffbccSCorey Minyard 19358bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 19368bfffbccSCorey Minyard ibs->device_id = 0x20; 19378bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1938b7088392SCédric Le Goater ibs->restart_cause = 0; 19398bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 19408bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 19418bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 19428bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 19438bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 19448bfffbccSCorey Minyard } 19458bfffbccSCorey Minyard 19464fa9f08eSCédric Le Goater ipmi_sdr_init(ibs); 19478bfffbccSCorey Minyard 1948540c07d3SCédric Le Goater ipmi_fru_init(&ibs->fru); 1949540c07d3SCédric Le Goater 195052ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 195152ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 195252ba4d50SCédric Le Goater 195352ba4d50SCédric Le Goater if (qemu_uuid_set) { 19549c5ce8dbSFam Zheng memcpy(&ibs->uuid, &qemu_uuid, 16); 195552ba4d50SCédric Le Goater } else { 195652ba4d50SCédric Le Goater memset(&ibs->uuid, 0, 16); 195752ba4d50SCédric Le Goater } 195852ba4d50SCédric Le Goater 19598bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 19608bfffbccSCorey Minyard register_cmds(ibs); 19618bfffbccSCorey Minyard 19628bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1963bd66bcfcSCorey Minyard 1964bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 19658bfffbccSCorey Minyard } 19668bfffbccSCorey Minyard 19678c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = { 1968540c07d3SCédric Le Goater DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024), 1969540c07d3SCédric Le Goater DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename), 19708c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename), 19718c6fd7f3SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 19728c6fd7f3SCédric Le Goater }; 19738c6fd7f3SCédric Le Goater 19748bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 19758bfffbccSCorey Minyard { 19760bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc); 19778bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 19788bfffbccSCorey Minyard 197966abfddbSCorey Minyard dc->hotpluggable = false; 19800bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize; 19818c6fd7f3SCédric Le Goater dc->props = ipmi_sim_properties; 19828bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 19838bfffbccSCorey Minyard } 19848bfffbccSCorey Minyard 19858bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 19868bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 19878bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 19888bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 19898bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 19908bfffbccSCorey Minyard }; 19918bfffbccSCorey Minyard 19928bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 19938bfffbccSCorey Minyard { 19948bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 19958bfffbccSCorey Minyard } 19968bfffbccSCorey Minyard 19978bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1998