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 2736acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte) 2746acb971aSCédric Le Goater { 2756acb971aSCédric Le Goater rsp->buffer[2] = byte; 2766acb971aSCédric Le Goater } 2776acb971aSCédric Le Goater 2788bfffbccSCorey Minyard /* Add a byte to the response. */ 279a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte) 280a580d820SCédric Le Goater { 281a580d820SCédric Le Goater if (rsp->len >= sizeof(rsp->buffer)) { 2826acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 283a580d820SCédric Le Goater return; 284a580d820SCédric Le Goater } 285a580d820SCédric Le Goater rsp->buffer[rsp->len++] = byte; 286a580d820SCédric Le Goater } 287a580d820SCédric Le Goater 288a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes, 289a580d820SCédric Le Goater unsigned int n) 290a580d820SCédric Le Goater { 291a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) { 2926acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 293a580d820SCédric Le Goater return; 294a580d820SCédric Le Goater } 295a580d820SCédric Le Goater 296a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n); 297a580d820SCédric Le Goater rsp->len += n; 298a580d820SCédric Le Goater } 2998bfffbccSCorey Minyard 3008bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 3018bfffbccSCorey Minyard 3028bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 3038bfffbccSCorey Minyard { 3048bfffbccSCorey Minyard int64_t stime; 3058bfffbccSCorey Minyard 3068bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 3078bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 3088bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 3098bfffbccSCorey Minyard } 3108bfffbccSCorey Minyard 3118bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 3128bfffbccSCorey Minyard { 3138bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3148bfffbccSCorey Minyard } 3158bfffbccSCorey Minyard 3168bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 3178bfffbccSCorey Minyard { 3188bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3198bfffbccSCorey Minyard 3208bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3218bfffbccSCorey Minyard } 3228bfffbccSCorey Minyard 3238bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3248bfffbccSCorey Minyard { 3258bfffbccSCorey Minyard unsigned int val; 3268bfffbccSCorey Minyard struct ipmi_time now; 3278bfffbccSCorey Minyard 3288bfffbccSCorey Minyard ipmi_gettime(&now); 3298bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3308bfffbccSCorey Minyard ts[0] = val & 0xff; 3318bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3328bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3338bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3348bfffbccSCorey Minyard } 3358bfffbccSCorey Minyard 3368bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3378bfffbccSCorey Minyard { 3388bfffbccSCorey Minyard sdr->reservation++; 3398bfffbccSCorey Minyard if (sdr->reservation == 0) { 3408bfffbccSCorey Minyard sdr->reservation = 1; 3418bfffbccSCorey Minyard } 3428bfffbccSCorey Minyard } 3438bfffbccSCorey Minyard 344a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 345a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3468bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3478bfffbccSCorey Minyard { 348a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 349a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 350a2295f0aSCédric Le Goater 351a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3528bfffbccSCorey Minyard return 1; 3538bfffbccSCorey Minyard } 3548bfffbccSCorey Minyard 355a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3568bfffbccSCorey Minyard return 1; 3578bfffbccSCorey Minyard } 3588bfffbccSCorey Minyard 3598bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3608bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3618bfffbccSCorey Minyard return 1; 3628bfffbccSCorey Minyard } 3638bfffbccSCorey Minyard 364a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 365a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 366a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 367a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3688bfffbccSCorey Minyard 3698bfffbccSCorey Minyard if (recid) { 3708bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3718bfffbccSCorey Minyard } 3728bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3738bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3748bfffbccSCorey Minyard ibs->sdr.next_free += len; 3758bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3768bfffbccSCorey Minyard return 0; 3778bfffbccSCorey Minyard } 3788bfffbccSCorey Minyard 3798bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3808bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3818bfffbccSCorey Minyard { 3828bfffbccSCorey Minyard unsigned int pos = *retpos; 3838bfffbccSCorey Minyard 3848bfffbccSCorey Minyard while (pos < sdr->next_free) { 385a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 386a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 387a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 388a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 3898bfffbccSCorey Minyard 3908bfffbccSCorey Minyard if (trec == recid) { 3918bfffbccSCorey Minyard if (nextrec) { 3928bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3938bfffbccSCorey Minyard *nextrec = 0xffff; 3948bfffbccSCorey Minyard } else { 3958bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3968bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3978bfffbccSCorey Minyard } 3988bfffbccSCorey Minyard } 3998bfffbccSCorey Minyard *retpos = pos; 4008bfffbccSCorey Minyard return 0; 4018bfffbccSCorey Minyard } 4028bfffbccSCorey Minyard pos = nextpos; 4038bfffbccSCorey Minyard } 4048bfffbccSCorey Minyard return 1; 4058bfffbccSCorey Minyard } 4068bfffbccSCorey Minyard 4078bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 4088bfffbccSCorey Minyard { 4098bfffbccSCorey Minyard sel->reservation++; 4108bfffbccSCorey Minyard if (sel->reservation == 0) { 4118bfffbccSCorey Minyard sel->reservation = 1; 4128bfffbccSCorey Minyard } 4138bfffbccSCorey Minyard } 4148bfffbccSCorey Minyard 4158bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4168bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4178bfffbccSCorey Minyard { 4188bfffbccSCorey Minyard event[0] = 0xff; 4198bfffbccSCorey Minyard event[1] = 0xff; 4208bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 4218bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4228bfffbccSCorey Minyard ibs->sel.overflow = 1; 4238bfffbccSCorey Minyard return 1; 4248bfffbccSCorey Minyard } 4258bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4268bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4278bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 4288bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4298bfffbccSCorey Minyard ibs->sel.next_free++; 4308bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4318bfffbccSCorey Minyard return 0; 4328bfffbccSCorey Minyard } 4338bfffbccSCorey Minyard 4348bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4358bfffbccSCorey Minyard { 4368bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4378bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4388bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4398bfffbccSCorey Minyard } 4408bfffbccSCorey Minyard 4418bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4428bfffbccSCorey Minyard { 4438bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4448bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4458bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4468bfffbccSCorey Minyard } 4478bfffbccSCorey Minyard 4488bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4498bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4508bfffbccSCorey Minyard { 4518bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4528bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4538bfffbccSCorey Minyard uint8_t evt[16]; 4548bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4558bfffbccSCorey Minyard 4568bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4578bfffbccSCorey Minyard return; 4588bfffbccSCorey Minyard } 4598bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4608bfffbccSCorey Minyard return; 4618bfffbccSCorey Minyard } 4628bfffbccSCorey Minyard 4638bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4648bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4658bfffbccSCorey Minyard evt[8] = 0; 4668bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4678bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4688bfffbccSCorey Minyard evt[11] = sens_num; 4698bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4708bfffbccSCorey Minyard evt[13] = evd1; 4718bfffbccSCorey Minyard evt[14] = evd2; 4728bfffbccSCorey Minyard evt[15] = evd3; 4738bfffbccSCorey Minyard 4748bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 4758bfffbccSCorey Minyard sel_add_event(ibs, evt); 4768bfffbccSCorey Minyard } 4778bfffbccSCorey Minyard 4788bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 479d13ada5dSCédric Le Goater return; 4808bfffbccSCorey Minyard } 4818bfffbccSCorey Minyard 4828bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 4838bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 4848bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 4858bfffbccSCorey Minyard } 4868bfffbccSCorey Minyard 4878bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 4888bfffbccSCorey Minyard unsigned int bit, unsigned int val, 4898bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4908bfffbccSCorey Minyard { 4918bfffbccSCorey Minyard IPMISensor *sens; 4928bfffbccSCorey Minyard uint16_t mask; 4938bfffbccSCorey Minyard 4948bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 4958bfffbccSCorey Minyard return; 4968bfffbccSCorey Minyard } 4978bfffbccSCorey Minyard if (bit >= 16) { 4988bfffbccSCorey Minyard return; 4998bfffbccSCorey Minyard } 5008bfffbccSCorey Minyard 5018bfffbccSCorey Minyard mask = (1 << bit); 5028bfffbccSCorey Minyard sens = ibs->sensors + sensor; 5038bfffbccSCorey Minyard if (val) { 5048bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5058bfffbccSCorey Minyard if (sens->assert_states & mask) { 5068bfffbccSCorey Minyard return; /* Already asserted */ 5078bfffbccSCorey Minyard } 5088bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 5098bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 5108bfffbccSCorey Minyard /* Send an event on assert */ 5118bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5128bfffbccSCorey Minyard } 5138bfffbccSCorey Minyard } else { 5148bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5158bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5168bfffbccSCorey Minyard return; /* Already deasserted */ 5178bfffbccSCorey Minyard } 5188bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5198bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5208bfffbccSCorey Minyard /* Send an event on deassert */ 5218bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5228bfffbccSCorey Minyard } 5238bfffbccSCorey Minyard } 5248bfffbccSCorey Minyard } 5258bfffbccSCorey Minyard 5268bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5278bfffbccSCorey Minyard { 5288bfffbccSCorey Minyard unsigned int i, pos; 5298bfffbccSCorey Minyard IPMISensor *sens; 5308bfffbccSCorey Minyard 5318bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5328bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5338bfffbccSCorey Minyard } 5348bfffbccSCorey Minyard 5358bfffbccSCorey Minyard pos = 0; 5368bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 537a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 538a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 539a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5408bfffbccSCorey Minyard 5418bfffbccSCorey Minyard if (len < 20) { 5428bfffbccSCorey Minyard continue; 5438bfffbccSCorey Minyard } 544a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5458bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5468bfffbccSCorey Minyard } 5478bfffbccSCorey Minyard 54873d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 5498bfffbccSCorey Minyard continue; 5508bfffbccSCorey Minyard } 551a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5528bfffbccSCorey Minyard 5538bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 554a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 555a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 556a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 557a2295f0aSCédric Le Goater sens->deassert_suppt = 558a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 559a2295f0aSCédric Le Goater sens->states_suppt = 560a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 561a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 562a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5638bfffbccSCorey Minyard 5648bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5658bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5668bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5678bfffbccSCorey Minyard } 5688bfffbccSCorey Minyard } 5698bfffbccSCorey Minyard 5708bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5718bfffbccSCorey Minyard const IPMINetfn *netfnd) 5728bfffbccSCorey Minyard { 57393a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 5748bfffbccSCorey Minyard return -1; 5758bfffbccSCorey Minyard } 5768bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 5778bfffbccSCorey Minyard return 0; 5788bfffbccSCorey Minyard } 5798bfffbccSCorey Minyard 5804f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 5814f298a4bSCédric Le Goater unsigned int netfn, 5824f298a4bSCédric Le Goater unsigned int cmd) 5834f298a4bSCédric Le Goater { 5844f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 5854f298a4bSCédric Le Goater 5864f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 5874f298a4bSCédric Le Goater return NULL; 5884f298a4bSCédric Le Goater } 5894f298a4bSCédric Le Goater 5904f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 5914f298a4bSCédric Le Goater return NULL; 5924f298a4bSCédric Le Goater } 5934f298a4bSCédric Le Goater 5944f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 5954f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 5964f298a4bSCédric Le Goater return NULL; 5974f298a4bSCédric Le Goater } 5984f298a4bSCédric Le Goater 5994f298a4bSCédric Le Goater return hdl; 6004f298a4bSCédric Le Goater } 6014f298a4bSCédric Le Goater 6028bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 6038bfffbccSCorey Minyard { 6048bfffbccSCorey Minyard int64_t next; 6058bfffbccSCorey Minyard if (ibs->watchdog_running) { 6068bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6078bfffbccSCorey Minyard } else { 6088bfffbccSCorey Minyard /* Wait a minute */ 6098bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6108bfffbccSCorey Minyard } 6118bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6128bfffbccSCorey Minyard } 6138bfffbccSCorey Minyard 6148bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6168bfffbccSCorey Minyard unsigned int max_cmd_len, 6178bfffbccSCorey Minyard uint8_t msg_id) 6188bfffbccSCorey Minyard { 6198bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6208bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6218bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6224f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 623a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6248bfffbccSCorey Minyard 6258bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6268bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 627a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 6286acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 629d13ada5dSCédric Le Goater goto out; 630d13ada5dSCédric Le Goater } 631d13ada5dSCédric Le Goater 632a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 633a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 634a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6358bfffbccSCorey Minyard 6368bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6378bfffbccSCorey Minyard if (cmd_len < 2) { 6386acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6398bfffbccSCorey Minyard goto out; 6408bfffbccSCorey Minyard } 6418bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6426acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 6438bfffbccSCorey Minyard goto out; 6448bfffbccSCorey Minyard } 6458bfffbccSCorey Minyard 6468bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6478bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 6486acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN); 6498bfffbccSCorey Minyard goto out; 6508bfffbccSCorey Minyard } 6518bfffbccSCorey Minyard 6524f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 6534f298a4bSCédric Le Goater if (!hdl) { 6546acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD); 6558bfffbccSCorey Minyard goto out; 6568bfffbccSCorey Minyard } 6578bfffbccSCorey Minyard 6584f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 6596acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6604f298a4bSCédric Le Goater goto out; 6614f298a4bSCédric Le Goater } 6624f298a4bSCédric Le Goater 663a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 6648bfffbccSCorey Minyard 6658bfffbccSCorey Minyard out: 666a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 6678bfffbccSCorey Minyard 6688bfffbccSCorey Minyard next_timeout(ibs); 6698bfffbccSCorey Minyard } 6708bfffbccSCorey Minyard 6718bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 6728bfffbccSCorey Minyard { 6738bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6748bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6758bfffbccSCorey Minyard 6768bfffbccSCorey Minyard if (!ibs->watchdog_running) { 6778bfffbccSCorey Minyard goto out; 6788bfffbccSCorey Minyard } 6798bfffbccSCorey Minyard 6808bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 6818bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 6828bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 6838bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6848bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 6858bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6868bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 6878bfffbccSCorey Minyard break; 6888bfffbccSCorey Minyard 6898bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 6908bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6918bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 6928bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6938bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 6948bfffbccSCorey Minyard break; 6958bfffbccSCorey Minyard 6968bfffbccSCorey Minyard default: 6978bfffbccSCorey Minyard goto do_full_expiry; 6988bfffbccSCorey Minyard } 6998bfffbccSCorey Minyard 7008bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 7018bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 7028bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 7038bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 7048bfffbccSCorey Minyard goto out; 7058bfffbccSCorey Minyard } 7068bfffbccSCorey Minyard 7078bfffbccSCorey Minyard do_full_expiry: 7088bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7098bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7108bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7118bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7128bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 7138bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 7148bfffbccSCorey Minyard break; 7158bfffbccSCorey Minyard 7168bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7178bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 7188bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 7198bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7208bfffbccSCorey Minyard break; 7218bfffbccSCorey Minyard 7228bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7238bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7248bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 7258bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7268bfffbccSCorey Minyard break; 7278bfffbccSCorey Minyard 7288bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7298bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7308bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7318bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7328bfffbccSCorey Minyard break; 7338bfffbccSCorey Minyard } 7348bfffbccSCorey Minyard 7358bfffbccSCorey Minyard out: 7368bfffbccSCorey Minyard next_timeout(ibs); 7378bfffbccSCorey Minyard } 7388bfffbccSCorey Minyard 7398bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7408bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 741a580d820SCédric Le Goater RspBuffer *rsp) 7428bfffbccSCorey Minyard { 743a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 744a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 745a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 746a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 747a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 7488bfffbccSCorey Minyard } 7498bfffbccSCorey Minyard 7508bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7518bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 752a580d820SCédric Le Goater RspBuffer *rsp) 7538bfffbccSCorey Minyard { 754a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 755a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 756a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 757a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 7588bfffbccSCorey Minyard } 7598bfffbccSCorey Minyard 7608bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 762a580d820SCédric Le Goater RspBuffer *rsp) 7638bfffbccSCorey Minyard { 7648bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7658bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7668bfffbccSCorey Minyard 7678bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7688bfffbccSCorey Minyard case 0: /* power down */ 7696acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0)); 7708bfffbccSCorey Minyard break; 7718bfffbccSCorey Minyard case 1: /* power up */ 7726acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0)); 7738bfffbccSCorey Minyard break; 7748bfffbccSCorey Minyard case 2: /* power cycle */ 7756acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0)); 7768bfffbccSCorey Minyard break; 7778bfffbccSCorey Minyard case 3: /* hard reset */ 7786acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0)); 7798bfffbccSCorey Minyard break; 7808bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 7816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0)); 7828bfffbccSCorey Minyard break; 7838bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 7846acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, 7856acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0)); 7868bfffbccSCorey Minyard break; 7878bfffbccSCorey Minyard default: 7886acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 7898bfffbccSCorey Minyard return; 7908bfffbccSCorey Minyard } 791d13ada5dSCédric Le Goater } 7928bfffbccSCorey Minyard 793b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 794b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 795a580d820SCédric Le Goater RspBuffer *rsp) 796a580d820SCédric Le Goater 797b7088392SCédric Le Goater { 798a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 799a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 800b7088392SCédric Le Goater } 801b7088392SCédric Le Goater 8028bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 8038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 804a580d820SCédric Le Goater RspBuffer *rsp) 8058bfffbccSCorey Minyard { 806a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 807a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 808a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 809a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 810a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 811a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 812a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[0]); 813a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[1]); 814a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[2]); 815a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[0]); 816a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[1]); 8178bfffbccSCorey Minyard } 8188bfffbccSCorey Minyard 8198bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8208bfffbccSCorey Minyard { 8218bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8228bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8238bfffbccSCorey Minyard bool irqs_on; 8248bfffbccSCorey Minyard 8258bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8268bfffbccSCorey Minyard 8278bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8288bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8298bfffbccSCorey Minyard 8308bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8318bfffbccSCorey Minyard } 8328bfffbccSCorey Minyard 8338bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8348bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 835a580d820SCédric Le Goater RspBuffer *rsp) 8368bfffbccSCorey Minyard { 8378bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8388bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8398bfffbccSCorey Minyard 8408bfffbccSCorey Minyard /* Disable all interrupts */ 8418bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8428bfffbccSCorey Minyard 8438bfffbccSCorey Minyard if (k->reset) { 8448bfffbccSCorey Minyard k->reset(s, true); 8458bfffbccSCorey Minyard } 8468bfffbccSCorey Minyard } 8478bfffbccSCorey Minyard 8488bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8498bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 850a580d820SCédric Le Goater RspBuffer *rsp) 8518bfffbccSCorey Minyard { 8528bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8538bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8548bfffbccSCorey Minyard 8558bfffbccSCorey Minyard if (k->reset) { 8568bfffbccSCorey Minyard k->reset(s, false); 8578bfffbccSCorey Minyard } 8588bfffbccSCorey Minyard } 85952ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 86052ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 861a580d820SCédric Le Goater RspBuffer *rsp) 86252ba4d50SCédric Le Goater { 86352ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 86452ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 86552ba4d50SCédric Le Goater } 86652ba4d50SCédric Le Goater 86752ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 86852ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 869a580d820SCédric Le Goater RspBuffer *rsp) 87052ba4d50SCédric Le Goater { 871a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 872a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 87352ba4d50SCédric Le Goater } 87452ba4d50SCédric Le Goater 87552ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 87652ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 877a580d820SCédric Le Goater RspBuffer *rsp) 87852ba4d50SCédric Le Goater { 87952ba4d50SCédric Le Goater unsigned int i; 88052ba4d50SCédric Le Goater 88152ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 882a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->uuid[i]); 88352ba4d50SCédric Le Goater } 88452ba4d50SCédric Le Goater } 8858bfffbccSCorey Minyard 8868bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 8878bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 888a580d820SCédric Le Goater RspBuffer *rsp) 8898bfffbccSCorey Minyard { 8908bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 8918bfffbccSCorey Minyard } 8928bfffbccSCorey Minyard 8938bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 8948bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 895a580d820SCédric Le Goater RspBuffer *rsp) 8968bfffbccSCorey Minyard { 897a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 8988bfffbccSCorey Minyard } 8998bfffbccSCorey Minyard 9008bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 9018bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 902a580d820SCédric Le Goater RspBuffer *rsp) 9038bfffbccSCorey Minyard { 9048bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9058bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9068bfffbccSCorey Minyard 9078bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9088bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9098bfffbccSCorey Minyard } 9108bfffbccSCorey Minyard 9118bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 913a580d820SCédric Le Goater RspBuffer *rsp) 9148bfffbccSCorey Minyard { 915a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9168bfffbccSCorey Minyard } 9178bfffbccSCorey Minyard 9188bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9198bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 920a580d820SCédric Le Goater RspBuffer *rsp) 9218bfffbccSCorey Minyard { 9228bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9238bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9248bfffbccSCorey Minyard unsigned int i; 9258bfffbccSCorey Minyard 9268bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 9276acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 928d13ada5dSCédric Le Goater return; 9298bfffbccSCorey Minyard } 9308bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 931a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 9328bfffbccSCorey Minyard } 9338bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9348bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9358bfffbccSCorey Minyard } 9368bfffbccSCorey Minyard 9378bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9388bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 939a580d820SCédric Le Goater RspBuffer *rsp) 9408bfffbccSCorey Minyard { 9418bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9428bfffbccSCorey Minyard 9438bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 9448bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9456acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ 9468bfffbccSCorey Minyard goto out; 9478bfffbccSCorey Minyard } 948a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 9498bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 950a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 9518bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9528bfffbccSCorey Minyard g_free(msg); 9538bfffbccSCorey Minyard 9548bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9558bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9568bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9578bfffbccSCorey Minyard 9588bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9598bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9608bfffbccSCorey Minyard } 9618bfffbccSCorey Minyard 9628bfffbccSCorey Minyard out: 9638bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 9648bfffbccSCorey Minyard return; 9658bfffbccSCorey Minyard } 9668bfffbccSCorey Minyard 9678bfffbccSCorey Minyard static unsigned char 9688bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 9698bfffbccSCorey Minyard { 9708bfffbccSCorey Minyard for (; size > 0; size--, data++) { 9718bfffbccSCorey Minyard csum += *data; 9728bfffbccSCorey Minyard } 9738bfffbccSCorey Minyard 9748bfffbccSCorey Minyard return -csum; 9758bfffbccSCorey Minyard } 9768bfffbccSCorey Minyard 9778bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 9788bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 979a580d820SCédric Le Goater RspBuffer *rsp) 9808bfffbccSCorey Minyard { 9818bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9828bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9838bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9848bfffbccSCorey Minyard uint8_t *buf; 9858bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 9868bfffbccSCorey Minyard 9878bfffbccSCorey Minyard if (cmd[2] != 0) { 9888bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 9896acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 990d13ada5dSCédric Le Goater return; 9918bfffbccSCorey Minyard } 9928bfffbccSCorey Minyard 9934f298a4bSCédric Le Goater if (cmd_len < 10) { 9946acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 9954f298a4bSCédric Le Goater return; 9964f298a4bSCédric Le Goater } 9974f298a4bSCédric Le Goater 9988bfffbccSCorey Minyard if (cmd[3] != 0x40) { 9998bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 10006acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */ 1001d13ada5dSCédric Le Goater return; 10028bfffbccSCorey Minyard } 10038bfffbccSCorey Minyard 10048bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10058bfffbccSCorey Minyard cmd_len -= 3; 10068bfffbccSCorey Minyard 10078bfffbccSCorey Minyard /* 10088bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10098bfffbccSCorey Minyard * be returned in the response. 10108bfffbccSCorey Minyard */ 10118bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10128bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1013d13ada5dSCédric Le Goater return; /* No response */ 10148bfffbccSCorey Minyard } 10158bfffbccSCorey Minyard 10168bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10178bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10188bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10198bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10208bfffbccSCorey Minyard 10218bfffbccSCorey Minyard if (rqLun != 2) { 10228bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1023d13ada5dSCédric Le Goater return; 10248bfffbccSCorey Minyard } 10258bfffbccSCorey Minyard 10268bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10278bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10288bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10298bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10308bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10318bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10328bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10338bfffbccSCorey Minyard msg->len = 6; 10348bfffbccSCorey Minyard 10358bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10368bfffbccSCorey Minyard /* Not a command we handle. */ 10378bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10388bfffbccSCorey Minyard goto end_msg; 10398bfffbccSCorey Minyard } 10408bfffbccSCorey Minyard 10418bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10428bfffbccSCorey Minyard buf[0] = 0; 10438bfffbccSCorey Minyard buf[1] = 0; 10448bfffbccSCorey Minyard buf[2] = 0; 10458bfffbccSCorey Minyard buf[3] = 0; 10468bfffbccSCorey Minyard buf[4] = 0x51; 10478bfffbccSCorey Minyard buf[5] = 0; 10488bfffbccSCorey Minyard buf[6] = 0; 10498bfffbccSCorey Minyard buf[7] = 0; 10508bfffbccSCorey Minyard buf[8] = 0; 10518bfffbccSCorey Minyard buf[9] = 0; 10528bfffbccSCorey Minyard buf[10] = 0; 10538bfffbccSCorey Minyard msg->len += 11; 10548bfffbccSCorey Minyard 10558bfffbccSCorey Minyard end_msg: 10568bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 10578bfffbccSCorey Minyard msg->len++; 10588bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 10598bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 10608bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10618bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 10628bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 10638bfffbccSCorey Minyard } 10648bfffbccSCorey Minyard 10658bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 10668bfffbccSCorey Minyard { 10678bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 10688bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 10698bfffbccSCorey Minyard ibs->watchdog_running = 0; 10708bfffbccSCorey Minyard return; 10718bfffbccSCorey Minyard } 10728bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 10738bfffbccSCorey Minyard 10748bfffbccSCorey Minyard 10758bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 10768bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 10778bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 10788bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 10798bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 10808bfffbccSCorey Minyard } 10818bfffbccSCorey Minyard ibs->watchdog_running = 1; 10828bfffbccSCorey Minyard } 10838bfffbccSCorey Minyard 10848bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 10858bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1086a580d820SCédric Le Goater RspBuffer *rsp) 10878bfffbccSCorey Minyard { 10888bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 10896acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1090d13ada5dSCédric Le Goater return; 10918bfffbccSCorey Minyard } 10928bfffbccSCorey Minyard do_watchdog_reset(ibs); 10938bfffbccSCorey Minyard } 10948bfffbccSCorey Minyard 10958bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 10968bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1097a580d820SCédric Le Goater RspBuffer *rsp) 10988bfffbccSCorey Minyard { 10998bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 11008bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 11018bfffbccSCorey Minyard unsigned int val; 11028bfffbccSCorey Minyard 11038bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 11048bfffbccSCorey Minyard if (val == 0 || val > 5) { 11056acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1106d13ada5dSCédric Le Goater return; 11078bfffbccSCorey Minyard } 11088bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11098bfffbccSCorey Minyard switch (val) { 11108bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11118bfffbccSCorey Minyard break; 11128bfffbccSCorey Minyard 11138bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11146acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1)); 11158bfffbccSCorey Minyard break; 11168bfffbccSCorey Minyard 11178bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11186acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1)); 11198bfffbccSCorey Minyard break; 11208bfffbccSCorey Minyard 11218bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11226acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1)); 11238bfffbccSCorey Minyard break; 11248bfffbccSCorey Minyard 11258bfffbccSCorey Minyard default: 11266acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 11278bfffbccSCorey Minyard } 1128a580d820SCédric Le Goater if (rsp->buffer[2]) { 11296acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1130d13ada5dSCédric Le Goater return; 11318bfffbccSCorey Minyard } 11328bfffbccSCorey Minyard 11338bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11348bfffbccSCorey Minyard switch (val) { 11358bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11368bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11378bfffbccSCorey Minyard break; 11388bfffbccSCorey Minyard 11398bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11408bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11418bfffbccSCorey Minyard /* NMI not supported. */ 11426acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1143d13ada5dSCédric Le Goater return; 11448bfffbccSCorey Minyard } 114537eebb86SCorey Minyard break; 114637eebb86SCorey Minyard 11478bfffbccSCorey Minyard default: 11488bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11496acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1150d13ada5dSCédric Le Goater return; 11518bfffbccSCorey Minyard } 11528bfffbccSCorey Minyard 11538bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11548bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11558bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11568bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 11578bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 11588bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 11598bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 11608bfffbccSCorey Minyard do_watchdog_reset(ibs); 11618bfffbccSCorey Minyard } else { 11628bfffbccSCorey Minyard ibs->watchdog_running = 0; 11638bfffbccSCorey Minyard } 11648bfffbccSCorey Minyard } 11658bfffbccSCorey Minyard 11668bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 11678bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1168a580d820SCédric Le Goater RspBuffer *rsp) 11698bfffbccSCorey Minyard { 1170a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1171a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1172a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1173a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 11748bfffbccSCorey Minyard if (ibs->watchdog_running) { 11758bfffbccSCorey Minyard long timeout; 11768bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 11778bfffbccSCorey Minyard / 100000000); 1178a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff); 1179a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff); 11808bfffbccSCorey Minyard } else { 1181a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 1182a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 11838bfffbccSCorey Minyard } 11848bfffbccSCorey Minyard } 11858bfffbccSCorey Minyard 11868bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 11878bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1188a580d820SCédric Le Goater RspBuffer *rsp) 11898bfffbccSCorey Minyard { 11908bfffbccSCorey Minyard unsigned int i; 11918bfffbccSCorey Minyard 1192a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1193a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1194a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1195a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1196a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 11978bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1198a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 11998bfffbccSCorey Minyard } 12008bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1201a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 12028bfffbccSCorey Minyard } 12038bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1204a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 12058bfffbccSCorey Minyard } 12068bfffbccSCorey Minyard 12078bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 12088bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1209a580d820SCédric Le Goater RspBuffer *rsp) 12108bfffbccSCorey Minyard { 1211a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1212a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 12138bfffbccSCorey Minyard } 12148bfffbccSCorey Minyard 12158bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 12168bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1217a580d820SCédric Le Goater RspBuffer *rsp) 12188bfffbccSCorey Minyard { 12198bfffbccSCorey Minyard unsigned int pos; 12208bfffbccSCorey Minyard uint16_t nextrec; 1221a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 12228bfffbccSCorey Minyard 12238bfffbccSCorey Minyard if (cmd[6]) { 12247f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 12256acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 12267f996411SCédric Le Goater return; 12278bfffbccSCorey Minyard } 12287f996411SCédric Le Goater } 12297f996411SCédric Le Goater 12308bfffbccSCorey Minyard pos = 0; 12318bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 12328bfffbccSCorey Minyard &pos, &nextrec)) { 12336acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1234d13ada5dSCédric Le Goater return; 12358bfffbccSCorey Minyard } 1236a2295f0aSCédric Le Goater 1237a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1238a2295f0aSCédric Le Goater 1239a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 12406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE); 1241d13ada5dSCédric Le Goater return; 12428bfffbccSCorey Minyard } 12438bfffbccSCorey Minyard 1244a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1245a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 12468bfffbccSCorey Minyard 12478bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1248a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 12498bfffbccSCorey Minyard } 12508bfffbccSCorey Minyard 1251a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 12526acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES); 1253d13ada5dSCédric Le Goater return; 12548bfffbccSCorey Minyard } 1255a580d820SCédric Le Goater 1256a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 12578bfffbccSCorey Minyard } 12588bfffbccSCorey Minyard 12598bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 12608bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1261a580d820SCédric Le Goater RspBuffer *rsp) 12628bfffbccSCorey Minyard { 12638bfffbccSCorey Minyard uint16_t recid; 1264a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 12658bfffbccSCorey Minyard 1266a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 12676acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1268d13ada5dSCédric Le Goater return; 12698bfffbccSCorey Minyard } 1270a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1271a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 12728bfffbccSCorey Minyard } 12738bfffbccSCorey Minyard 12748bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 12758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1276a580d820SCédric Le Goater RspBuffer *rsp) 12778bfffbccSCorey Minyard { 12787f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 12796acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 12807f996411SCédric Le Goater return; 12817f996411SCédric Le Goater } 12827f996411SCédric Le Goater 12838bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 12846acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1285d13ada5dSCédric Le Goater return; 12868bfffbccSCorey Minyard } 12878bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 12888bfffbccSCorey Minyard ibs->sdr.next_free = 0; 12898bfffbccSCorey Minyard ibs->sdr.overflow = 0; 12908bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1291a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 12928bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 12938bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1294a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 12958bfffbccSCorey Minyard } else { 12966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 12978bfffbccSCorey Minyard return; 12988bfffbccSCorey Minyard } 1299d13ada5dSCédric Le Goater } 13008bfffbccSCorey Minyard 13018bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 13028bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1303a580d820SCédric Le Goater RspBuffer *rsp) 13048bfffbccSCorey Minyard { 13058bfffbccSCorey Minyard unsigned int i, val; 13068bfffbccSCorey Minyard 1307a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1308a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1309a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 13108bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1311a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1312a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 13138bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1314a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 13158bfffbccSCorey Minyard } 13168bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1317a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 13188bfffbccSCorey Minyard } 13198bfffbccSCorey Minyard /* Only support Reserve SEL */ 1320a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 13218bfffbccSCorey Minyard } 13228bfffbccSCorey Minyard 13238bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 13248bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1325a580d820SCédric Le Goater RspBuffer *rsp) 13268bfffbccSCorey Minyard { 1327a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1328a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 13298bfffbccSCorey Minyard } 13308bfffbccSCorey Minyard 13318bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 13328bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1333a580d820SCédric Le Goater RspBuffer *rsp) 13348bfffbccSCorey Minyard { 13358bfffbccSCorey Minyard unsigned int val; 13368bfffbccSCorey Minyard 13378bfffbccSCorey Minyard if (cmd[6]) { 13387f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 13396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13407f996411SCédric Le Goater return; 13417f996411SCédric Le Goater } 13428bfffbccSCorey Minyard } 13438bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 13446acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1345d13ada5dSCédric Le Goater return; 13468bfffbccSCorey Minyard } 13478bfffbccSCorey Minyard if (cmd[6] > 15) { 13486acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1349d13ada5dSCédric Le Goater return; 13508bfffbccSCorey Minyard } 13518bfffbccSCorey Minyard if (cmd[7] == 0xff) { 13528bfffbccSCorey Minyard cmd[7] = 16; 13538bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 13546acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1355d13ada5dSCédric Le Goater return; 13568bfffbccSCorey Minyard } else { 13578bfffbccSCorey Minyard cmd[7] += cmd[6]; 13588bfffbccSCorey Minyard } 13598bfffbccSCorey Minyard 13608bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 13618bfffbccSCorey Minyard if (val == 0xffff) { 13628bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 13638bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 13646acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1365d13ada5dSCédric Le Goater return; 13668bfffbccSCorey Minyard } 13678bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1368a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1369a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 13708bfffbccSCorey Minyard } else { 1371a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1372a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 13738bfffbccSCorey Minyard } 13748bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1375a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 13768bfffbccSCorey Minyard } 13778bfffbccSCorey Minyard } 13788bfffbccSCorey Minyard 13798bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 13808bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1381a580d820SCédric Le Goater RspBuffer *rsp) 13828bfffbccSCorey Minyard { 13838bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 13846acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 1385d13ada5dSCédric Le Goater return; 13868bfffbccSCorey Minyard } 13878bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1388a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1389a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 13908bfffbccSCorey Minyard } 13918bfffbccSCorey Minyard 13928bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 13938bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1394a580d820SCédric Le Goater RspBuffer *rsp) 13958bfffbccSCorey Minyard { 13967f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 13976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13987f996411SCédric Le Goater return; 13997f996411SCédric Le Goater } 14007f996411SCédric Le Goater 14018bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 14026acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1403d13ada5dSCédric Le Goater return; 14048bfffbccSCorey Minyard } 14058bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 14068bfffbccSCorey Minyard ibs->sel.next_free = 0; 14078bfffbccSCorey Minyard ibs->sel.overflow = 0; 14088bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1409a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14108bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 14118bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1412a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14138bfffbccSCorey Minyard } else { 14146acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 14158bfffbccSCorey Minyard return; 14168bfffbccSCorey Minyard } 1417d13ada5dSCédric Le Goater } 14188bfffbccSCorey Minyard 14198bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 14208bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1421a580d820SCédric Le Goater RspBuffer *rsp) 14228bfffbccSCorey Minyard { 14238bfffbccSCorey Minyard uint32_t val; 14248bfffbccSCorey Minyard struct ipmi_time now; 14258bfffbccSCorey Minyard 14268bfffbccSCorey Minyard ipmi_gettime(&now); 14278bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1428a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1429a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1430a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1431a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 14328bfffbccSCorey Minyard } 14338bfffbccSCorey Minyard 14348bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 14358bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1436a580d820SCédric Le Goater RspBuffer *rsp) 14378bfffbccSCorey Minyard { 14388bfffbccSCorey Minyard uint32_t val; 14398bfffbccSCorey Minyard struct ipmi_time now; 14408bfffbccSCorey Minyard 14418bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 14428bfffbccSCorey Minyard ipmi_gettime(&now); 14438bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 14448bfffbccSCorey Minyard } 14458bfffbccSCorey Minyard 14468bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 14478bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1448a580d820SCédric Le Goater RspBuffer *rsp) 14498bfffbccSCorey Minyard { 14508bfffbccSCorey Minyard IPMISensor *sens; 14518bfffbccSCorey Minyard 145273d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 14538bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14546acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1455d13ada5dSCédric Le Goater return; 14568bfffbccSCorey Minyard } 14578bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14588bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 14598bfffbccSCorey Minyard case 0: /* Do not change */ 14608bfffbccSCorey Minyard break; 14618bfffbccSCorey Minyard case 1: /* Enable bits */ 14628bfffbccSCorey Minyard if (cmd_len > 4) { 14638bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 14648bfffbccSCorey Minyard } 14658bfffbccSCorey Minyard if (cmd_len > 5) { 14668bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 14678bfffbccSCorey Minyard } 14688bfffbccSCorey Minyard if (cmd_len > 6) { 14698bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 14708bfffbccSCorey Minyard } 14718bfffbccSCorey Minyard if (cmd_len > 7) { 14728bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 14738bfffbccSCorey Minyard } 14748bfffbccSCorey Minyard break; 14758bfffbccSCorey Minyard case 2: /* Disable bits */ 14768bfffbccSCorey Minyard if (cmd_len > 4) { 14778bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 14788bfffbccSCorey Minyard } 14798bfffbccSCorey Minyard if (cmd_len > 5) { 14808bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 14818bfffbccSCorey Minyard } 14828bfffbccSCorey Minyard if (cmd_len > 6) { 14838bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 14848bfffbccSCorey Minyard } 14858bfffbccSCorey Minyard if (cmd_len > 7) { 14868bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 14878bfffbccSCorey Minyard } 14888bfffbccSCorey Minyard break; 14898bfffbccSCorey Minyard case 3: 14906acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1491d13ada5dSCédric Le Goater return; 14928bfffbccSCorey Minyard } 14938bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 14948bfffbccSCorey Minyard } 14958bfffbccSCorey Minyard 14968bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 14978bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1498a580d820SCédric Le Goater RspBuffer *rsp) 14998bfffbccSCorey Minyard { 15008bfffbccSCorey Minyard IPMISensor *sens; 15018bfffbccSCorey Minyard 150273d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15038bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15046acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1505d13ada5dSCédric Le Goater return; 15068bfffbccSCorey Minyard } 15078bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1508a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1509a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1510a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1511a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1512a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 15138bfffbccSCorey Minyard } 15148bfffbccSCorey Minyard 15158bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 15168bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1517a580d820SCédric Le Goater RspBuffer *rsp) 15188bfffbccSCorey Minyard { 15198bfffbccSCorey Minyard IPMISensor *sens; 15208bfffbccSCorey Minyard 152173d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15228bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1524d13ada5dSCédric Le Goater return; 15258bfffbccSCorey Minyard } 15268bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15278bfffbccSCorey Minyard 15288bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 15298bfffbccSCorey Minyard /* Just clear everything */ 15308bfffbccSCorey Minyard sens->states = 0; 15318bfffbccSCorey Minyard return; 15328bfffbccSCorey Minyard } 1533d13ada5dSCédric Le Goater } 15348bfffbccSCorey Minyard 15358bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 15368bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1537a580d820SCédric Le Goater RspBuffer *rsp) 15388bfffbccSCorey Minyard { 15398bfffbccSCorey Minyard IPMISensor *sens; 15408bfffbccSCorey Minyard 154173d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15428bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15436acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1544d13ada5dSCédric Le Goater return; 15458bfffbccSCorey Minyard } 15468bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1547a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1548a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1549a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1550a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1551a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1552a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 15538bfffbccSCorey Minyard } 15548bfffbccSCorey Minyard 15558bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 15568bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1557a580d820SCédric Le Goater RspBuffer *rsp) 15588bfffbccSCorey Minyard { 15598bfffbccSCorey Minyard IPMISensor *sens; 15608bfffbccSCorey Minyard 156173d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15628bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15636acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1564d13ada5dSCédric Le Goater return; 15658bfffbccSCorey Minyard } 15668bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1567a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1568a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1569a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 15708bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1571a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 15728bfffbccSCorey Minyard } 15738bfffbccSCorey Minyard } 15748bfffbccSCorey Minyard 1575728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1576728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1577a580d820SCédric Le Goater RspBuffer *rsp) 1578728710e1SCédric Le Goater { 1579728710e1SCédric Le Goater IPMISensor *sens; 1580728710e1SCédric Le Goater 1581728710e1SCédric Le Goater 158273d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1583728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15846acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1585728710e1SCédric Le Goater return; 1586728710e1SCédric Le Goater } 1587728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1588728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1589728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1590728710e1SCédric Le Goater } 1591728710e1SCédric Le Goater 1592728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1593728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1594a580d820SCédric Le Goater RspBuffer *rsp) 1595728710e1SCédric Le Goater { 1596728710e1SCédric Le Goater IPMISensor *sens; 1597728710e1SCédric Le Goater 1598728710e1SCédric Le Goater 159973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1600728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16016acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1602728710e1SCédric Le Goater return; 1603728710e1SCédric Le Goater } 1604728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1605a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1606a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1607728710e1SCédric Le Goater } 1608728710e1SCédric Le Goater 1609728710e1SCédric Le Goater 161062a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 16114f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 16124f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 16134f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 16144f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 16158bfffbccSCorey Minyard }; 16168bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 161762a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 16188bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 16198bfffbccSCorey Minyard }; 16208bfffbccSCorey Minyard 162162a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 16224f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 16234f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 16244f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 16254f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 16264f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 16274f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 16284f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 16298bfffbccSCorey Minyard }; 16308bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 163162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 16328bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 16338bfffbccSCorey Minyard }; 16348bfffbccSCorey Minyard 163562a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 16364f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 16374f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 16384f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 16394f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 16404f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 16414f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 16424f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 16434f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 16444f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 16454f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 16464f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 16474f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 16484f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 16494f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 16504f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 16514f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 16528bfffbccSCorey Minyard }; 16538bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 165462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 16558bfffbccSCorey Minyard .cmd_handlers = app_cmds 16568bfffbccSCorey Minyard }; 16578bfffbccSCorey Minyard 165862a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 16594f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 16604f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 16614f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 16624f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 16634f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 16644f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 16654f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 16664f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 16674f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 16684f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 16694f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 }, 16704f298a4bSCédric Le Goater [IPMI_CMD_SET_SEL_TIME] = { set_sel_time }, 16718bfffbccSCorey Minyard }; 16728bfffbccSCorey Minyard 16738bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 167462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 16758bfffbccSCorey Minyard .cmd_handlers = storage_cmds 16768bfffbccSCorey Minyard }; 16778bfffbccSCorey Minyard 16788bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 16798bfffbccSCorey Minyard { 16808bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 16818bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 16828bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 16838bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 16848bfffbccSCorey Minyard } 16858bfffbccSCorey Minyard 16868bfffbccSCorey Minyard static const uint8_t init_sdrs[] = { 16878bfffbccSCorey Minyard /* Watchdog device */ 16888bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 16898bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 16908bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16918bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 16928bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 16938bfffbccSCorey Minyard /* End */ 16948bfffbccSCorey Minyard 0xff, 0xff, 0x00, 0x00, 0x00 16958bfffbccSCorey Minyard }; 16968bfffbccSCorey Minyard 1697*4fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs) 1698*4fa9f08eSCédric Le Goater { 1699*4fa9f08eSCédric Le Goater unsigned int i; 1700*4fa9f08eSCédric Le Goater unsigned int recid; 1701*4fa9f08eSCédric Le Goater 1702*4fa9f08eSCédric Le Goater for (i = 0;;) { 1703*4fa9f08eSCédric Le Goater struct ipmi_sdr_header *sdrh; 1704*4fa9f08eSCédric Le Goater int len; 1705*4fa9f08eSCédric Le Goater if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) { 1706*4fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 1707*4fa9f08eSCédric Le Goater return; 1708*4fa9f08eSCédric Le Goater } 1709*4fa9f08eSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &init_sdrs[i]; 1710*4fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh); 1711*4fa9f08eSCédric Le Goater recid = ipmi_sdr_recid(sdrh); 1712*4fa9f08eSCédric Le Goater if (recid == 0xffff) { 1713*4fa9f08eSCédric Le Goater break; 1714*4fa9f08eSCédric Le Goater } 1715*4fa9f08eSCédric Le Goater if ((i + len) > sizeof(init_sdrs)) { 1716*4fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 1717*4fa9f08eSCédric Le Goater return; 1718*4fa9f08eSCédric Le Goater } 1719*4fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 1720*4fa9f08eSCédric Le Goater i += len; 1721*4fa9f08eSCédric Le Goater } 1722*4fa9f08eSCédric Le Goater } 1723*4fa9f08eSCédric Le Goater 1724bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1725bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1726bd66bcfcSCorey Minyard .version_id = 1, 1727bd66bcfcSCorey Minyard .minimum_version_id = 1, 1728bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1729bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1730bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1731bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1732bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1733bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1734bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1735bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1736bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1737bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1738bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1739bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1740bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1741bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1742bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1743bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1744bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1745bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1746bd66bcfcSCorey Minyard IPMIBmcSim), 1747bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1748bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1749bd66bcfcSCorey Minyard } 1750bd66bcfcSCorey Minyard }; 1751bd66bcfcSCorey Minyard 17520bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp) 17538bfffbccSCorey Minyard { 17540bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev); 17558bfffbccSCorey Minyard unsigned int i; 17568bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 17578bfffbccSCorey Minyard 17588bfffbccSCorey Minyard qemu_mutex_init(&ibs->lock); 17598bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 17608bfffbccSCorey Minyard 17618bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 17628bfffbccSCorey Minyard ibs->device_id = 0x20; 17638bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1764b7088392SCédric Le Goater ibs->restart_cause = 0; 17658bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 17668bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 17678bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 17688bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 17698bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 17708bfffbccSCorey Minyard } 17718bfffbccSCorey Minyard 1772*4fa9f08eSCédric Le Goater ipmi_sdr_init(ibs); 17738bfffbccSCorey Minyard 177452ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 177552ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 177652ba4d50SCédric Le Goater 177752ba4d50SCédric Le Goater if (qemu_uuid_set) { 177852ba4d50SCédric Le Goater memcpy(&ibs->uuid, qemu_uuid, 16); 177952ba4d50SCédric Le Goater } else { 178052ba4d50SCédric Le Goater memset(&ibs->uuid, 0, 16); 178152ba4d50SCédric Le Goater } 178252ba4d50SCédric Le Goater 17838bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 17848bfffbccSCorey Minyard register_cmds(ibs); 17858bfffbccSCorey Minyard 17868bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1787bd66bcfcSCorey Minyard 1788bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 17898bfffbccSCorey Minyard } 17908bfffbccSCorey Minyard 17918bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 17928bfffbccSCorey Minyard { 17930bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc); 17948bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 17958bfffbccSCorey Minyard 17960bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize; 17978bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 17988bfffbccSCorey Minyard } 17998bfffbccSCorey Minyard 18008bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 18018bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 18028bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 18038bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 18048bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 18058bfffbccSCorey Minyard }; 18068bfffbccSCorey Minyard 18078bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 18088bfffbccSCorey Minyard { 18098bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 18108bfffbccSCorey Minyard } 18118bfffbccSCorey Minyard 18128bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1813