18bfffbccSCorey Minyard /* 28bfffbccSCorey Minyard * IPMI BMC emulation 38bfffbccSCorey Minyard * 48bfffbccSCorey Minyard * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC 58bfffbccSCorey Minyard * 68bfffbccSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 78bfffbccSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 88bfffbccSCorey Minyard * in the Software without restriction, including without limitation the rights 98bfffbccSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108bfffbccSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 118bfffbccSCorey Minyard * furnished to do so, subject to the following conditions: 128bfffbccSCorey Minyard * 138bfffbccSCorey Minyard * The above copyright notice and this permission notice shall be included in 148bfffbccSCorey Minyard * all copies or substantial portions of the Software. 158bfffbccSCorey Minyard * 168bfffbccSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178bfffbccSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188bfffbccSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198bfffbccSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208bfffbccSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218bfffbccSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228bfffbccSCorey Minyard * THE SOFTWARE. 238bfffbccSCorey Minyard */ 248bfffbccSCorey Minyard 250430891cSPeter Maydell #include "qemu/osdep.h" 2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h" 278bfffbccSCorey Minyard #include "qemu/timer.h" 288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 298bfffbccSCorey Minyard #include "qemu/error-report.h" 308bfffbccSCorey Minyard 318bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 328bfffbccSCorey Minyard 338bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 358bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 36b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 378bfffbccSCorey Minyard 388bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 398bfffbccSCorey Minyard 408bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 418bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 428bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 438bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 45728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e 46728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f 478bfffbccSCorey Minyard 488bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 498bfffbccSCorey Minyard 508bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 518bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 528bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 5352ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06 5452ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07 5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID 0x08 568bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 578bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 588bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 598bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 608bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 618bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 628bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 648bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 658bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 668bfffbccSCorey Minyard 678bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 688bfffbccSCorey Minyard 698bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 718bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 728bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 738bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 748bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 758bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 768bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 788bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 798bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 808bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 818bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 828bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 848bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 858bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 868bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 878bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 888bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 898bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 908bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 918bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 928bfffbccSCorey Minyard 938bfffbccSCorey Minyard 948bfffbccSCorey Minyard /* Same as a timespec struct. */ 958bfffbccSCorey Minyard struct ipmi_time { 968bfffbccSCorey Minyard long tv_sec; 978bfffbccSCorey Minyard long tv_nsec; 988bfffbccSCorey Minyard }; 998bfffbccSCorey Minyard 1008bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 1018bfffbccSCorey Minyard 1028bfffbccSCorey Minyard typedef struct IPMISel { 1038bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 1048bfffbccSCorey Minyard unsigned int next_free; 1058bfffbccSCorey Minyard long time_offset; 1068bfffbccSCorey Minyard uint16_t reservation; 1078bfffbccSCorey Minyard uint8_t last_addition[4]; 1088bfffbccSCorey Minyard uint8_t last_clear[4]; 1098bfffbccSCorey Minyard uint8_t overflow; 1108bfffbccSCorey Minyard } IPMISel; 1118bfffbccSCorey Minyard 1128bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1138bfffbccSCorey Minyard 1148bfffbccSCorey Minyard typedef struct IPMISdr { 1158bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1168bfffbccSCorey Minyard unsigned int next_free; 1178bfffbccSCorey Minyard uint16_t next_rec_id; 1188bfffbccSCorey Minyard uint16_t reservation; 1198bfffbccSCorey Minyard uint8_t last_addition[4]; 1208bfffbccSCorey Minyard uint8_t last_clear[4]; 1218bfffbccSCorey Minyard uint8_t overflow; 1228bfffbccSCorey Minyard } IPMISdr; 1238bfffbccSCorey Minyard 1248bfffbccSCorey Minyard typedef struct IPMISensor { 1258bfffbccSCorey Minyard uint8_t status; 1268bfffbccSCorey Minyard uint8_t reading; 1278bfffbccSCorey Minyard uint16_t states_suppt; 1288bfffbccSCorey Minyard uint16_t assert_suppt; 1298bfffbccSCorey Minyard uint16_t deassert_suppt; 1308bfffbccSCorey Minyard uint16_t states; 1318bfffbccSCorey Minyard uint16_t assert_states; 1328bfffbccSCorey Minyard uint16_t deassert_states; 1338bfffbccSCorey Minyard uint16_t assert_enable; 1348bfffbccSCorey Minyard uint16_t deassert_enable; 1358bfffbccSCorey Minyard uint8_t sensor_type; 1368bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1378bfffbccSCorey Minyard } IPMISensor; 1388bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1398bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1408bfffbccSCorey Minyard !!(v)) 1418bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1428bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1438bfffbccSCorey Minyard ((!!(v)) << 6)) 1448bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1458bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1468bfffbccSCorey Minyard ((!!(v)) << 7)) 1478bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1488bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1498bfffbccSCorey Minyard (v & 0xc0)) 1508bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1518bfffbccSCorey Minyard 1528bfffbccSCorey Minyard #define MAX_SENSORS 20 1538bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1548bfffbccSCorey Minyard 1558bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 156a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer; 1578bfffbccSCorey Minyard 1588bfffbccSCorey Minyard #define MAX_NETFNS 64 1594f298a4bSCédric Le Goater 1604f298a4bSCédric Le Goater typedef struct IPMICmdHandler { 1614f298a4bSCédric Le Goater void (*cmd_handler)(IPMIBmcSim *s, 1628bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 163a580d820SCédric Le Goater RspBuffer *rsp); 1644f298a4bSCédric Le Goater unsigned int cmd_len_min; 1654f298a4bSCédric Le Goater } IPMICmdHandler; 1664f298a4bSCédric Le Goater 1678bfffbccSCorey Minyard typedef struct IPMINetfn { 1688bfffbccSCorey Minyard unsigned int cmd_nums; 1698bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1708bfffbccSCorey Minyard } IPMINetfn; 1718bfffbccSCorey Minyard 1728bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1738bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1748bfffbccSCorey Minyard uint8_t len; 1758bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1768bfffbccSCorey Minyard } IPMIRcvBufEntry; 1778bfffbccSCorey Minyard 1788bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1798bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1808bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1818bfffbccSCorey Minyard struct IPMIBmcSim { 1828bfffbccSCorey Minyard IPMIBmc parent; 1838bfffbccSCorey Minyard 1848bfffbccSCorey Minyard QEMUTimer *timer; 1858bfffbccSCorey Minyard 1868bfffbccSCorey Minyard uint8_t bmc_global_enables; 1878bfffbccSCorey Minyard uint8_t msg_flags; 1888bfffbccSCorey Minyard 1898bfffbccSCorey Minyard bool watchdog_initialized; 1908bfffbccSCorey Minyard uint8_t watchdog_use; 1918bfffbccSCorey Minyard uint8_t watchdog_action; 1928bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 1938bfffbccSCorey Minyard bool watchdog_expired; 1948bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 1958bfffbccSCorey Minyard 1968bfffbccSCorey Minyard bool watchdog_running; 1978bfffbccSCorey Minyard bool watchdog_preaction_ran; 1988bfffbccSCorey Minyard int64_t watchdog_expiry; 1998bfffbccSCorey Minyard 2008bfffbccSCorey Minyard uint8_t device_id; 2018bfffbccSCorey Minyard uint8_t ipmi_version; 2028bfffbccSCorey Minyard uint8_t device_rev; 2038bfffbccSCorey Minyard uint8_t fwrev1; 2048bfffbccSCorey Minyard uint8_t fwrev2; 2058bfffbccSCorey Minyard uint8_t mfg_id[3]; 2068bfffbccSCorey Minyard uint8_t product_id[2]; 2078bfffbccSCorey Minyard 208b7088392SCédric Le Goater uint8_t restart_cause; 209b7088392SCédric Le Goater 21052ba4d50SCédric Le Goater uint8_t acpi_power_state[2]; 21152ba4d50SCédric Le Goater uint8_t uuid[16]; 21252ba4d50SCédric Le Goater 2138bfffbccSCorey Minyard IPMISel sel; 2148bfffbccSCorey Minyard IPMISdr sdr; 2158bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 2168bfffbccSCorey Minyard 2178bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2188bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2198bfffbccSCorey Minyard 2208bfffbccSCorey Minyard QemuMutex lock; 2218bfffbccSCorey Minyard /* We allow one event in the buffer */ 2228bfffbccSCorey Minyard uint8_t evtbuf[16]; 2238bfffbccSCorey Minyard 2248bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2258bfffbccSCorey Minyard }; 2268bfffbccSCorey Minyard 2278bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2318bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2328bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2338bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2348bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2358bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2368bfffbccSCorey Minyard 2378bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2388bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2398bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2418bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2428bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2438bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2448bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2458bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2468bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2478bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2488bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2498bfffbccSCorey Minyard 2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2658bfffbccSCorey Minyard 266a580d820SCédric Le Goater struct RspBuffer { 267a580d820SCédric Le Goater uint8_t buffer[MAX_IPMI_MSG_SIZE]; 268a580d820SCédric Le Goater unsigned int len; 269a580d820SCédric Le Goater }; 270a580d820SCédric Le Goater 271a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { } 2728bfffbccSCorey Minyard 2738bfffbccSCorey Minyard /* Add a byte to the response. */ 274a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte) 275a580d820SCédric Le Goater { 276a580d820SCédric Le Goater if (rsp->len >= sizeof(rsp->buffer)) { 277a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 278a580d820SCédric Le Goater return; 279a580d820SCédric Le Goater } 280a580d820SCédric Le Goater rsp->buffer[rsp->len++] = byte; 281a580d820SCédric Le Goater } 282a580d820SCédric Le Goater 283a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes, 284a580d820SCédric Le Goater unsigned int n) 285a580d820SCédric Le Goater { 286a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) { 287a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 288a580d820SCédric Le Goater return; 289a580d820SCédric Le Goater } 290a580d820SCédric Le Goater 291a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n); 292a580d820SCédric Le Goater rsp->len += n; 293a580d820SCédric Le Goater } 2948bfffbccSCorey Minyard 2958bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 2968bfffbccSCorey Minyard 2978bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 2988bfffbccSCorey Minyard { 2998bfffbccSCorey Minyard int64_t stime; 3008bfffbccSCorey Minyard 3018bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 3028bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 3038bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 3048bfffbccSCorey Minyard } 3058bfffbccSCorey Minyard 3068bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 3078bfffbccSCorey Minyard { 3088bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3098bfffbccSCorey Minyard } 3108bfffbccSCorey Minyard 3118bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 3128bfffbccSCorey Minyard { 3138bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3148bfffbccSCorey Minyard 3158bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3168bfffbccSCorey Minyard } 3178bfffbccSCorey Minyard 3188bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3198bfffbccSCorey Minyard { 3208bfffbccSCorey Minyard unsigned int val; 3218bfffbccSCorey Minyard struct ipmi_time now; 3228bfffbccSCorey Minyard 3238bfffbccSCorey Minyard ipmi_gettime(&now); 3248bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3258bfffbccSCorey Minyard ts[0] = val & 0xff; 3268bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3278bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3288bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3298bfffbccSCorey Minyard } 3308bfffbccSCorey Minyard 3318bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3328bfffbccSCorey Minyard { 3338bfffbccSCorey Minyard sdr->reservation++; 3348bfffbccSCorey Minyard if (sdr->reservation == 0) { 3358bfffbccSCorey Minyard sdr->reservation = 1; 3368bfffbccSCorey Minyard } 3378bfffbccSCorey Minyard } 3388bfffbccSCorey Minyard 339a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 340a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3418bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3428bfffbccSCorey Minyard { 343a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 344a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 345a2295f0aSCédric Le Goater 346a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3478bfffbccSCorey Minyard return 1; 3488bfffbccSCorey Minyard } 3498bfffbccSCorey Minyard 350a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3518bfffbccSCorey Minyard return 1; 3528bfffbccSCorey Minyard } 3538bfffbccSCorey Minyard 3548bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3558bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3568bfffbccSCorey Minyard return 1; 3578bfffbccSCorey Minyard } 3588bfffbccSCorey Minyard 359a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 360a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 361a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 362a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3638bfffbccSCorey Minyard 3648bfffbccSCorey Minyard if (recid) { 3658bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3668bfffbccSCorey Minyard } 3678bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3688bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3698bfffbccSCorey Minyard ibs->sdr.next_free += len; 3708bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3718bfffbccSCorey Minyard return 0; 3728bfffbccSCorey Minyard } 3738bfffbccSCorey Minyard 3748bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3758bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3768bfffbccSCorey Minyard { 3778bfffbccSCorey Minyard unsigned int pos = *retpos; 3788bfffbccSCorey Minyard 3798bfffbccSCorey Minyard while (pos < sdr->next_free) { 380a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 381a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 382a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 383a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 3848bfffbccSCorey Minyard 3858bfffbccSCorey Minyard if (trec == recid) { 3868bfffbccSCorey Minyard if (nextrec) { 3878bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3888bfffbccSCorey Minyard *nextrec = 0xffff; 3898bfffbccSCorey Minyard } else { 3908bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3918bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3928bfffbccSCorey Minyard } 3938bfffbccSCorey Minyard } 3948bfffbccSCorey Minyard *retpos = pos; 3958bfffbccSCorey Minyard return 0; 3968bfffbccSCorey Minyard } 3978bfffbccSCorey Minyard pos = nextpos; 3988bfffbccSCorey Minyard } 3998bfffbccSCorey Minyard return 1; 4008bfffbccSCorey Minyard } 4018bfffbccSCorey Minyard 4028bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 4038bfffbccSCorey Minyard { 4048bfffbccSCorey Minyard sel->reservation++; 4058bfffbccSCorey Minyard if (sel->reservation == 0) { 4068bfffbccSCorey Minyard sel->reservation = 1; 4078bfffbccSCorey Minyard } 4088bfffbccSCorey Minyard } 4098bfffbccSCorey Minyard 4108bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4118bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4128bfffbccSCorey Minyard { 4138bfffbccSCorey Minyard event[0] = 0xff; 4148bfffbccSCorey Minyard event[1] = 0xff; 4158bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 4168bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4178bfffbccSCorey Minyard ibs->sel.overflow = 1; 4188bfffbccSCorey Minyard return 1; 4198bfffbccSCorey Minyard } 4208bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4218bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4228bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 4238bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4248bfffbccSCorey Minyard ibs->sel.next_free++; 4258bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4268bfffbccSCorey Minyard return 0; 4278bfffbccSCorey Minyard } 4288bfffbccSCorey Minyard 4298bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4308bfffbccSCorey Minyard { 4318bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4328bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4338bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4348bfffbccSCorey Minyard } 4358bfffbccSCorey Minyard 4368bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4378bfffbccSCorey Minyard { 4388bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4398bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4408bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4418bfffbccSCorey Minyard } 4428bfffbccSCorey Minyard 4438bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4448bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4458bfffbccSCorey Minyard { 4468bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4478bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4488bfffbccSCorey Minyard uint8_t evt[16]; 4498bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4508bfffbccSCorey Minyard 4518bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4528bfffbccSCorey Minyard return; 4538bfffbccSCorey Minyard } 4548bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4558bfffbccSCorey Minyard return; 4568bfffbccSCorey Minyard } 4578bfffbccSCorey Minyard 4588bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4598bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4608bfffbccSCorey Minyard evt[8] = 0; 4618bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4628bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4638bfffbccSCorey Minyard evt[11] = sens_num; 4648bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4658bfffbccSCorey Minyard evt[13] = evd1; 4668bfffbccSCorey Minyard evt[14] = evd2; 4678bfffbccSCorey Minyard evt[15] = evd3; 4688bfffbccSCorey Minyard 4698bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 4708bfffbccSCorey Minyard sel_add_event(ibs, evt); 4718bfffbccSCorey Minyard } 4728bfffbccSCorey Minyard 4738bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 474d13ada5dSCédric Le Goater return; 4758bfffbccSCorey Minyard } 4768bfffbccSCorey Minyard 4778bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 4788bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 4798bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 4808bfffbccSCorey Minyard } 4818bfffbccSCorey Minyard 4828bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 4838bfffbccSCorey Minyard unsigned int bit, unsigned int val, 4848bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4858bfffbccSCorey Minyard { 4868bfffbccSCorey Minyard IPMISensor *sens; 4878bfffbccSCorey Minyard uint16_t mask; 4888bfffbccSCorey Minyard 4898bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 4908bfffbccSCorey Minyard return; 4918bfffbccSCorey Minyard } 4928bfffbccSCorey Minyard if (bit >= 16) { 4938bfffbccSCorey Minyard return; 4948bfffbccSCorey Minyard } 4958bfffbccSCorey Minyard 4968bfffbccSCorey Minyard mask = (1 << bit); 4978bfffbccSCorey Minyard sens = ibs->sensors + sensor; 4988bfffbccSCorey Minyard if (val) { 4998bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5008bfffbccSCorey Minyard if (sens->assert_states & mask) { 5018bfffbccSCorey Minyard return; /* Already asserted */ 5028bfffbccSCorey Minyard } 5038bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 5048bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 5058bfffbccSCorey Minyard /* Send an event on assert */ 5068bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5078bfffbccSCorey Minyard } 5088bfffbccSCorey Minyard } else { 5098bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5108bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5118bfffbccSCorey Minyard return; /* Already deasserted */ 5128bfffbccSCorey Minyard } 5138bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5148bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5158bfffbccSCorey Minyard /* Send an event on deassert */ 5168bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5178bfffbccSCorey Minyard } 5188bfffbccSCorey Minyard } 5198bfffbccSCorey Minyard } 5208bfffbccSCorey Minyard 5218bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5228bfffbccSCorey Minyard { 5238bfffbccSCorey Minyard unsigned int i, pos; 5248bfffbccSCorey Minyard IPMISensor *sens; 5258bfffbccSCorey Minyard 5268bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5278bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5288bfffbccSCorey Minyard } 5298bfffbccSCorey Minyard 5308bfffbccSCorey Minyard pos = 0; 5318bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 532a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 533a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 534a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5358bfffbccSCorey Minyard 5368bfffbccSCorey Minyard if (len < 20) { 5378bfffbccSCorey Minyard continue; 5388bfffbccSCorey Minyard } 539a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5408bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5418bfffbccSCorey Minyard } 5428bfffbccSCorey Minyard 54373d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 5448bfffbccSCorey Minyard continue; 5458bfffbccSCorey Minyard } 546a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5478bfffbccSCorey Minyard 5488bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 549a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 550a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 551a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 552a2295f0aSCédric Le Goater sens->deassert_suppt = 553a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 554a2295f0aSCédric Le Goater sens->states_suppt = 555a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 556a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 557a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5588bfffbccSCorey Minyard 5598bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5608bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5618bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5628bfffbccSCorey Minyard } 5638bfffbccSCorey Minyard } 5648bfffbccSCorey Minyard 5658bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5668bfffbccSCorey Minyard const IPMINetfn *netfnd) 5678bfffbccSCorey Minyard { 56893a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 5698bfffbccSCorey Minyard return -1; 5708bfffbccSCorey Minyard } 5718bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 5728bfffbccSCorey Minyard return 0; 5738bfffbccSCorey Minyard } 5748bfffbccSCorey Minyard 5754f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 5764f298a4bSCédric Le Goater unsigned int netfn, 5774f298a4bSCédric Le Goater unsigned int cmd) 5784f298a4bSCédric Le Goater { 5794f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 5804f298a4bSCédric Le Goater 5814f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 5824f298a4bSCédric Le Goater return NULL; 5834f298a4bSCédric Le Goater } 5844f298a4bSCédric Le Goater 5854f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 5864f298a4bSCédric Le Goater return NULL; 5874f298a4bSCédric Le Goater } 5884f298a4bSCédric Le Goater 5894f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 5904f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 5914f298a4bSCédric Le Goater return NULL; 5924f298a4bSCédric Le Goater } 5934f298a4bSCédric Le Goater 5944f298a4bSCédric Le Goater return hdl; 5954f298a4bSCédric Le Goater } 5964f298a4bSCédric Le Goater 5978bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 5988bfffbccSCorey Minyard { 5998bfffbccSCorey Minyard int64_t next; 6008bfffbccSCorey Minyard if (ibs->watchdog_running) { 6018bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6028bfffbccSCorey Minyard } else { 6038bfffbccSCorey Minyard /* Wait a minute */ 6048bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6058bfffbccSCorey Minyard } 6068bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6078bfffbccSCorey Minyard } 6088bfffbccSCorey Minyard 6098bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6108bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6118bfffbccSCorey Minyard unsigned int max_cmd_len, 6128bfffbccSCorey Minyard uint8_t msg_id) 6138bfffbccSCorey Minyard { 6148bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6158bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6168bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6174f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 618a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6198bfffbccSCorey Minyard 6208bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6218bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 622a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 623a580d820SCédric Le Goater rsp.buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 624d13ada5dSCédric Le Goater goto out; 625d13ada5dSCédric Le Goater } 626d13ada5dSCédric Le Goater 627a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 628a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 629a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6308bfffbccSCorey Minyard 6318bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6328bfffbccSCorey Minyard if (cmd_len < 2) { 633a580d820SCédric Le Goater rsp.buffer[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 6348bfffbccSCorey Minyard goto out; 6358bfffbccSCorey Minyard } 6368bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 637a580d820SCédric Le Goater rsp.buffer[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 6388bfffbccSCorey Minyard goto out; 6398bfffbccSCorey Minyard } 6408bfffbccSCorey Minyard 6418bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6428bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 643a580d820SCédric Le Goater rsp.buffer[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN; 6448bfffbccSCorey Minyard goto out; 6458bfffbccSCorey Minyard } 6468bfffbccSCorey Minyard 6474f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 6484f298a4bSCédric Le Goater if (!hdl) { 649a580d820SCédric Le Goater rsp.buffer[2] = IPMI_CC_INVALID_CMD; 6508bfffbccSCorey Minyard goto out; 6518bfffbccSCorey Minyard } 6528bfffbccSCorey Minyard 6534f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 654a580d820SCédric Le Goater rsp.buffer[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 6554f298a4bSCédric Le Goater goto out; 6564f298a4bSCédric Le Goater } 6574f298a4bSCédric Le Goater 658a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 6598bfffbccSCorey Minyard 6608bfffbccSCorey Minyard out: 661a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 6628bfffbccSCorey Minyard 6638bfffbccSCorey Minyard next_timeout(ibs); 6648bfffbccSCorey Minyard } 6658bfffbccSCorey Minyard 6668bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 6678bfffbccSCorey Minyard { 6688bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6698bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6708bfffbccSCorey Minyard 6718bfffbccSCorey Minyard if (!ibs->watchdog_running) { 6728bfffbccSCorey Minyard goto out; 6738bfffbccSCorey Minyard } 6748bfffbccSCorey Minyard 6758bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 6768bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 6778bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 6788bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6798bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 6808bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6818bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 6828bfffbccSCorey Minyard break; 6838bfffbccSCorey Minyard 6848bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 6858bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6868bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 6878bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6888bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 6898bfffbccSCorey Minyard break; 6908bfffbccSCorey Minyard 6918bfffbccSCorey Minyard default: 6928bfffbccSCorey Minyard goto do_full_expiry; 6938bfffbccSCorey Minyard } 6948bfffbccSCorey Minyard 6958bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 6968bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 6978bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 6988bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 6998bfffbccSCorey Minyard goto out; 7008bfffbccSCorey Minyard } 7018bfffbccSCorey Minyard 7028bfffbccSCorey Minyard do_full_expiry: 7038bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7048bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7058bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7068bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7078bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 7088bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 7098bfffbccSCorey Minyard break; 7108bfffbccSCorey Minyard 7118bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7128bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 7138bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 7148bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7158bfffbccSCorey Minyard break; 7168bfffbccSCorey Minyard 7178bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7188bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7198bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 7208bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7218bfffbccSCorey Minyard break; 7228bfffbccSCorey Minyard 7238bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7248bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7258bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7268bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7278bfffbccSCorey Minyard break; 7288bfffbccSCorey Minyard } 7298bfffbccSCorey Minyard 7308bfffbccSCorey Minyard out: 7318bfffbccSCorey Minyard next_timeout(ibs); 7328bfffbccSCorey Minyard } 7338bfffbccSCorey Minyard 7348bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7358bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 736a580d820SCédric Le Goater RspBuffer *rsp) 7378bfffbccSCorey Minyard { 738a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 739a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 740a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 741a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 742a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 7438bfffbccSCorey Minyard } 7448bfffbccSCorey Minyard 7458bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7468bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 747a580d820SCédric Le Goater RspBuffer *rsp) 7488bfffbccSCorey Minyard { 749a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 750a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 751a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 752a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 7538bfffbccSCorey Minyard } 7548bfffbccSCorey Minyard 7558bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7568bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 757a580d820SCédric Le Goater RspBuffer *rsp) 7588bfffbccSCorey Minyard { 7598bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7608bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7618bfffbccSCorey Minyard 7628bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7638bfffbccSCorey Minyard case 0: /* power down */ 764a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7658bfffbccSCorey Minyard break; 7668bfffbccSCorey Minyard case 1: /* power up */ 767a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0); 7688bfffbccSCorey Minyard break; 7698bfffbccSCorey Minyard case 2: /* power cycle */ 770a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7718bfffbccSCorey Minyard break; 7728bfffbccSCorey Minyard case 3: /* hard reset */ 773a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7748bfffbccSCorey Minyard break; 7758bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 776a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0); 7778bfffbccSCorey Minyard break; 7788bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 779a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, 7808bfffbccSCorey Minyard IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0); 7818bfffbccSCorey Minyard break; 7828bfffbccSCorey Minyard default: 783a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 7848bfffbccSCorey Minyard return; 7858bfffbccSCorey Minyard } 786d13ada5dSCédric Le Goater } 7878bfffbccSCorey Minyard 788b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 789b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 790a580d820SCédric Le Goater RspBuffer *rsp) 791a580d820SCédric Le Goater 792b7088392SCédric Le Goater { 793a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 794a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 795b7088392SCédric Le Goater } 796b7088392SCédric Le Goater 7978bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 7988bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 799a580d820SCédric Le Goater RspBuffer *rsp) 8008bfffbccSCorey Minyard { 801a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 802a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 803a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 804a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 805a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 806a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 807a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[0]); 808a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[1]); 809a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[2]); 810a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[0]); 811a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[1]); 8128bfffbccSCorey Minyard } 8138bfffbccSCorey Minyard 8148bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8158bfffbccSCorey Minyard { 8168bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8178bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8188bfffbccSCorey Minyard bool irqs_on; 8198bfffbccSCorey Minyard 8208bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8218bfffbccSCorey Minyard 8228bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8238bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8248bfffbccSCorey Minyard 8258bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8268bfffbccSCorey Minyard } 8278bfffbccSCorey Minyard 8288bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8298bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 830a580d820SCédric Le Goater RspBuffer *rsp) 8318bfffbccSCorey Minyard { 8328bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8338bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8348bfffbccSCorey Minyard 8358bfffbccSCorey Minyard /* Disable all interrupts */ 8368bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8378bfffbccSCorey Minyard 8388bfffbccSCorey Minyard if (k->reset) { 8398bfffbccSCorey Minyard k->reset(s, true); 8408bfffbccSCorey Minyard } 8418bfffbccSCorey Minyard } 8428bfffbccSCorey Minyard 8438bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8448bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 845a580d820SCédric Le Goater RspBuffer *rsp) 8468bfffbccSCorey Minyard { 8478bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8488bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8498bfffbccSCorey Minyard 8508bfffbccSCorey Minyard if (k->reset) { 8518bfffbccSCorey Minyard k->reset(s, false); 8528bfffbccSCorey Minyard } 8538bfffbccSCorey Minyard } 85452ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 85552ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 856a580d820SCédric Le Goater RspBuffer *rsp) 85752ba4d50SCédric Le Goater { 85852ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 85952ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 86052ba4d50SCédric Le Goater } 86152ba4d50SCédric Le Goater 86252ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 86352ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 864a580d820SCédric Le Goater RspBuffer *rsp) 86552ba4d50SCédric Le Goater { 866a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 867a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 86852ba4d50SCédric Le Goater } 86952ba4d50SCédric Le Goater 87052ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 87152ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 872a580d820SCédric Le Goater RspBuffer *rsp) 87352ba4d50SCédric Le Goater { 87452ba4d50SCédric Le Goater unsigned int i; 87552ba4d50SCédric Le Goater 87652ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 877a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->uuid[i]); 87852ba4d50SCédric Le Goater } 87952ba4d50SCédric Le Goater } 8808bfffbccSCorey Minyard 8818bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 8828bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 883a580d820SCédric Le Goater RspBuffer *rsp) 8848bfffbccSCorey Minyard { 8858bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 8868bfffbccSCorey Minyard } 8878bfffbccSCorey Minyard 8888bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 8898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 890a580d820SCédric Le Goater RspBuffer *rsp) 8918bfffbccSCorey Minyard { 892a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 8938bfffbccSCorey Minyard } 8948bfffbccSCorey Minyard 8958bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 8968bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 897a580d820SCédric Le Goater RspBuffer *rsp) 8988bfffbccSCorey Minyard { 8998bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9008bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9018bfffbccSCorey Minyard 9028bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9038bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9048bfffbccSCorey Minyard } 9058bfffbccSCorey Minyard 9068bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9078bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 908a580d820SCédric Le Goater RspBuffer *rsp) 9098bfffbccSCorey Minyard { 910a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9118bfffbccSCorey Minyard } 9128bfffbccSCorey Minyard 9138bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9148bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 915a580d820SCédric Le Goater RspBuffer *rsp) 9168bfffbccSCorey Minyard { 9178bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9188bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9198bfffbccSCorey Minyard unsigned int i; 9208bfffbccSCorey Minyard 9218bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 922a580d820SCédric Le Goater rsp->buffer[2] = 0x80; 923d13ada5dSCédric Le Goater return; 9248bfffbccSCorey Minyard } 9258bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 926a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 9278bfffbccSCorey Minyard } 9288bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9298bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9308bfffbccSCorey Minyard } 9318bfffbccSCorey Minyard 9328bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 934a580d820SCédric Le Goater RspBuffer *rsp) 9358bfffbccSCorey Minyard { 9368bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9378bfffbccSCorey Minyard 9388bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 9398bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 940a580d820SCédric Le Goater rsp->buffer[2] = 0x80; /* Queue empty */ 9418bfffbccSCorey Minyard goto out; 9428bfffbccSCorey Minyard } 943a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 9448bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 945a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 9468bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9478bfffbccSCorey Minyard g_free(msg); 9488bfffbccSCorey Minyard 9498bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9508bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9518bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9528bfffbccSCorey Minyard 9538bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9548bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9558bfffbccSCorey Minyard } 9568bfffbccSCorey Minyard 9578bfffbccSCorey Minyard out: 9588bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 9598bfffbccSCorey Minyard return; 9608bfffbccSCorey Minyard } 9618bfffbccSCorey Minyard 9628bfffbccSCorey Minyard static unsigned char 9638bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 9648bfffbccSCorey Minyard { 9658bfffbccSCorey Minyard for (; size > 0; size--, data++) { 9668bfffbccSCorey Minyard csum += *data; 9678bfffbccSCorey Minyard } 9688bfffbccSCorey Minyard 9698bfffbccSCorey Minyard return -csum; 9708bfffbccSCorey Minyard } 9718bfffbccSCorey Minyard 9728bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 9738bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 974a580d820SCédric Le Goater RspBuffer *rsp) 9758bfffbccSCorey Minyard { 9768bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9778bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9788bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9798bfffbccSCorey Minyard uint8_t *buf; 9808bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 9818bfffbccSCorey Minyard 9828bfffbccSCorey Minyard if (cmd[2] != 0) { 9838bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 984a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 985d13ada5dSCédric Le Goater return; 9868bfffbccSCorey Minyard } 9878bfffbccSCorey Minyard 9884f298a4bSCédric Le Goater if (cmd_len < 10) { 989a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 9904f298a4bSCédric Le Goater return; 9914f298a4bSCédric Le Goater } 9924f298a4bSCédric Le Goater 9938bfffbccSCorey Minyard if (cmd[3] != 0x40) { 9948bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 995a580d820SCédric Le Goater rsp->buffer[2] = 0x83; /* NAK on write */ 996d13ada5dSCédric Le Goater return; 9978bfffbccSCorey Minyard } 9988bfffbccSCorey Minyard 9998bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10008bfffbccSCorey Minyard cmd_len -= 3; 10018bfffbccSCorey Minyard 10028bfffbccSCorey Minyard /* 10038bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10048bfffbccSCorey Minyard * be returned in the response. 10058bfffbccSCorey Minyard */ 10068bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10078bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1008d13ada5dSCédric Le Goater return; /* No response */ 10098bfffbccSCorey Minyard } 10108bfffbccSCorey Minyard 10118bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10128bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10138bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10148bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10158bfffbccSCorey Minyard 10168bfffbccSCorey Minyard if (rqLun != 2) { 10178bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1018d13ada5dSCédric Le Goater return; 10198bfffbccSCorey Minyard } 10208bfffbccSCorey Minyard 10218bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10228bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10238bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10248bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10258bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10268bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10278bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10288bfffbccSCorey Minyard msg->len = 6; 10298bfffbccSCorey Minyard 10308bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10318bfffbccSCorey Minyard /* Not a command we handle. */ 10328bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10338bfffbccSCorey Minyard goto end_msg; 10348bfffbccSCorey Minyard } 10358bfffbccSCorey Minyard 10368bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10378bfffbccSCorey Minyard buf[0] = 0; 10388bfffbccSCorey Minyard buf[1] = 0; 10398bfffbccSCorey Minyard buf[2] = 0; 10408bfffbccSCorey Minyard buf[3] = 0; 10418bfffbccSCorey Minyard buf[4] = 0x51; 10428bfffbccSCorey Minyard buf[5] = 0; 10438bfffbccSCorey Minyard buf[6] = 0; 10448bfffbccSCorey Minyard buf[7] = 0; 10458bfffbccSCorey Minyard buf[8] = 0; 10468bfffbccSCorey Minyard buf[9] = 0; 10478bfffbccSCorey Minyard buf[10] = 0; 10488bfffbccSCorey Minyard msg->len += 11; 10498bfffbccSCorey Minyard 10508bfffbccSCorey Minyard end_msg: 10518bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 10528bfffbccSCorey Minyard msg->len++; 10538bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 10548bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 10558bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10568bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 10578bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 10588bfffbccSCorey Minyard } 10598bfffbccSCorey Minyard 10608bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 10618bfffbccSCorey Minyard { 10628bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 10638bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 10648bfffbccSCorey Minyard ibs->watchdog_running = 0; 10658bfffbccSCorey Minyard return; 10668bfffbccSCorey Minyard } 10678bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 10688bfffbccSCorey Minyard 10698bfffbccSCorey Minyard 10708bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 10718bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 10728bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 10738bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 10748bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 10758bfffbccSCorey Minyard } 10768bfffbccSCorey Minyard ibs->watchdog_running = 1; 10778bfffbccSCorey Minyard } 10788bfffbccSCorey Minyard 10798bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 10808bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1081a580d820SCédric Le Goater RspBuffer *rsp) 10828bfffbccSCorey Minyard { 10838bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 1084a580d820SCédric Le Goater rsp->buffer[2] = 0x80; 1085d13ada5dSCédric Le Goater return; 10868bfffbccSCorey Minyard } 10878bfffbccSCorey Minyard do_watchdog_reset(ibs); 10888bfffbccSCorey Minyard } 10898bfffbccSCorey Minyard 10908bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 10918bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1092a580d820SCédric Le Goater RspBuffer *rsp) 10938bfffbccSCorey Minyard { 10948bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10958bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10968bfffbccSCorey Minyard unsigned int val; 10978bfffbccSCorey Minyard 10988bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 10998bfffbccSCorey Minyard if (val == 0 || val > 5) { 1100a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1101d13ada5dSCédric Le Goater return; 11028bfffbccSCorey Minyard } 11038bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11048bfffbccSCorey Minyard switch (val) { 11058bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11068bfffbccSCorey Minyard break; 11078bfffbccSCorey Minyard 11088bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 1109a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1); 11108bfffbccSCorey Minyard break; 11118bfffbccSCorey Minyard 11128bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 1113a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1); 11148bfffbccSCorey Minyard break; 11158bfffbccSCorey Minyard 11168bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 1117a580d820SCédric Le Goater rsp->buffer[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1); 11188bfffbccSCorey Minyard break; 11198bfffbccSCorey Minyard 11208bfffbccSCorey Minyard default: 1121a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 11228bfffbccSCorey Minyard } 1123a580d820SCédric Le Goater if (rsp->buffer[2]) { 1124a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1125d13ada5dSCédric Le Goater return; 11268bfffbccSCorey Minyard } 11278bfffbccSCorey Minyard 11288bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11298bfffbccSCorey Minyard switch (val) { 11308bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11318bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11328bfffbccSCorey Minyard break; 11338bfffbccSCorey Minyard 11348bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11358bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11368bfffbccSCorey Minyard /* NMI not supported. */ 1137a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1138d13ada5dSCédric Le Goater return; 11398bfffbccSCorey Minyard } 114037eebb86SCorey Minyard break; 114137eebb86SCorey Minyard 11428bfffbccSCorey Minyard default: 11438bfffbccSCorey Minyard /* We don't support PRE_SMI */ 1144a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1145d13ada5dSCédric Le Goater return; 11468bfffbccSCorey Minyard } 11478bfffbccSCorey Minyard 11488bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11498bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11508bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11518bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 11528bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 11538bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 11548bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 11558bfffbccSCorey Minyard do_watchdog_reset(ibs); 11568bfffbccSCorey Minyard } else { 11578bfffbccSCorey Minyard ibs->watchdog_running = 0; 11588bfffbccSCorey Minyard } 11598bfffbccSCorey Minyard } 11608bfffbccSCorey Minyard 11618bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 11628bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1163a580d820SCédric Le Goater RspBuffer *rsp) 11648bfffbccSCorey Minyard { 1165a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1166a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1167a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1168a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 11698bfffbccSCorey Minyard if (ibs->watchdog_running) { 11708bfffbccSCorey Minyard long timeout; 11718bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 11728bfffbccSCorey Minyard / 100000000); 1173a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff); 1174a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff); 11758bfffbccSCorey Minyard } else { 1176a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 1177a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 11788bfffbccSCorey Minyard } 11798bfffbccSCorey Minyard } 11808bfffbccSCorey Minyard 11818bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 11828bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1183a580d820SCédric Le Goater RspBuffer *rsp) 11848bfffbccSCorey Minyard { 11858bfffbccSCorey Minyard unsigned int i; 11868bfffbccSCorey Minyard 1187a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1188a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1189a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1190a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1191a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 11928bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1193a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 11948bfffbccSCorey Minyard } 11958bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1196a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 11978bfffbccSCorey Minyard } 11988bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1199a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 12008bfffbccSCorey Minyard } 12018bfffbccSCorey Minyard 12028bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 12038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1204a580d820SCédric Le Goater RspBuffer *rsp) 12058bfffbccSCorey Minyard { 1206a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1207a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 12088bfffbccSCorey Minyard } 12098bfffbccSCorey Minyard 12108bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 12118bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1212a580d820SCédric Le Goater RspBuffer *rsp) 12138bfffbccSCorey Minyard { 12148bfffbccSCorey Minyard unsigned int pos; 12158bfffbccSCorey Minyard uint16_t nextrec; 1216a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 12178bfffbccSCorey Minyard 12188bfffbccSCorey Minyard if (cmd[6]) { 1219*7f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 1220*7f996411SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION; 1221*7f996411SCédric Le Goater return; 12228bfffbccSCorey Minyard } 1223*7f996411SCédric Le Goater } 1224*7f996411SCédric Le Goater 12258bfffbccSCorey Minyard pos = 0; 12268bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 12278bfffbccSCorey Minyard &pos, &nextrec)) { 1228a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1229d13ada5dSCédric Le Goater return; 12308bfffbccSCorey Minyard } 1231a2295f0aSCédric Le Goater 1232a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1233a2295f0aSCédric Le Goater 1234a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 1235a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_PARM_OUT_OF_RANGE; 1236d13ada5dSCédric Le Goater return; 12378bfffbccSCorey Minyard } 12388bfffbccSCorey Minyard 1239a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1240a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 12418bfffbccSCorey Minyard 12428bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1243a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 12448bfffbccSCorey Minyard } 12458bfffbccSCorey Minyard 1246a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 1247a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 1248d13ada5dSCédric Le Goater return; 12498bfffbccSCorey Minyard } 1250a580d820SCédric Le Goater 1251a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 12528bfffbccSCorey Minyard } 12538bfffbccSCorey Minyard 12548bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 12558bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1256a580d820SCédric Le Goater RspBuffer *rsp) 12578bfffbccSCorey Minyard { 12588bfffbccSCorey Minyard uint16_t recid; 1259a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 12608bfffbccSCorey Minyard 1261a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 1262a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1263d13ada5dSCédric Le Goater return; 12648bfffbccSCorey Minyard } 1265a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1266a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 12678bfffbccSCorey Minyard } 12688bfffbccSCorey Minyard 12698bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 12708bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1271a580d820SCédric Le Goater RspBuffer *rsp) 12728bfffbccSCorey Minyard { 1273*7f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 1274*7f996411SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION; 1275*7f996411SCédric Le Goater return; 1276*7f996411SCédric Le Goater } 1277*7f996411SCédric Le Goater 12788bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 1279a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1280d13ada5dSCédric Le Goater return; 12818bfffbccSCorey Minyard } 12828bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 12838bfffbccSCorey Minyard ibs->sdr.next_free = 0; 12848bfffbccSCorey Minyard ibs->sdr.overflow = 0; 12858bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1286a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 12878bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 12888bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1289a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 12908bfffbccSCorey Minyard } else { 1291a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 12928bfffbccSCorey Minyard return; 12938bfffbccSCorey Minyard } 1294d13ada5dSCédric Le Goater } 12958bfffbccSCorey Minyard 12968bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 12978bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1298a580d820SCédric Le Goater RspBuffer *rsp) 12998bfffbccSCorey Minyard { 13008bfffbccSCorey Minyard unsigned int i, val; 13018bfffbccSCorey Minyard 1302a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1303a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1304a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 13058bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1306a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1307a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 13088bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1309a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 13108bfffbccSCorey Minyard } 13118bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1312a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 13138bfffbccSCorey Minyard } 13148bfffbccSCorey Minyard /* Only support Reserve SEL */ 1315a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 13168bfffbccSCorey Minyard } 13178bfffbccSCorey Minyard 13188bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 13198bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1320a580d820SCédric Le Goater RspBuffer *rsp) 13218bfffbccSCorey Minyard { 1322a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1323a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 13248bfffbccSCorey Minyard } 13258bfffbccSCorey Minyard 13268bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 13278bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1328a580d820SCédric Le Goater RspBuffer *rsp) 13298bfffbccSCorey Minyard { 13308bfffbccSCorey Minyard unsigned int val; 13318bfffbccSCorey Minyard 13328bfffbccSCorey Minyard if (cmd[6]) { 1333*7f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 1334*7f996411SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION; 1335*7f996411SCédric Le Goater return; 1336*7f996411SCédric Le Goater } 13378bfffbccSCorey Minyard } 13388bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 1339a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1340d13ada5dSCédric Le Goater return; 13418bfffbccSCorey Minyard } 13428bfffbccSCorey Minyard if (cmd[6] > 15) { 1343a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1344d13ada5dSCédric Le Goater return; 13458bfffbccSCorey Minyard } 13468bfffbccSCorey Minyard if (cmd[7] == 0xff) { 13478bfffbccSCorey Minyard cmd[7] = 16; 13488bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 1349a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1350d13ada5dSCédric Le Goater return; 13518bfffbccSCorey Minyard } else { 13528bfffbccSCorey Minyard cmd[7] += cmd[6]; 13538bfffbccSCorey Minyard } 13548bfffbccSCorey Minyard 13558bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 13568bfffbccSCorey Minyard if (val == 0xffff) { 13578bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 13588bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 1359a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1360d13ada5dSCédric Le Goater return; 13618bfffbccSCorey Minyard } 13628bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1363a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1364a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 13658bfffbccSCorey Minyard } else { 1366a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1367a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 13688bfffbccSCorey Minyard } 13698bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1370a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 13718bfffbccSCorey Minyard } 13728bfffbccSCorey Minyard } 13738bfffbccSCorey Minyard 13748bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 13758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1376a580d820SCédric Le Goater RspBuffer *rsp) 13778bfffbccSCorey Minyard { 13788bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 1379a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_OUT_OF_SPACE; 1380d13ada5dSCédric Le Goater return; 13818bfffbccSCorey Minyard } 13828bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1383a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1384a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 13858bfffbccSCorey Minyard } 13868bfffbccSCorey Minyard 13878bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 13888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1389a580d820SCédric Le Goater RspBuffer *rsp) 13908bfffbccSCorey Minyard { 1391*7f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 1392*7f996411SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_RESERVATION; 1393*7f996411SCédric Le Goater return; 1394*7f996411SCédric Le Goater } 1395*7f996411SCédric Le Goater 13968bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 1397a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1398d13ada5dSCédric Le Goater return; 13998bfffbccSCorey Minyard } 14008bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 14018bfffbccSCorey Minyard ibs->sel.next_free = 0; 14028bfffbccSCorey Minyard ibs->sel.overflow = 0; 14038bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1404a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14058bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 14068bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1407a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14088bfffbccSCorey Minyard } else { 1409a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 14108bfffbccSCorey Minyard return; 14118bfffbccSCorey Minyard } 1412d13ada5dSCédric Le Goater } 14138bfffbccSCorey Minyard 14148bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 14158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1416a580d820SCédric Le Goater RspBuffer *rsp) 14178bfffbccSCorey Minyard { 14188bfffbccSCorey Minyard uint32_t val; 14198bfffbccSCorey Minyard struct ipmi_time now; 14208bfffbccSCorey Minyard 14218bfffbccSCorey Minyard ipmi_gettime(&now); 14228bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1423a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1424a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1425a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1426a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 14278bfffbccSCorey Minyard } 14288bfffbccSCorey Minyard 14298bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 14308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1431a580d820SCédric Le Goater RspBuffer *rsp) 14328bfffbccSCorey Minyard { 14338bfffbccSCorey Minyard uint32_t val; 14348bfffbccSCorey Minyard struct ipmi_time now; 14358bfffbccSCorey Minyard 14368bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 14378bfffbccSCorey Minyard ipmi_gettime(&now); 14388bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 14398bfffbccSCorey Minyard } 14408bfffbccSCorey Minyard 14418bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 14428bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1443a580d820SCédric Le Goater RspBuffer *rsp) 14448bfffbccSCorey Minyard { 14458bfffbccSCorey Minyard IPMISensor *sens; 14468bfffbccSCorey Minyard 144773d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 14488bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1449a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1450d13ada5dSCédric Le Goater return; 14518bfffbccSCorey Minyard } 14528bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14538bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 14548bfffbccSCorey Minyard case 0: /* Do not change */ 14558bfffbccSCorey Minyard break; 14568bfffbccSCorey Minyard case 1: /* Enable bits */ 14578bfffbccSCorey Minyard if (cmd_len > 4) { 14588bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 14598bfffbccSCorey Minyard } 14608bfffbccSCorey Minyard if (cmd_len > 5) { 14618bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 14628bfffbccSCorey Minyard } 14638bfffbccSCorey Minyard if (cmd_len > 6) { 14648bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 14658bfffbccSCorey Minyard } 14668bfffbccSCorey Minyard if (cmd_len > 7) { 14678bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 14688bfffbccSCorey Minyard } 14698bfffbccSCorey Minyard break; 14708bfffbccSCorey Minyard case 2: /* Disable bits */ 14718bfffbccSCorey Minyard if (cmd_len > 4) { 14728bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 14738bfffbccSCorey Minyard } 14748bfffbccSCorey Minyard if (cmd_len > 5) { 14758bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 14768bfffbccSCorey Minyard } 14778bfffbccSCorey Minyard if (cmd_len > 6) { 14788bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 14798bfffbccSCorey Minyard } 14808bfffbccSCorey Minyard if (cmd_len > 7) { 14818bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 14828bfffbccSCorey Minyard } 14838bfffbccSCorey Minyard break; 14848bfffbccSCorey Minyard case 3: 1485a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_INVALID_DATA_FIELD; 1486d13ada5dSCédric Le Goater return; 14878bfffbccSCorey Minyard } 14888bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 14898bfffbccSCorey Minyard } 14908bfffbccSCorey Minyard 14918bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 14928bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1493a580d820SCédric Le Goater RspBuffer *rsp) 14948bfffbccSCorey Minyard { 14958bfffbccSCorey Minyard IPMISensor *sens; 14968bfffbccSCorey Minyard 149773d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 14988bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1499a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1500d13ada5dSCédric Le Goater return; 15018bfffbccSCorey Minyard } 15028bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1503a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1504a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1505a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1506a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1507a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 15088bfffbccSCorey Minyard } 15098bfffbccSCorey Minyard 15108bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 15118bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1512a580d820SCédric Le Goater RspBuffer *rsp) 15138bfffbccSCorey Minyard { 15148bfffbccSCorey Minyard IPMISensor *sens; 15158bfffbccSCorey Minyard 151673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15178bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1518a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1519d13ada5dSCédric Le Goater return; 15208bfffbccSCorey Minyard } 15218bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15228bfffbccSCorey Minyard 15238bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 15248bfffbccSCorey Minyard /* Just clear everything */ 15258bfffbccSCorey Minyard sens->states = 0; 15268bfffbccSCorey Minyard return; 15278bfffbccSCorey Minyard } 1528d13ada5dSCédric Le Goater } 15298bfffbccSCorey Minyard 15308bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 15318bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1532a580d820SCédric Le Goater RspBuffer *rsp) 15338bfffbccSCorey Minyard { 15348bfffbccSCorey Minyard IPMISensor *sens; 15358bfffbccSCorey Minyard 153673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15378bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1538a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1539d13ada5dSCédric Le Goater return; 15408bfffbccSCorey Minyard } 15418bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1542a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1543a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1544a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1545a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1546a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1547a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 15488bfffbccSCorey Minyard } 15498bfffbccSCorey Minyard 15508bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 15518bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1552a580d820SCédric Le Goater RspBuffer *rsp) 15538bfffbccSCorey Minyard { 15548bfffbccSCorey Minyard IPMISensor *sens; 15558bfffbccSCorey Minyard 155673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15578bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1558a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1559d13ada5dSCédric Le Goater return; 15608bfffbccSCorey Minyard } 15618bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1562a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1563a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1564a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 15658bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1566a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 15678bfffbccSCorey Minyard } 15688bfffbccSCorey Minyard } 15698bfffbccSCorey Minyard 1570728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1571728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1572a580d820SCédric Le Goater RspBuffer *rsp) 1573728710e1SCédric Le Goater { 1574728710e1SCédric Le Goater IPMISensor *sens; 1575728710e1SCédric Le Goater 1576728710e1SCédric Le Goater 157773d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1578728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1579a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1580728710e1SCédric Le Goater return; 1581728710e1SCédric Le Goater } 1582728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1583728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1584728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1585728710e1SCédric Le Goater } 1586728710e1SCédric Le Goater 1587728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1588728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1589a580d820SCédric Le Goater RspBuffer *rsp) 1590728710e1SCédric Le Goater { 1591728710e1SCédric Le Goater IPMISensor *sens; 1592728710e1SCédric Le Goater 1593728710e1SCédric Le Goater 159473d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1595728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1596a580d820SCédric Le Goater rsp->buffer[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1597728710e1SCédric Le Goater return; 1598728710e1SCédric Le Goater } 1599728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1600a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1601a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1602728710e1SCédric Le Goater } 1603728710e1SCédric Le Goater 1604728710e1SCédric Le Goater 160562a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 16064f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 16074f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 16084f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 16094f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 16108bfffbccSCorey Minyard }; 16118bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 161262a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 16138bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 16148bfffbccSCorey Minyard }; 16158bfffbccSCorey Minyard 161662a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 16174f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 16184f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 16194f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 16204f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 16214f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 16224f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 16234f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 16248bfffbccSCorey Minyard }; 16258bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 162662a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 16278bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 16288bfffbccSCorey Minyard }; 16298bfffbccSCorey Minyard 163062a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 16314f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 16324f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 16334f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 16344f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 16354f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 16364f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 16374f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 16384f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 16394f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 16404f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 16414f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 16424f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 16434f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 16444f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 16454f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 16464f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 16478bfffbccSCorey Minyard }; 16488bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 164962a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 16508bfffbccSCorey Minyard .cmd_handlers = app_cmds 16518bfffbccSCorey Minyard }; 16528bfffbccSCorey Minyard 165362a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 16544f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 16554f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 16564f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 16574f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 16584f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 16594f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 16604f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 16614f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 16624f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 16634f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 16644f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 }, 16654f298a4bSCédric Le Goater [IPMI_CMD_SET_SEL_TIME] = { set_sel_time }, 16668bfffbccSCorey Minyard }; 16678bfffbccSCorey Minyard 16688bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 166962a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 16708bfffbccSCorey Minyard .cmd_handlers = storage_cmds 16718bfffbccSCorey Minyard }; 16728bfffbccSCorey Minyard 16738bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 16748bfffbccSCorey Minyard { 16758bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 16768bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 16778bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 16788bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 16798bfffbccSCorey Minyard } 16808bfffbccSCorey Minyard 16818bfffbccSCorey Minyard static const uint8_t init_sdrs[] = { 16828bfffbccSCorey Minyard /* Watchdog device */ 16838bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 16848bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 16858bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16868bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 16878bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 16888bfffbccSCorey Minyard /* End */ 16898bfffbccSCorey Minyard 0xff, 0xff, 0x00, 0x00, 0x00 16908bfffbccSCorey Minyard }; 16918bfffbccSCorey Minyard 1692bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1693bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1694bd66bcfcSCorey Minyard .version_id = 1, 1695bd66bcfcSCorey Minyard .minimum_version_id = 1, 1696bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1697bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1698bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1699bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1700bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1701bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1702bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1703bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1704bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1705bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1706bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1707bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1708bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1709bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1710bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1711bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1712bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1713bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1714bd66bcfcSCorey Minyard IPMIBmcSim), 1715bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1716bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1717bd66bcfcSCorey Minyard } 1718bd66bcfcSCorey Minyard }; 1719bd66bcfcSCorey Minyard 17208bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj) 17218bfffbccSCorey Minyard { 17228bfffbccSCorey Minyard IPMIBmc *b = IPMI_BMC(obj); 17238bfffbccSCorey Minyard unsigned int i; 17248bfffbccSCorey Minyard unsigned int recid; 17258bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 17268bfffbccSCorey Minyard 17278bfffbccSCorey Minyard qemu_mutex_init(&ibs->lock); 17288bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 17298bfffbccSCorey Minyard 17308bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 17318bfffbccSCorey Minyard ibs->device_id = 0x20; 17328bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1733b7088392SCédric Le Goater ibs->restart_cause = 0; 17348bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 17358bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 17368bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 17378bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 17388bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 17398bfffbccSCorey Minyard } 17408bfffbccSCorey Minyard 17418bfffbccSCorey Minyard for (i = 0;;) { 1742a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 17438bfffbccSCorey Minyard int len; 1744a2295f0aSCédric Le Goater if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) { 17457cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 17468bfffbccSCorey Minyard return; 17478bfffbccSCorey Minyard } 1748a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &init_sdrs[i]; 1749a2295f0aSCédric Le Goater len = ipmi_sdr_length(sdrh); 1750a2295f0aSCédric Le Goater recid = ipmi_sdr_recid(sdrh); 17518bfffbccSCorey Minyard if (recid == 0xffff) { 17528bfffbccSCorey Minyard break; 17538bfffbccSCorey Minyard } 1754792afddbSCédric Le Goater if ((i + len) > sizeof(init_sdrs)) { 17557cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 17568bfffbccSCorey Minyard return; 17578bfffbccSCorey Minyard } 1758a2295f0aSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 1759792afddbSCédric Le Goater i += len; 17608bfffbccSCorey Minyard } 17618bfffbccSCorey Minyard 176252ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 176352ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 176452ba4d50SCédric Le Goater 176552ba4d50SCédric Le Goater if (qemu_uuid_set) { 176652ba4d50SCédric Le Goater memcpy(&ibs->uuid, qemu_uuid, 16); 176752ba4d50SCédric Le Goater } else { 176852ba4d50SCédric Le Goater memset(&ibs->uuid, 0, 16); 176952ba4d50SCédric Le Goater } 177052ba4d50SCédric Le Goater 17718bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 17728bfffbccSCorey Minyard register_cmds(ibs); 17738bfffbccSCorey Minyard 17748bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1775bd66bcfcSCorey Minyard 1776bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 17778bfffbccSCorey Minyard } 17788bfffbccSCorey Minyard 17798bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 17808bfffbccSCorey Minyard { 17818bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 17828bfffbccSCorey Minyard 17838bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 17848bfffbccSCorey Minyard } 17858bfffbccSCorey Minyard 17868bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 17878bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 17888bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 17898bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 17908bfffbccSCorey Minyard .instance_init = ipmi_sim_init, 17918bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 17928bfffbccSCorey Minyard }; 17938bfffbccSCorey Minyard 17948bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 17958bfffbccSCorey Minyard { 17968bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 17978bfffbccSCorey Minyard } 17988bfffbccSCorey Minyard 17998bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1800