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; 1568bfffbccSCorey Minyard 1578bfffbccSCorey Minyard #define MAX_NETFNS 64 1588bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s, 1598bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1608bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1618bfffbccSCorey Minyard unsigned int max_rsp_len); 1628bfffbccSCorey Minyard typedef struct IPMINetfn { 1638bfffbccSCorey Minyard unsigned int cmd_nums; 1648bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1658bfffbccSCorey Minyard } IPMINetfn; 1668bfffbccSCorey Minyard 1678bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1688bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1698bfffbccSCorey Minyard uint8_t len; 1708bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1718bfffbccSCorey Minyard } IPMIRcvBufEntry; 1728bfffbccSCorey Minyard 1738bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1748bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1758bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1768bfffbccSCorey Minyard struct IPMIBmcSim { 1778bfffbccSCorey Minyard IPMIBmc parent; 1788bfffbccSCorey Minyard 1798bfffbccSCorey Minyard QEMUTimer *timer; 1808bfffbccSCorey Minyard 1818bfffbccSCorey Minyard uint8_t bmc_global_enables; 1828bfffbccSCorey Minyard uint8_t msg_flags; 1838bfffbccSCorey Minyard 1848bfffbccSCorey Minyard bool watchdog_initialized; 1858bfffbccSCorey Minyard uint8_t watchdog_use; 1868bfffbccSCorey Minyard uint8_t watchdog_action; 1878bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 1888bfffbccSCorey Minyard bool watchdog_expired; 1898bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 1908bfffbccSCorey Minyard 1918bfffbccSCorey Minyard bool watchdog_running; 1928bfffbccSCorey Minyard bool watchdog_preaction_ran; 1938bfffbccSCorey Minyard int64_t watchdog_expiry; 1948bfffbccSCorey Minyard 1958bfffbccSCorey Minyard uint8_t device_id; 1968bfffbccSCorey Minyard uint8_t ipmi_version; 1978bfffbccSCorey Minyard uint8_t device_rev; 1988bfffbccSCorey Minyard uint8_t fwrev1; 1998bfffbccSCorey Minyard uint8_t fwrev2; 2008bfffbccSCorey Minyard uint8_t mfg_id[3]; 2018bfffbccSCorey Minyard uint8_t product_id[2]; 2028bfffbccSCorey Minyard 203b7088392SCédric Le Goater uint8_t restart_cause; 204b7088392SCédric Le Goater 20552ba4d50SCédric Le Goater uint8_t acpi_power_state[2]; 20652ba4d50SCédric Le Goater uint8_t uuid[16]; 20752ba4d50SCédric Le Goater 2088bfffbccSCorey Minyard IPMISel sel; 2098bfffbccSCorey Minyard IPMISdr sdr; 2108bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 2118bfffbccSCorey Minyard 2128bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2138bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2148bfffbccSCorey Minyard 2158bfffbccSCorey Minyard QemuMutex lock; 2168bfffbccSCorey Minyard /* We allow one event in the buffer */ 2178bfffbccSCorey Minyard uint8_t evtbuf[16]; 2188bfffbccSCorey Minyard 2198bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2208bfffbccSCorey Minyard }; 2218bfffbccSCorey Minyard 2228bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2238bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2248bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2258bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2268bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2278bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2288bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2308bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2318bfffbccSCorey Minyard 2328bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2338bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2348bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2358bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2368bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2378bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2388bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2398bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2418bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2428bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2438bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2448bfffbccSCorey Minyard 2458bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2468bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2478bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2488bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2498bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2608bfffbccSCorey Minyard 2618bfffbccSCorey Minyard 2628bfffbccSCorey Minyard /* Add a byte to the response. */ 2638bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \ 2648bfffbccSCorey Minyard do { \ 2658bfffbccSCorey Minyard if (*rsp_len >= max_rsp_len) { \ 2668bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \ 267d13ada5dSCédric Le Goater return; \ 2688bfffbccSCorey Minyard } \ 2698bfffbccSCorey Minyard rsp[(*rsp_len)++] = (b); \ 2708bfffbccSCorey Minyard } while (0) 2718bfffbccSCorey Minyard 2728bfffbccSCorey Minyard /* Verify that the received command is a certain length. */ 2738bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \ 2748bfffbccSCorey Minyard if (cmd_len < l) { \ 2758bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \ 276d13ada5dSCédric Le Goater return; \ 2778bfffbccSCorey Minyard } 2788bfffbccSCorey Minyard 2798bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */ 2808bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \ 2818bfffbccSCorey Minyard do { \ 2828bfffbccSCorey Minyard if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \ 2838bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_RESERVATION; \ 284d13ada5dSCédric Le Goater return; \ 2858bfffbccSCorey Minyard } \ 2868bfffbccSCorey Minyard } while (0) 2878bfffbccSCorey Minyard 2888bfffbccSCorey Minyard 2898bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 2908bfffbccSCorey Minyard 2918bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 2928bfffbccSCorey Minyard { 2938bfffbccSCorey Minyard int64_t stime; 2948bfffbccSCorey Minyard 2958bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 2968bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 2978bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 2988bfffbccSCorey Minyard } 2998bfffbccSCorey Minyard 3008bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 3018bfffbccSCorey Minyard { 3028bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3038bfffbccSCorey Minyard } 3048bfffbccSCorey Minyard 3058bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 3068bfffbccSCorey Minyard { 3078bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3088bfffbccSCorey Minyard 3098bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3108bfffbccSCorey Minyard } 3118bfffbccSCorey Minyard 3128bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3138bfffbccSCorey Minyard { 3148bfffbccSCorey Minyard unsigned int val; 3158bfffbccSCorey Minyard struct ipmi_time now; 3168bfffbccSCorey Minyard 3178bfffbccSCorey Minyard ipmi_gettime(&now); 3188bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3198bfffbccSCorey Minyard ts[0] = val & 0xff; 3208bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3218bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3228bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3238bfffbccSCorey Minyard } 3248bfffbccSCorey Minyard 3258bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3268bfffbccSCorey Minyard { 3278bfffbccSCorey Minyard sdr->reservation++; 3288bfffbccSCorey Minyard if (sdr->reservation == 0) { 3298bfffbccSCorey Minyard sdr->reservation = 1; 3308bfffbccSCorey Minyard } 3318bfffbccSCorey Minyard } 3328bfffbccSCorey Minyard 333a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 334a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3358bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3368bfffbccSCorey Minyard { 337a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 338a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 339a2295f0aSCédric Le Goater 340a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3418bfffbccSCorey Minyard return 1; 3428bfffbccSCorey Minyard } 3438bfffbccSCorey Minyard 344a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3458bfffbccSCorey Minyard return 1; 3468bfffbccSCorey Minyard } 3478bfffbccSCorey Minyard 3488bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3498bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3508bfffbccSCorey Minyard return 1; 3518bfffbccSCorey Minyard } 3528bfffbccSCorey Minyard 353a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 354a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 355a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 356a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3578bfffbccSCorey Minyard 3588bfffbccSCorey Minyard if (recid) { 3598bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3608bfffbccSCorey Minyard } 3618bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3628bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3638bfffbccSCorey Minyard ibs->sdr.next_free += len; 3648bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3658bfffbccSCorey Minyard return 0; 3668bfffbccSCorey Minyard } 3678bfffbccSCorey Minyard 3688bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3698bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3708bfffbccSCorey Minyard { 3718bfffbccSCorey Minyard unsigned int pos = *retpos; 3728bfffbccSCorey Minyard 3738bfffbccSCorey Minyard while (pos < sdr->next_free) { 374a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 375a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 376a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 377a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 3788bfffbccSCorey Minyard 3798bfffbccSCorey Minyard if (trec == recid) { 3808bfffbccSCorey Minyard if (nextrec) { 3818bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3828bfffbccSCorey Minyard *nextrec = 0xffff; 3838bfffbccSCorey Minyard } else { 3848bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3858bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3868bfffbccSCorey Minyard } 3878bfffbccSCorey Minyard } 3888bfffbccSCorey Minyard *retpos = pos; 3898bfffbccSCorey Minyard return 0; 3908bfffbccSCorey Minyard } 3918bfffbccSCorey Minyard pos = nextpos; 3928bfffbccSCorey Minyard } 3938bfffbccSCorey Minyard return 1; 3948bfffbccSCorey Minyard } 3958bfffbccSCorey Minyard 3968bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 3978bfffbccSCorey Minyard { 3988bfffbccSCorey Minyard sel->reservation++; 3998bfffbccSCorey Minyard if (sel->reservation == 0) { 4008bfffbccSCorey Minyard sel->reservation = 1; 4018bfffbccSCorey Minyard } 4028bfffbccSCorey Minyard } 4038bfffbccSCorey Minyard 4048bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4058bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4068bfffbccSCorey Minyard { 4078bfffbccSCorey Minyard event[0] = 0xff; 4088bfffbccSCorey Minyard event[1] = 0xff; 4098bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 4108bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4118bfffbccSCorey Minyard ibs->sel.overflow = 1; 4128bfffbccSCorey Minyard return 1; 4138bfffbccSCorey Minyard } 4148bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4158bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4168bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 4178bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4188bfffbccSCorey Minyard ibs->sel.next_free++; 4198bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4208bfffbccSCorey Minyard return 0; 4218bfffbccSCorey Minyard } 4228bfffbccSCorey Minyard 4238bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4248bfffbccSCorey Minyard { 4258bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4268bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4278bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4288bfffbccSCorey Minyard } 4298bfffbccSCorey Minyard 4308bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4318bfffbccSCorey Minyard { 4328bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4338bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4348bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4358bfffbccSCorey Minyard } 4368bfffbccSCorey Minyard 4378bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4388bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4398bfffbccSCorey Minyard { 4408bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4418bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4428bfffbccSCorey Minyard uint8_t evt[16]; 4438bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4448bfffbccSCorey Minyard 4458bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4468bfffbccSCorey Minyard return; 4478bfffbccSCorey Minyard } 4488bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4498bfffbccSCorey Minyard return; 4508bfffbccSCorey Minyard } 4518bfffbccSCorey Minyard 4528bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4538bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4548bfffbccSCorey Minyard evt[8] = 0; 4558bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4568bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4578bfffbccSCorey Minyard evt[11] = sens_num; 4588bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4598bfffbccSCorey Minyard evt[13] = evd1; 4608bfffbccSCorey Minyard evt[14] = evd2; 4618bfffbccSCorey Minyard evt[15] = evd3; 4628bfffbccSCorey Minyard 4638bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 4648bfffbccSCorey Minyard sel_add_event(ibs, evt); 4658bfffbccSCorey Minyard } 4668bfffbccSCorey Minyard 4678bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 468d13ada5dSCédric Le Goater return; 4698bfffbccSCorey Minyard } 4708bfffbccSCorey Minyard 4718bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 4728bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 4738bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 4748bfffbccSCorey Minyard } 4758bfffbccSCorey Minyard 4768bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 4778bfffbccSCorey Minyard unsigned int bit, unsigned int val, 4788bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4798bfffbccSCorey Minyard { 4808bfffbccSCorey Minyard IPMISensor *sens; 4818bfffbccSCorey Minyard uint16_t mask; 4828bfffbccSCorey Minyard 4838bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 4848bfffbccSCorey Minyard return; 4858bfffbccSCorey Minyard } 4868bfffbccSCorey Minyard if (bit >= 16) { 4878bfffbccSCorey Minyard return; 4888bfffbccSCorey Minyard } 4898bfffbccSCorey Minyard 4908bfffbccSCorey Minyard mask = (1 << bit); 4918bfffbccSCorey Minyard sens = ibs->sensors + sensor; 4928bfffbccSCorey Minyard if (val) { 4938bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 4948bfffbccSCorey Minyard if (sens->assert_states & mask) { 4958bfffbccSCorey Minyard return; /* Already asserted */ 4968bfffbccSCorey Minyard } 4978bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 4988bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 4998bfffbccSCorey Minyard /* Send an event on assert */ 5008bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5018bfffbccSCorey Minyard } 5028bfffbccSCorey Minyard } else { 5038bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5048bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5058bfffbccSCorey Minyard return; /* Already deasserted */ 5068bfffbccSCorey Minyard } 5078bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5088bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5098bfffbccSCorey Minyard /* Send an event on deassert */ 5108bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5118bfffbccSCorey Minyard } 5128bfffbccSCorey Minyard } 5138bfffbccSCorey Minyard } 5148bfffbccSCorey Minyard 5158bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5168bfffbccSCorey Minyard { 5178bfffbccSCorey Minyard unsigned int i, pos; 5188bfffbccSCorey Minyard IPMISensor *sens; 5198bfffbccSCorey Minyard 5208bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5218bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5228bfffbccSCorey Minyard } 5238bfffbccSCorey Minyard 5248bfffbccSCorey Minyard pos = 0; 5258bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 526a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 527a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 528a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5298bfffbccSCorey Minyard 5308bfffbccSCorey Minyard if (len < 20) { 5318bfffbccSCorey Minyard continue; 5328bfffbccSCorey Minyard } 533a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5348bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5358bfffbccSCorey Minyard } 5368bfffbccSCorey Minyard 537*73d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 5388bfffbccSCorey Minyard continue; 5398bfffbccSCorey Minyard } 540a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5418bfffbccSCorey Minyard 5428bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 543a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 544a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 545a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 546a2295f0aSCédric Le Goater sens->deassert_suppt = 547a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 548a2295f0aSCédric Le Goater sens->states_suppt = 549a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 550a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 551a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5528bfffbccSCorey Minyard 5538bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5548bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5558bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5568bfffbccSCorey Minyard } 5578bfffbccSCorey Minyard } 5588bfffbccSCorey Minyard 5598bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5608bfffbccSCorey Minyard const IPMINetfn *netfnd) 5618bfffbccSCorey Minyard { 56293a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 5638bfffbccSCorey Minyard return -1; 5648bfffbccSCorey Minyard } 5658bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 5668bfffbccSCorey Minyard return 0; 5678bfffbccSCorey Minyard } 5688bfffbccSCorey Minyard 5698bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 5708bfffbccSCorey Minyard { 5718bfffbccSCorey Minyard int64_t next; 5728bfffbccSCorey Minyard if (ibs->watchdog_running) { 5738bfffbccSCorey Minyard next = ibs->watchdog_expiry; 5748bfffbccSCorey Minyard } else { 5758bfffbccSCorey Minyard /* Wait a minute */ 5768bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 5778bfffbccSCorey Minyard } 5788bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 5798bfffbccSCorey Minyard } 5808bfffbccSCorey Minyard 5818bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 5828bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 5838bfffbccSCorey Minyard unsigned int max_cmd_len, 5848bfffbccSCorey Minyard uint8_t msg_id) 5858bfffbccSCorey Minyard { 5868bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 5878bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 5888bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 5898bfffbccSCorey Minyard unsigned int netfn; 5908bfffbccSCorey Minyard uint8_t rsp[MAX_IPMI_MSG_SIZE]; 5918bfffbccSCorey Minyard unsigned int rsp_len_holder = 0; 5928bfffbccSCorey Minyard unsigned int *rsp_len = &rsp_len_holder; 5938bfffbccSCorey Minyard unsigned int max_rsp_len = sizeof(rsp); 5948bfffbccSCorey Minyard 5958bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 5968bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 597d13ada5dSCédric Le Goater if (max_rsp_len < 3) { 598d13ada5dSCédric Le Goater rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 599d13ada5dSCédric Le Goater goto out; 600d13ada5dSCédric Le Goater } 601d13ada5dSCédric Le Goater 6028bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[0] | 0x04); 6038bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[1]); 6048bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); /* Assume success */ 6058bfffbccSCorey Minyard 6068bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6078bfffbccSCorey Minyard if (cmd_len < 2) { 6088bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 6098bfffbccSCorey Minyard goto out; 6108bfffbccSCorey Minyard } 6118bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6128bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 6138bfffbccSCorey Minyard goto out; 6148bfffbccSCorey Minyard } 6158bfffbccSCorey Minyard 6168bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6178bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 6188bfffbccSCorey Minyard rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN; 6198bfffbccSCorey Minyard goto out; 6208bfffbccSCorey Minyard } 6218bfffbccSCorey Minyard 6228bfffbccSCorey Minyard netfn = cmd[0] >> 2; 6238bfffbccSCorey Minyard 6248bfffbccSCorey Minyard /* Odd netfns are not valid, make sure the command is registered */ 6258bfffbccSCorey Minyard if ((netfn & 1) || !ibs->netfns[netfn / 2] || 6268bfffbccSCorey Minyard (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) || 6278bfffbccSCorey Minyard (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) { 6288bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_CMD; 6298bfffbccSCorey Minyard goto out; 6308bfffbccSCorey Minyard } 6318bfffbccSCorey Minyard 6328bfffbccSCorey Minyard ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len, 6338bfffbccSCorey Minyard max_rsp_len); 6348bfffbccSCorey Minyard 6358bfffbccSCorey Minyard out: 6368bfffbccSCorey Minyard k->handle_rsp(s, msg_id, rsp, *rsp_len); 6378bfffbccSCorey Minyard 6388bfffbccSCorey Minyard next_timeout(ibs); 6398bfffbccSCorey Minyard } 6408bfffbccSCorey Minyard 6418bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 6428bfffbccSCorey Minyard { 6438bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6448bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6458bfffbccSCorey Minyard 6468bfffbccSCorey Minyard if (!ibs->watchdog_running) { 6478bfffbccSCorey Minyard goto out; 6488bfffbccSCorey Minyard } 6498bfffbccSCorey Minyard 6508bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 6518bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 6528bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 6538bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6548bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 6558bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6568bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 6578bfffbccSCorey Minyard break; 6588bfffbccSCorey Minyard 6598bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 6608bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6618bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 6628bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6638bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 6648bfffbccSCorey Minyard break; 6658bfffbccSCorey Minyard 6668bfffbccSCorey Minyard default: 6678bfffbccSCorey Minyard goto do_full_expiry; 6688bfffbccSCorey Minyard } 6698bfffbccSCorey Minyard 6708bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 6718bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 6728bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 6738bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 6748bfffbccSCorey Minyard goto out; 6758bfffbccSCorey Minyard } 6768bfffbccSCorey Minyard 6778bfffbccSCorey Minyard do_full_expiry: 6788bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 6798bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 6808bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 6818bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 6828bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 6838bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 6848bfffbccSCorey Minyard break; 6858bfffbccSCorey Minyard 6868bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 6878bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 6888bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 6898bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 6908bfffbccSCorey Minyard break; 6918bfffbccSCorey Minyard 6928bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 6938bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 6948bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 6958bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 6968bfffbccSCorey Minyard break; 6978bfffbccSCorey Minyard 6988bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 6998bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7008bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7018bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7028bfffbccSCorey Minyard break; 7038bfffbccSCorey Minyard } 7048bfffbccSCorey Minyard 7058bfffbccSCorey Minyard out: 7068bfffbccSCorey Minyard next_timeout(ibs); 7078bfffbccSCorey Minyard } 7088bfffbccSCorey Minyard 7098bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7108bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7118bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7128bfffbccSCorey Minyard unsigned int max_rsp_len) 7138bfffbccSCorey Minyard { 7148bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7158bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7168bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7178bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7188bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7198bfffbccSCorey Minyard } 7208bfffbccSCorey Minyard 7218bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7228bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7238bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7248bfffbccSCorey Minyard unsigned int max_rsp_len) 7258bfffbccSCorey Minyard { 7268bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */ 7278bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7288bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7298bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7308bfffbccSCorey Minyard } 7318bfffbccSCorey Minyard 7328bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7348bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7358bfffbccSCorey Minyard unsigned int max_rsp_len) 7368bfffbccSCorey Minyard { 7378bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7388bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7398bfffbccSCorey Minyard 7408bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 7418bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7428bfffbccSCorey Minyard case 0: /* power down */ 7438bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7448bfffbccSCorey Minyard break; 7458bfffbccSCorey Minyard case 1: /* power up */ 7468bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0); 7478bfffbccSCorey Minyard break; 7488bfffbccSCorey Minyard case 2: /* power cycle */ 7498bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7508bfffbccSCorey Minyard break; 7518bfffbccSCorey Minyard case 3: /* hard reset */ 7528bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7538bfffbccSCorey Minyard break; 7548bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 7558bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0); 7568bfffbccSCorey Minyard break; 7578bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 7588bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, 7598bfffbccSCorey Minyard IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0); 7608bfffbccSCorey Minyard break; 7618bfffbccSCorey Minyard default: 7628bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 7638bfffbccSCorey Minyard return; 7648bfffbccSCorey Minyard } 765d13ada5dSCédric Le Goater } 7668bfffbccSCorey Minyard 767b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 768b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 769b7088392SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 770b7088392SCédric Le Goater unsigned int max_rsp_len) 771b7088392SCédric Le Goater { 772b7088392SCédric Le Goater IPMI_ADD_RSP_DATA(ibs->restart_cause & 0xf); /* Restart Cause */ 773b7088392SCédric Le Goater IPMI_ADD_RSP_DATA(0); /* Channel 0 */ 774b7088392SCédric Le Goater } 775b7088392SCédric Le Goater 7768bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 7778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7788bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7798bfffbccSCorey Minyard unsigned int max_rsp_len) 7808bfffbccSCorey Minyard { 7818bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_id); 7828bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf); 7838bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f); 7848bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev2); 7858bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->ipmi_version); 7868bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */ 7878bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[0]); 7888bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[1]); 7898bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[2]); 7908bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[0]); 7918bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[1]); 7928bfffbccSCorey Minyard } 7938bfffbccSCorey Minyard 7948bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 7958bfffbccSCorey Minyard { 7968bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7978bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7988bfffbccSCorey Minyard bool irqs_on; 7998bfffbccSCorey Minyard 8008bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8018bfffbccSCorey Minyard 8028bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8038bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8048bfffbccSCorey Minyard 8058bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8068bfffbccSCorey Minyard } 8078bfffbccSCorey Minyard 8088bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8098bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8108bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8118bfffbccSCorey Minyard unsigned int max_rsp_len) 8128bfffbccSCorey Minyard { 8138bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8148bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8158bfffbccSCorey Minyard 8168bfffbccSCorey Minyard /* Disable all interrupts */ 8178bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8188bfffbccSCorey Minyard 8198bfffbccSCorey Minyard if (k->reset) { 8208bfffbccSCorey Minyard k->reset(s, true); 8218bfffbccSCorey Minyard } 8228bfffbccSCorey Minyard } 8238bfffbccSCorey Minyard 8248bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8258bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8268bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8278bfffbccSCorey Minyard unsigned int max_rsp_len) 8288bfffbccSCorey Minyard { 8298bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8308bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8318bfffbccSCorey Minyard 8328bfffbccSCorey Minyard if (k->reset) { 8338bfffbccSCorey Minyard k->reset(s, false); 8348bfffbccSCorey Minyard } 8358bfffbccSCorey Minyard } 83652ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 83752ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 83852ba4d50SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 83952ba4d50SCédric Le Goater unsigned int max_rsp_len) 84052ba4d50SCédric Le Goater { 84152ba4d50SCédric Le Goater IPMI_CHECK_CMD_LEN(4); 84252ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 84352ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 84452ba4d50SCédric Le Goater } 84552ba4d50SCédric Le Goater 84652ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 84752ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 84852ba4d50SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 84952ba4d50SCédric Le Goater unsigned int max_rsp_len) 85052ba4d50SCédric Le Goater { 85152ba4d50SCédric Le Goater IPMI_ADD_RSP_DATA(ibs->acpi_power_state[0]); 85252ba4d50SCédric Le Goater IPMI_ADD_RSP_DATA(ibs->acpi_power_state[1]); 85352ba4d50SCédric Le Goater } 85452ba4d50SCédric Le Goater 85552ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 85652ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 85752ba4d50SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 85852ba4d50SCédric Le Goater unsigned int max_rsp_len) 85952ba4d50SCédric Le Goater { 86052ba4d50SCédric Le Goater unsigned int i; 86152ba4d50SCédric Le Goater 86252ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 86352ba4d50SCédric Le Goater IPMI_ADD_RSP_DATA(ibs->uuid[i]); 86452ba4d50SCédric Le Goater } 86552ba4d50SCédric Le Goater } 8668bfffbccSCorey Minyard 8678bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 8688bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8698bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8708bfffbccSCorey Minyard unsigned int max_rsp_len) 8718bfffbccSCorey Minyard { 8728bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 8738bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 8748bfffbccSCorey Minyard } 8758bfffbccSCorey Minyard 8768bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 8778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8788bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8798bfffbccSCorey Minyard unsigned int max_rsp_len) 8808bfffbccSCorey Minyard { 8818bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->bmc_global_enables); 8828bfffbccSCorey Minyard } 8838bfffbccSCorey Minyard 8848bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 8858bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8868bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8878bfffbccSCorey Minyard unsigned int max_rsp_len) 8888bfffbccSCorey Minyard { 8898bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8908bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8918bfffbccSCorey Minyard 8928bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 8938bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 8948bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 8958bfffbccSCorey Minyard } 8968bfffbccSCorey Minyard 8978bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 8988bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8998bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 9008bfffbccSCorey Minyard unsigned int max_rsp_len) 9018bfffbccSCorey Minyard { 9028bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->msg_flags); 9038bfffbccSCorey Minyard } 9048bfffbccSCorey Minyard 9058bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9068bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 9078bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 9088bfffbccSCorey Minyard unsigned int max_rsp_len) 9098bfffbccSCorey Minyard { 9108bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9118bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9128bfffbccSCorey Minyard unsigned int i; 9138bfffbccSCorey Minyard 9148bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 9158bfffbccSCorey Minyard rsp[2] = 0x80; 916d13ada5dSCédric Le Goater return; 9178bfffbccSCorey Minyard } 9188bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 9198bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->evtbuf[i]); 9208bfffbccSCorey Minyard } 9218bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9228bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9238bfffbccSCorey Minyard } 9248bfffbccSCorey Minyard 9258bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 9278bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 9288bfffbccSCorey Minyard unsigned int max_rsp_len) 9298bfffbccSCorey Minyard { 9308bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9318bfffbccSCorey Minyard 9328bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 9338bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9348bfffbccSCorey Minyard rsp[2] = 0x80; /* Queue empty */ 9358bfffbccSCorey Minyard goto out; 9368bfffbccSCorey Minyard } 9378bfffbccSCorey Minyard rsp[3] = 0; /* Channel 0 */ 9388bfffbccSCorey Minyard *rsp_len += 1; 9398bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 9408bfffbccSCorey Minyard memcpy(rsp + 4, msg->buf, msg->len); 9418bfffbccSCorey Minyard *rsp_len += msg->len; 9428bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9438bfffbccSCorey Minyard g_free(msg); 9448bfffbccSCorey Minyard 9458bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9468bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9478bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9488bfffbccSCorey Minyard 9498bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9508bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9518bfffbccSCorey Minyard } 9528bfffbccSCorey Minyard 9538bfffbccSCorey Minyard out: 9548bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 9558bfffbccSCorey Minyard return; 9568bfffbccSCorey Minyard } 9578bfffbccSCorey Minyard 9588bfffbccSCorey Minyard static unsigned char 9598bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 9608bfffbccSCorey Minyard { 9618bfffbccSCorey Minyard for (; size > 0; size--, data++) { 9628bfffbccSCorey Minyard csum += *data; 9638bfffbccSCorey Minyard } 9648bfffbccSCorey Minyard 9658bfffbccSCorey Minyard return -csum; 9668bfffbccSCorey Minyard } 9678bfffbccSCorey Minyard 9688bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 9698bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 9708bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 9718bfffbccSCorey Minyard unsigned int max_rsp_len) 9728bfffbccSCorey Minyard { 9738bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9748bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9758bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9768bfffbccSCorey Minyard uint8_t *buf; 9778bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 9788bfffbccSCorey Minyard 9798bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 9808bfffbccSCorey Minyard 9818bfffbccSCorey Minyard if (cmd[2] != 0) { 9828bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 9838bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 984d13ada5dSCédric Le Goater return; 9858bfffbccSCorey Minyard } 9868bfffbccSCorey Minyard 9878bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(10); 9888bfffbccSCorey Minyard if (cmd[3] != 0x40) { 9898bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 9908bfffbccSCorey Minyard rsp[2] = 0x83; /* NAK on write */ 991d13ada5dSCédric Le Goater return; 9928bfffbccSCorey Minyard } 9938bfffbccSCorey Minyard 9948bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 9958bfffbccSCorey Minyard cmd_len -= 3; 9968bfffbccSCorey Minyard 9978bfffbccSCorey Minyard /* 9988bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 9998bfffbccSCorey Minyard * be returned in the response. 10008bfffbccSCorey Minyard */ 10018bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10028bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1003d13ada5dSCédric Le Goater return; /* No response */ 10048bfffbccSCorey Minyard } 10058bfffbccSCorey Minyard 10068bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10078bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10088bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10098bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10108bfffbccSCorey Minyard 10118bfffbccSCorey Minyard if (rqLun != 2) { 10128bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1013d13ada5dSCédric Le Goater return; 10148bfffbccSCorey Minyard } 10158bfffbccSCorey Minyard 10168bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10178bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10188bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10198bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10208bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10218bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10228bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10238bfffbccSCorey Minyard msg->len = 6; 10248bfffbccSCorey Minyard 10258bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10268bfffbccSCorey Minyard /* Not a command we handle. */ 10278bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10288bfffbccSCorey Minyard goto end_msg; 10298bfffbccSCorey Minyard } 10308bfffbccSCorey Minyard 10318bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10328bfffbccSCorey Minyard buf[0] = 0; 10338bfffbccSCorey Minyard buf[1] = 0; 10348bfffbccSCorey Minyard buf[2] = 0; 10358bfffbccSCorey Minyard buf[3] = 0; 10368bfffbccSCorey Minyard buf[4] = 0x51; 10378bfffbccSCorey Minyard buf[5] = 0; 10388bfffbccSCorey Minyard buf[6] = 0; 10398bfffbccSCorey Minyard buf[7] = 0; 10408bfffbccSCorey Minyard buf[8] = 0; 10418bfffbccSCorey Minyard buf[9] = 0; 10428bfffbccSCorey Minyard buf[10] = 0; 10438bfffbccSCorey Minyard msg->len += 11; 10448bfffbccSCorey Minyard 10458bfffbccSCorey Minyard end_msg: 10468bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 10478bfffbccSCorey Minyard msg->len++; 10488bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 10498bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 10508bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10518bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 10528bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 10538bfffbccSCorey Minyard } 10548bfffbccSCorey Minyard 10558bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 10568bfffbccSCorey Minyard { 10578bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 10588bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 10598bfffbccSCorey Minyard ibs->watchdog_running = 0; 10608bfffbccSCorey Minyard return; 10618bfffbccSCorey Minyard } 10628bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 10638bfffbccSCorey Minyard 10648bfffbccSCorey Minyard 10658bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 10668bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 10678bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 10688bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 10698bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 10708bfffbccSCorey Minyard } 10718bfffbccSCorey Minyard ibs->watchdog_running = 1; 10728bfffbccSCorey Minyard } 10738bfffbccSCorey Minyard 10748bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 10758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10768bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 10778bfffbccSCorey Minyard unsigned int max_rsp_len) 10788bfffbccSCorey Minyard { 10798bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 10808bfffbccSCorey Minyard rsp[2] = 0x80; 1081d13ada5dSCédric Le Goater return; 10828bfffbccSCorey Minyard } 10838bfffbccSCorey Minyard do_watchdog_reset(ibs); 10848bfffbccSCorey Minyard } 10858bfffbccSCorey Minyard 10868bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 10878bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10888bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 10898bfffbccSCorey Minyard unsigned int max_rsp_len) 10908bfffbccSCorey Minyard { 10918bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10928bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10938bfffbccSCorey Minyard unsigned int val; 10948bfffbccSCorey Minyard 10958bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 10968bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 10978bfffbccSCorey Minyard if (val == 0 || val > 5) { 10988bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1099d13ada5dSCédric Le Goater return; 11008bfffbccSCorey Minyard } 11018bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11028bfffbccSCorey Minyard switch (val) { 11038bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11048bfffbccSCorey Minyard break; 11058bfffbccSCorey Minyard 11068bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11078bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1); 11088bfffbccSCorey Minyard break; 11098bfffbccSCorey Minyard 11108bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11118bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1); 11128bfffbccSCorey Minyard break; 11138bfffbccSCorey Minyard 11148bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11158bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1); 11168bfffbccSCorey Minyard break; 11178bfffbccSCorey Minyard 11188bfffbccSCorey Minyard default: 11198bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 11208bfffbccSCorey Minyard } 11218bfffbccSCorey Minyard if (rsp[2]) { 11228bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1123d13ada5dSCédric Le Goater return; 11248bfffbccSCorey Minyard } 11258bfffbccSCorey Minyard 11268bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11278bfffbccSCorey Minyard switch (val) { 11288bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11298bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11308bfffbccSCorey Minyard break; 11318bfffbccSCorey Minyard 11328bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11338bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11348bfffbccSCorey Minyard /* NMI not supported. */ 11358bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1136d13ada5dSCédric Le Goater return; 11378bfffbccSCorey Minyard } 113837eebb86SCorey Minyard break; 113937eebb86SCorey Minyard 11408bfffbccSCorey Minyard default: 11418bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11428bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1143d13ada5dSCédric Le Goater return; 11448bfffbccSCorey Minyard } 11458bfffbccSCorey Minyard 11468bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11478bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11488bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11498bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 11508bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 11518bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 11528bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 11538bfffbccSCorey Minyard do_watchdog_reset(ibs); 11548bfffbccSCorey Minyard } else { 11558bfffbccSCorey Minyard ibs->watchdog_running = 0; 11568bfffbccSCorey Minyard } 11578bfffbccSCorey Minyard } 11588bfffbccSCorey Minyard 11598bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 11608bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11618bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11628bfffbccSCorey Minyard unsigned int max_rsp_len) 11638bfffbccSCorey Minyard { 11648bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_use); 11658bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_action); 11668bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout); 11678bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_expired); 11688bfffbccSCorey Minyard if (ibs->watchdog_running) { 11698bfffbccSCorey Minyard long timeout; 11708bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 11718bfffbccSCorey Minyard / 100000000); 11728bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(timeout & 0xff); 11738bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff); 11748bfffbccSCorey Minyard } else { 11758bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 11768bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 11778bfffbccSCorey Minyard } 11788bfffbccSCorey Minyard } 11798bfffbccSCorey Minyard 11808bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 11818bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11828bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11838bfffbccSCorey Minyard unsigned int max_rsp_len) 11848bfffbccSCorey Minyard { 11858bfffbccSCorey Minyard unsigned int i; 11868bfffbccSCorey Minyard 11878bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */ 11888bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff); 11898bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff); 11908bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 11918bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 11928bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 11938bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]); 11948bfffbccSCorey Minyard } 11958bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 11968bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]); 11978bfffbccSCorey Minyard } 11988bfffbccSCorey Minyard /* Only modal support, reserve supported */ 11998bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22); 12008bfffbccSCorey Minyard } 12018bfffbccSCorey Minyard 12028bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 12038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12048bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12058bfffbccSCorey Minyard unsigned int max_rsp_len) 12068bfffbccSCorey Minyard { 12078bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff); 12088bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff); 12098bfffbccSCorey Minyard } 12108bfffbccSCorey Minyard 12118bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 12128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12138bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12148bfffbccSCorey Minyard unsigned int max_rsp_len) 12158bfffbccSCorey Minyard { 12168bfffbccSCorey Minyard unsigned int pos; 12178bfffbccSCorey Minyard uint16_t nextrec; 1218a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 12198bfffbccSCorey Minyard 12208bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 12218bfffbccSCorey Minyard if (cmd[6]) { 12228bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 12238bfffbccSCorey Minyard } 12248bfffbccSCorey Minyard pos = 0; 12258bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 12268bfffbccSCorey Minyard &pos, &nextrec)) { 12278bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1228d13ada5dSCédric Le Goater return; 12298bfffbccSCorey Minyard } 1230a2295f0aSCédric Le Goater 1231a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1232a2295f0aSCédric Le Goater 1233a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 12348bfffbccSCorey Minyard rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; 1235d13ada5dSCédric Le Goater return; 12368bfffbccSCorey Minyard } 12378bfffbccSCorey Minyard 12388bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(nextrec & 0xff); 12398bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); 12408bfffbccSCorey Minyard 12418bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1242a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 12438bfffbccSCorey Minyard } 12448bfffbccSCorey Minyard 12458bfffbccSCorey Minyard if ((cmd[7] + *rsp_len) > max_rsp_len) { 12468bfffbccSCorey Minyard rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 1247d13ada5dSCédric Le Goater return; 12488bfffbccSCorey Minyard } 12498bfffbccSCorey Minyard memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 12508bfffbccSCorey Minyard *rsp_len += cmd[7]; 12518bfffbccSCorey Minyard } 12528bfffbccSCorey Minyard 12538bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 12548bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12558bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12568bfffbccSCorey Minyard unsigned int max_rsp_len) 12578bfffbccSCorey Minyard { 12588bfffbccSCorey Minyard uint16_t recid; 1259a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 12608bfffbccSCorey Minyard 1261a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 12628bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1263d13ada5dSCédric Le Goater return; 12648bfffbccSCorey Minyard } 12658bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(recid & 0xff); 12668bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((recid >> 8) & 0xff); 12678bfffbccSCorey Minyard } 12688bfffbccSCorey Minyard 12698bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 12708bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12718bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12728bfffbccSCorey Minyard unsigned int max_rsp_len) 12738bfffbccSCorey Minyard { 12748bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 12758bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 12768bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 12778bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1278d13ada5dSCédric Le Goater return; 12798bfffbccSCorey Minyard } 12808bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 12818bfffbccSCorey Minyard ibs->sdr.next_free = 0; 12828bfffbccSCorey Minyard ibs->sdr.overflow = 0; 12838bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 12848bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 12858bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 12868bfffbccSCorey Minyard } else if (cmd[7] == 0) { 12878bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 12888bfffbccSCorey Minyard } else { 12898bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 12908bfffbccSCorey Minyard return; 12918bfffbccSCorey Minyard } 1292d13ada5dSCédric Le Goater } 12938bfffbccSCorey Minyard 12948bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 12958bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12968bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12978bfffbccSCorey Minyard unsigned int max_rsp_len) 12988bfffbccSCorey Minyard { 12998bfffbccSCorey Minyard unsigned int i, val; 13008bfffbccSCorey Minyard 13018bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */ 13028bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff); 13038bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff); 13048bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 13058bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 13068bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 13078bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 13088bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]); 13098bfffbccSCorey Minyard } 13108bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 13118bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]); 13128bfffbccSCorey Minyard } 13138bfffbccSCorey Minyard /* Only support Reserve SEL */ 13148bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); 13158bfffbccSCorey Minyard } 13168bfffbccSCorey Minyard 13178bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 13188bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13198bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13208bfffbccSCorey Minyard unsigned int max_rsp_len) 13218bfffbccSCorey Minyard { 13228bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff); 13238bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff); 13248bfffbccSCorey Minyard } 13258bfffbccSCorey Minyard 13268bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 13278bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13288bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13298bfffbccSCorey Minyard unsigned int max_rsp_len) 13308bfffbccSCorey Minyard { 13318bfffbccSCorey Minyard unsigned int val; 13328bfffbccSCorey Minyard 13338bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 13348bfffbccSCorey Minyard if (cmd[6]) { 13358bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 13368bfffbccSCorey Minyard } 13378bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 13388bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1339d13ada5dSCédric Le Goater return; 13408bfffbccSCorey Minyard } 13418bfffbccSCorey Minyard if (cmd[6] > 15) { 13428bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1343d13ada5dSCédric Le Goater return; 13448bfffbccSCorey Minyard } 13458bfffbccSCorey Minyard if (cmd[7] == 0xff) { 13468bfffbccSCorey Minyard cmd[7] = 16; 13478bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 13488bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1349d13ada5dSCédric Le Goater return; 13508bfffbccSCorey Minyard } else { 13518bfffbccSCorey Minyard cmd[7] += cmd[6]; 13528bfffbccSCorey Minyard } 13538bfffbccSCorey Minyard 13548bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 13558bfffbccSCorey Minyard if (val == 0xffff) { 13568bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 13578bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 13588bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1359d13ada5dSCédric Le Goater return; 13608bfffbccSCorey Minyard } 13618bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 13628bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 13638bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 13648bfffbccSCorey Minyard } else { 13658bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val + 1) & 0xff); 13668bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff); 13678bfffbccSCorey Minyard } 13688bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 13698bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]); 13708bfffbccSCorey Minyard } 13718bfffbccSCorey Minyard } 13728bfffbccSCorey Minyard 13738bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 13748bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13758bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13768bfffbccSCorey Minyard unsigned int max_rsp_len) 13778bfffbccSCorey Minyard { 13788bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(18); 13798bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 13808bfffbccSCorey Minyard rsp[2] = IPMI_CC_OUT_OF_SPACE; 1381d13ada5dSCédric Le Goater return; 13828bfffbccSCorey Minyard } 13838bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 13848bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[2]); 13858bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[3]); 13868bfffbccSCorey Minyard } 13878bfffbccSCorey Minyard 13888bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 13898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13908bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13918bfffbccSCorey Minyard unsigned int max_rsp_len) 13928bfffbccSCorey Minyard { 13938bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 13948bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 13958bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13968bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1397d13ada5dSCédric Le Goater return; 13988bfffbccSCorey Minyard } 13998bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 14008bfffbccSCorey Minyard ibs->sel.next_free = 0; 14018bfffbccSCorey Minyard ibs->sel.overflow = 0; 14028bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 14038bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 14048bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 14058bfffbccSCorey Minyard } else if (cmd[7] == 0) { 14068bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 14078bfffbccSCorey Minyard } else { 14088bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 14098bfffbccSCorey Minyard return; 14108bfffbccSCorey Minyard } 1411d13ada5dSCédric Le Goater } 14128bfffbccSCorey Minyard 14138bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 14148bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14158bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14168bfffbccSCorey Minyard unsigned int max_rsp_len) 14178bfffbccSCorey Minyard { 14188bfffbccSCorey Minyard uint32_t val; 14198bfffbccSCorey Minyard struct ipmi_time now; 14208bfffbccSCorey Minyard 14218bfffbccSCorey Minyard ipmi_gettime(&now); 14228bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 14238bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 14248bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 14258bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 16) & 0xff); 14268bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 24) & 0xff); 14278bfffbccSCorey Minyard } 14288bfffbccSCorey Minyard 14298bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 14308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14318bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14328bfffbccSCorey Minyard unsigned int max_rsp_len) 14338bfffbccSCorey Minyard { 14348bfffbccSCorey Minyard uint32_t val; 14358bfffbccSCorey Minyard struct ipmi_time now; 14368bfffbccSCorey Minyard 14378bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(6); 14388bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 14398bfffbccSCorey Minyard ipmi_gettime(&now); 14408bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 14418bfffbccSCorey Minyard } 14428bfffbccSCorey Minyard 14438bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 14448bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14458bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14468bfffbccSCorey Minyard unsigned int max_rsp_len) 14478bfffbccSCorey Minyard { 14488bfffbccSCorey Minyard IPMISensor *sens; 14498bfffbccSCorey Minyard 14508bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 1451*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 14528bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14538bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1454d13ada5dSCédric Le Goater return; 14558bfffbccSCorey Minyard } 14568bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14578bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 14588bfffbccSCorey Minyard case 0: /* Do not change */ 14598bfffbccSCorey Minyard break; 14608bfffbccSCorey Minyard case 1: /* Enable bits */ 14618bfffbccSCorey Minyard if (cmd_len > 4) { 14628bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 14638bfffbccSCorey Minyard } 14648bfffbccSCorey Minyard if (cmd_len > 5) { 14658bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 14668bfffbccSCorey Minyard } 14678bfffbccSCorey Minyard if (cmd_len > 6) { 14688bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 14698bfffbccSCorey Minyard } 14708bfffbccSCorey Minyard if (cmd_len > 7) { 14718bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 14728bfffbccSCorey Minyard } 14738bfffbccSCorey Minyard break; 14748bfffbccSCorey Minyard case 2: /* Disable bits */ 14758bfffbccSCorey Minyard if (cmd_len > 4) { 14768bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 14778bfffbccSCorey Minyard } 14788bfffbccSCorey Minyard if (cmd_len > 5) { 14798bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 14808bfffbccSCorey Minyard } 14818bfffbccSCorey Minyard if (cmd_len > 6) { 14828bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 14838bfffbccSCorey Minyard } 14848bfffbccSCorey Minyard if (cmd_len > 7) { 14858bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 14868bfffbccSCorey Minyard } 14878bfffbccSCorey Minyard break; 14888bfffbccSCorey Minyard case 3: 14898bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1490d13ada5dSCédric Le Goater return; 14918bfffbccSCorey Minyard } 14928bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 14938bfffbccSCorey Minyard } 14948bfffbccSCorey Minyard 14958bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 14968bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14978bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14988bfffbccSCorey Minyard unsigned int max_rsp_len) 14998bfffbccSCorey Minyard { 15008bfffbccSCorey Minyard IPMISensor *sens; 15018bfffbccSCorey Minyard 15028bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 1503*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15048bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15058bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1506d13ada5dSCédric Le Goater return; 15078bfffbccSCorey Minyard } 15088bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15098bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 15108bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff); 15118bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff); 15128bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff); 15138bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff); 15148bfffbccSCorey Minyard } 15158bfffbccSCorey Minyard 15168bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 15178bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 15188bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 15198bfffbccSCorey Minyard unsigned int max_rsp_len) 15208bfffbccSCorey Minyard { 15218bfffbccSCorey Minyard IPMISensor *sens; 15228bfffbccSCorey Minyard 15238bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 1524*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15258bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15268bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1527d13ada5dSCédric Le Goater return; 15288bfffbccSCorey Minyard } 15298bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15308bfffbccSCorey Minyard 15318bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 15328bfffbccSCorey Minyard /* Just clear everything */ 15338bfffbccSCorey Minyard sens->states = 0; 15348bfffbccSCorey Minyard return; 15358bfffbccSCorey Minyard } 1536d13ada5dSCédric Le Goater } 15378bfffbccSCorey Minyard 15388bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 15398bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 15408bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 15418bfffbccSCorey Minyard unsigned int max_rsp_len) 15428bfffbccSCorey Minyard { 15438bfffbccSCorey Minyard IPMISensor *sens; 15448bfffbccSCorey Minyard 15458bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 1546*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15478bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15488bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1549d13ada5dSCédric Le Goater return; 15508bfffbccSCorey Minyard } 15518bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15528bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 15538bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 15548bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_states & 0xff); 15558bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff); 15568bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff); 15578bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff); 15588bfffbccSCorey Minyard } 15598bfffbccSCorey Minyard 15608bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 15618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 15628bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 15638bfffbccSCorey Minyard unsigned int max_rsp_len) 15648bfffbccSCorey Minyard { 15658bfffbccSCorey Minyard IPMISensor *sens; 15668bfffbccSCorey Minyard 15678bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 1568*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15698bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15708bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1571d13ada5dSCédric Le Goater return; 15728bfffbccSCorey Minyard } 15738bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15748bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 15758bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 15768bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->states & 0xff); 15778bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 15788bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff); 15798bfffbccSCorey Minyard } 15808bfffbccSCorey Minyard } 15818bfffbccSCorey Minyard 1582728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1583728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1584728710e1SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 1585728710e1SCédric Le Goater unsigned int max_rsp_len) 1586728710e1SCédric Le Goater { 1587728710e1SCédric Le Goater IPMISensor *sens; 1588728710e1SCédric Le Goater 1589728710e1SCédric Le Goater 1590728710e1SCédric Le Goater IPMI_CHECK_CMD_LEN(5); 1591*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1592728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1593728710e1SCédric Le Goater rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1594728710e1SCédric Le Goater return; 1595728710e1SCédric Le Goater } 1596728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1597728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1598728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1599728710e1SCédric Le Goater } 1600728710e1SCédric Le Goater 1601728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1602728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1603728710e1SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 1604728710e1SCédric Le Goater unsigned int max_rsp_len) 1605728710e1SCédric Le Goater { 1606728710e1SCédric Le Goater IPMISensor *sens; 1607728710e1SCédric Le Goater 1608728710e1SCédric Le Goater 1609728710e1SCédric Le Goater IPMI_CHECK_CMD_LEN(3); 1610*73d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1611728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1612728710e1SCédric Le Goater rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1613728710e1SCédric Le Goater return; 1614728710e1SCédric Le Goater } 1615728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1616728710e1SCédric Le Goater IPMI_ADD_RSP_DATA(sens->sensor_type); 1617728710e1SCédric Le Goater IPMI_ADD_RSP_DATA(sens->evt_reading_type_code); 1618728710e1SCédric Le Goater } 1619728710e1SCédric Le Goater 1620728710e1SCédric Le Goater 162162a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 16228bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, 16238bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, 1624b7088392SCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = chassis_control, 1625b7088392SCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = chassis_get_sys_restart_cause 16268bfffbccSCorey Minyard }; 16278bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 162862a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 16298bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 16308bfffbccSCorey Minyard }; 16318bfffbccSCorey Minyard 163262a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 16338bfffbccSCorey Minyard [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable, 16348bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable, 16358bfffbccSCorey Minyard [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts, 16368bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status, 1637728710e1SCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading, 1638728710e1SCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = set_sensor_type, 1639728710e1SCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = get_sensor_type, 16408bfffbccSCorey Minyard }; 16418bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 164262a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 16438bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 16448bfffbccSCorey Minyard }; 16458bfffbccSCorey Minyard 164662a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 16478bfffbccSCorey Minyard [IPMI_CMD_GET_DEVICE_ID] = get_device_id, 16488bfffbccSCorey Minyard [IPMI_CMD_COLD_RESET] = cold_reset, 16498bfffbccSCorey Minyard [IPMI_CMD_WARM_RESET] = warm_reset, 165052ba4d50SCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = set_acpi_power_state, 165152ba4d50SCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = get_acpi_power_state, 165252ba4d50SCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = get_device_guid, 16538bfffbccSCorey Minyard [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables, 16548bfffbccSCorey Minyard [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables, 16558bfffbccSCorey Minyard [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags, 16568bfffbccSCorey Minyard [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags, 16578bfffbccSCorey Minyard [IPMI_CMD_GET_MSG] = get_msg, 16588bfffbccSCorey Minyard [IPMI_CMD_SEND_MSG] = send_msg, 16598bfffbccSCorey Minyard [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf, 16608bfffbccSCorey Minyard [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer, 16618bfffbccSCorey Minyard [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer, 16628bfffbccSCorey Minyard [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer, 16638bfffbccSCorey Minyard }; 16648bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 166562a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 16668bfffbccSCorey Minyard .cmd_handlers = app_cmds 16678bfffbccSCorey Minyard }; 16688bfffbccSCorey Minyard 166962a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 16708bfffbccSCorey Minyard [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info, 16718bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep, 16728bfffbccSCorey Minyard [IPMI_CMD_GET_SDR] = get_sdr, 16738bfffbccSCorey Minyard [IPMI_CMD_ADD_SDR] = add_sdr, 16748bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep, 16758bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_INFO] = get_sel_info, 16768bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SEL] = reserve_sel, 16778bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry, 16788bfffbccSCorey Minyard [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry, 16798bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SEL] = clear_sel, 16808bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_TIME] = get_sel_time, 16818bfffbccSCorey Minyard [IPMI_CMD_SET_SEL_TIME] = set_sel_time, 16828bfffbccSCorey Minyard }; 16838bfffbccSCorey Minyard 16848bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 168562a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 16868bfffbccSCorey Minyard .cmd_handlers = storage_cmds 16878bfffbccSCorey Minyard }; 16888bfffbccSCorey Minyard 16898bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 16908bfffbccSCorey Minyard { 16918bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 16928bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 16938bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 16948bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 16958bfffbccSCorey Minyard } 16968bfffbccSCorey Minyard 16978bfffbccSCorey Minyard static const uint8_t init_sdrs[] = { 16988bfffbccSCorey Minyard /* Watchdog device */ 16998bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 17008bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 17018bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17028bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 17038bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 17048bfffbccSCorey Minyard /* End */ 17058bfffbccSCorey Minyard 0xff, 0xff, 0x00, 0x00, 0x00 17068bfffbccSCorey Minyard }; 17078bfffbccSCorey Minyard 1708bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1709bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1710bd66bcfcSCorey Minyard .version_id = 1, 1711bd66bcfcSCorey Minyard .minimum_version_id = 1, 1712bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1713bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1714bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1715bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1716bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1717bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1718bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1719bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1720bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1721bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1722bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1723bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1724bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1725bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1726bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1727bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1728bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1729bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1730bd66bcfcSCorey Minyard IPMIBmcSim), 1731bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1732bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1733bd66bcfcSCorey Minyard } 1734bd66bcfcSCorey Minyard }; 1735bd66bcfcSCorey Minyard 17368bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj) 17378bfffbccSCorey Minyard { 17388bfffbccSCorey Minyard IPMIBmc *b = IPMI_BMC(obj); 17398bfffbccSCorey Minyard unsigned int i; 17408bfffbccSCorey Minyard unsigned int recid; 17418bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 17428bfffbccSCorey Minyard 17438bfffbccSCorey Minyard qemu_mutex_init(&ibs->lock); 17448bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 17458bfffbccSCorey Minyard 17468bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 17478bfffbccSCorey Minyard ibs->device_id = 0x20; 17488bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1749b7088392SCédric Le Goater ibs->restart_cause = 0; 17508bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 17518bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 17528bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 17538bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 17548bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 17558bfffbccSCorey Minyard } 17568bfffbccSCorey Minyard 17578bfffbccSCorey Minyard for (i = 0;;) { 1758a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 17598bfffbccSCorey Minyard int len; 1760a2295f0aSCédric Le Goater if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) { 17617cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 17628bfffbccSCorey Minyard return; 17638bfffbccSCorey Minyard } 1764a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &init_sdrs[i]; 1765a2295f0aSCédric Le Goater len = ipmi_sdr_length(sdrh); 1766a2295f0aSCédric Le Goater recid = ipmi_sdr_recid(sdrh); 17678bfffbccSCorey Minyard if (recid == 0xffff) { 17688bfffbccSCorey Minyard break; 17698bfffbccSCorey Minyard } 1770792afddbSCédric Le Goater if ((i + len) > sizeof(init_sdrs)) { 17717cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 17728bfffbccSCorey Minyard return; 17738bfffbccSCorey Minyard } 1774a2295f0aSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 1775792afddbSCédric Le Goater i += len; 17768bfffbccSCorey Minyard } 17778bfffbccSCorey Minyard 177852ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 177952ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 178052ba4d50SCédric Le Goater 178152ba4d50SCédric Le Goater if (qemu_uuid_set) { 178252ba4d50SCédric Le Goater memcpy(&ibs->uuid, qemu_uuid, 16); 178352ba4d50SCédric Le Goater } else { 178452ba4d50SCédric Le Goater memset(&ibs->uuid, 0, 16); 178552ba4d50SCédric Le Goater } 178652ba4d50SCédric Le Goater 17878bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 17888bfffbccSCorey Minyard register_cmds(ibs); 17898bfffbccSCorey Minyard 17908bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1791bd66bcfcSCorey Minyard 1792bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 17938bfffbccSCorey Minyard } 17948bfffbccSCorey Minyard 17958bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 17968bfffbccSCorey Minyard { 17978bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 17988bfffbccSCorey Minyard 17998bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 18008bfffbccSCorey Minyard } 18018bfffbccSCorey Minyard 18028bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 18038bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 18048bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 18058bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 18068bfffbccSCorey Minyard .instance_init = ipmi_sim_init, 18078bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 18088bfffbccSCorey Minyard }; 18098bfffbccSCorey Minyard 18108bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 18118bfffbccSCorey Minyard { 18128bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 18138bfffbccSCorey Minyard } 18148bfffbccSCorey Minyard 18158bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1816