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" 268bfffbccSCorey Minyard #include "qemu/timer.h" 278bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 288bfffbccSCorey Minyard #include "qemu/error-report.h" 298bfffbccSCorey Minyard 308bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 318bfffbccSCorey Minyard 328bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 338bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 348bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 358bfffbccSCorey Minyard 368bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 378bfffbccSCorey Minyard 388bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 398bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 408bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 418bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 438bfffbccSCorey Minyard 448bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 458bfffbccSCorey Minyard 468bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 478bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 488bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 498bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 508bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 518bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 528bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 538bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 548bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 558bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 568bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 578bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 588bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 598bfffbccSCorey Minyard 608bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 618bfffbccSCorey Minyard 628bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 638bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 648bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 658bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 668bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 678bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 688bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 698bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 718bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 728bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 738bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 748bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 758bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 768bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 778bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 788bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 798bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 808bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 818bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 828bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 848bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 858bfffbccSCorey Minyard 868bfffbccSCorey Minyard 878bfffbccSCorey Minyard /* Same as a timespec struct. */ 888bfffbccSCorey Minyard struct ipmi_time { 898bfffbccSCorey Minyard long tv_sec; 908bfffbccSCorey Minyard long tv_nsec; 918bfffbccSCorey Minyard }; 928bfffbccSCorey Minyard 938bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 948bfffbccSCorey Minyard 958bfffbccSCorey Minyard typedef struct IPMISel { 968bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 978bfffbccSCorey Minyard unsigned int next_free; 988bfffbccSCorey Minyard long time_offset; 998bfffbccSCorey Minyard uint16_t reservation; 1008bfffbccSCorey Minyard uint8_t last_addition[4]; 1018bfffbccSCorey Minyard uint8_t last_clear[4]; 1028bfffbccSCorey Minyard uint8_t overflow; 1038bfffbccSCorey Minyard } IPMISel; 1048bfffbccSCorey Minyard 1058bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1068bfffbccSCorey Minyard 1078bfffbccSCorey Minyard typedef struct IPMISdr { 1088bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1098bfffbccSCorey Minyard unsigned int next_free; 1108bfffbccSCorey Minyard uint16_t next_rec_id; 1118bfffbccSCorey Minyard uint16_t reservation; 1128bfffbccSCorey Minyard uint8_t last_addition[4]; 1138bfffbccSCorey Minyard uint8_t last_clear[4]; 1148bfffbccSCorey Minyard uint8_t overflow; 1158bfffbccSCorey Minyard } IPMISdr; 1168bfffbccSCorey Minyard 1178bfffbccSCorey Minyard typedef struct IPMISensor { 1188bfffbccSCorey Minyard uint8_t status; 1198bfffbccSCorey Minyard uint8_t reading; 1208bfffbccSCorey Minyard uint16_t states_suppt; 1218bfffbccSCorey Minyard uint16_t assert_suppt; 1228bfffbccSCorey Minyard uint16_t deassert_suppt; 1238bfffbccSCorey Minyard uint16_t states; 1248bfffbccSCorey Minyard uint16_t assert_states; 1258bfffbccSCorey Minyard uint16_t deassert_states; 1268bfffbccSCorey Minyard uint16_t assert_enable; 1278bfffbccSCorey Minyard uint16_t deassert_enable; 1288bfffbccSCorey Minyard uint8_t sensor_type; 1298bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1308bfffbccSCorey Minyard } IPMISensor; 1318bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1328bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1338bfffbccSCorey Minyard !!(v)) 1348bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1358bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1368bfffbccSCorey Minyard ((!!(v)) << 6)) 1378bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1388bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1398bfffbccSCorey Minyard ((!!(v)) << 7)) 1408bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1418bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1428bfffbccSCorey Minyard (v & 0xc0)) 1438bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1448bfffbccSCorey Minyard 1458bfffbccSCorey Minyard #define MAX_SENSORS 20 1468bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1478bfffbccSCorey Minyard 1488bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 1498bfffbccSCorey Minyard 1508bfffbccSCorey Minyard #define MAX_NETFNS 64 1518bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s, 1528bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1538bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1548bfffbccSCorey Minyard unsigned int max_rsp_len); 1558bfffbccSCorey Minyard typedef struct IPMINetfn { 1568bfffbccSCorey Minyard unsigned int cmd_nums; 1578bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1588bfffbccSCorey Minyard } IPMINetfn; 1598bfffbccSCorey Minyard 1608bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1618bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1628bfffbccSCorey Minyard uint8_t len; 1638bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1648bfffbccSCorey Minyard } IPMIRcvBufEntry; 1658bfffbccSCorey Minyard 1668bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1678bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1688bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1698bfffbccSCorey Minyard struct IPMIBmcSim { 1708bfffbccSCorey Minyard IPMIBmc parent; 1718bfffbccSCorey Minyard 1728bfffbccSCorey Minyard QEMUTimer *timer; 1738bfffbccSCorey Minyard 1748bfffbccSCorey Minyard uint8_t bmc_global_enables; 1758bfffbccSCorey Minyard uint8_t msg_flags; 1768bfffbccSCorey Minyard 1778bfffbccSCorey Minyard bool watchdog_initialized; 1788bfffbccSCorey Minyard uint8_t watchdog_use; 1798bfffbccSCorey Minyard uint8_t watchdog_action; 1808bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 1818bfffbccSCorey Minyard bool watchdog_expired; 1828bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 1838bfffbccSCorey Minyard 1848bfffbccSCorey Minyard bool watchdog_running; 1858bfffbccSCorey Minyard bool watchdog_preaction_ran; 1868bfffbccSCorey Minyard int64_t watchdog_expiry; 1878bfffbccSCorey Minyard 1888bfffbccSCorey Minyard uint8_t device_id; 1898bfffbccSCorey Minyard uint8_t ipmi_version; 1908bfffbccSCorey Minyard uint8_t device_rev; 1918bfffbccSCorey Minyard uint8_t fwrev1; 1928bfffbccSCorey Minyard uint8_t fwrev2; 1938bfffbccSCorey Minyard uint8_t mfg_id[3]; 1948bfffbccSCorey Minyard uint8_t product_id[2]; 1958bfffbccSCorey Minyard 1968bfffbccSCorey Minyard IPMISel sel; 1978bfffbccSCorey Minyard IPMISdr sdr; 1988bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 1998bfffbccSCorey Minyard 2008bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2018bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2028bfffbccSCorey Minyard 2038bfffbccSCorey Minyard QemuMutex lock; 2048bfffbccSCorey Minyard /* We allow one event in the buffer */ 2058bfffbccSCorey Minyard uint8_t evtbuf[16]; 2068bfffbccSCorey Minyard 2078bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2088bfffbccSCorey Minyard }; 2098bfffbccSCorey Minyard 2108bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2118bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2128bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2138bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2148bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2158bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2168bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2178bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2188bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2198bfffbccSCorey Minyard 2208bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2218bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2228bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2238bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2248bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2258bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2268bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2278bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2288bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2298bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2308bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2318bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2328bfffbccSCorey Minyard 2338bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2348bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2358bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2368bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2378bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2388bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2398bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2408bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2418bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2428bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2438bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2448bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2458bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2468bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2478bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2488bfffbccSCorey Minyard 2498bfffbccSCorey Minyard 2508bfffbccSCorey Minyard /* Add a byte to the response. */ 2518bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \ 2528bfffbccSCorey Minyard do { \ 2538bfffbccSCorey Minyard if (*rsp_len >= max_rsp_len) { \ 2548bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \ 255d13ada5dSCédric Le Goater return; \ 2568bfffbccSCorey Minyard } \ 2578bfffbccSCorey Minyard rsp[(*rsp_len)++] = (b); \ 2588bfffbccSCorey Minyard } while (0) 2598bfffbccSCorey Minyard 2608bfffbccSCorey Minyard /* Verify that the received command is a certain length. */ 2618bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \ 2628bfffbccSCorey Minyard if (cmd_len < l) { \ 2638bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \ 264d13ada5dSCédric Le Goater return; \ 2658bfffbccSCorey Minyard } 2668bfffbccSCorey Minyard 2678bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */ 2688bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \ 2698bfffbccSCorey Minyard do { \ 2708bfffbccSCorey Minyard if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \ 2718bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_RESERVATION; \ 272d13ada5dSCédric Le Goater return; \ 2738bfffbccSCorey Minyard } \ 2748bfffbccSCorey Minyard } while (0) 2758bfffbccSCorey Minyard 2768bfffbccSCorey Minyard 2778bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 2788bfffbccSCorey Minyard 2798bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 2808bfffbccSCorey Minyard { 2818bfffbccSCorey Minyard int64_t stime; 2828bfffbccSCorey Minyard 2838bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 2848bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 2858bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 2868bfffbccSCorey Minyard } 2878bfffbccSCorey Minyard 2888bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 2898bfffbccSCorey Minyard { 2908bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 2918bfffbccSCorey Minyard } 2928bfffbccSCorey Minyard 2938bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 2948bfffbccSCorey Minyard { 2958bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 2968bfffbccSCorey Minyard 2978bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 2988bfffbccSCorey Minyard } 2998bfffbccSCorey Minyard 3008bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3018bfffbccSCorey Minyard { 3028bfffbccSCorey Minyard unsigned int val; 3038bfffbccSCorey Minyard struct ipmi_time now; 3048bfffbccSCorey Minyard 3058bfffbccSCorey Minyard ipmi_gettime(&now); 3068bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3078bfffbccSCorey Minyard ts[0] = val & 0xff; 3088bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3098bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3108bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3118bfffbccSCorey Minyard } 3128bfffbccSCorey Minyard 3138bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3148bfffbccSCorey Minyard { 3158bfffbccSCorey Minyard sdr->reservation++; 3168bfffbccSCorey Minyard if (sdr->reservation == 0) { 3178bfffbccSCorey Minyard sdr->reservation = 1; 3188bfffbccSCorey Minyard } 3198bfffbccSCorey Minyard } 3208bfffbccSCorey Minyard 3218bfffbccSCorey Minyard static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry, 3228bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3238bfffbccSCorey Minyard { 3248bfffbccSCorey Minyard if ((len < 5) || (len > 255)) { 3258bfffbccSCorey Minyard return 1; 3268bfffbccSCorey Minyard } 3278bfffbccSCorey Minyard 3288bfffbccSCorey Minyard if (entry[4] != len - 5) { 3298bfffbccSCorey Minyard return 1; 3308bfffbccSCorey Minyard } 3318bfffbccSCorey Minyard 3328bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3338bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3348bfffbccSCorey Minyard return 1; 3358bfffbccSCorey Minyard } 3368bfffbccSCorey Minyard 3378bfffbccSCorey Minyard memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len); 3388bfffbccSCorey Minyard ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff; 3398bfffbccSCorey Minyard ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 3408bfffbccSCorey Minyard ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */ 3418bfffbccSCorey Minyard 3428bfffbccSCorey Minyard if (recid) { 3438bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3448bfffbccSCorey Minyard } 3458bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3468bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3478bfffbccSCorey Minyard ibs->sdr.next_free += len; 3488bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3498bfffbccSCorey Minyard return 0; 3508bfffbccSCorey Minyard } 3518bfffbccSCorey Minyard 3528bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3538bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3548bfffbccSCorey Minyard { 3558bfffbccSCorey Minyard unsigned int pos = *retpos; 3568bfffbccSCorey Minyard 3578bfffbccSCorey Minyard while (pos < sdr->next_free) { 3588bfffbccSCorey Minyard uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8); 359*792afddbSCédric Le Goater unsigned int nextpos = pos + sdr->sdr[pos + 4] + 5; 3608bfffbccSCorey Minyard 3618bfffbccSCorey Minyard if (trec == recid) { 3628bfffbccSCorey Minyard if (nextrec) { 3638bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3648bfffbccSCorey Minyard *nextrec = 0xffff; 3658bfffbccSCorey Minyard } else { 3668bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3678bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3688bfffbccSCorey Minyard } 3698bfffbccSCorey Minyard } 3708bfffbccSCorey Minyard *retpos = pos; 3718bfffbccSCorey Minyard return 0; 3728bfffbccSCorey Minyard } 3738bfffbccSCorey Minyard pos = nextpos; 3748bfffbccSCorey Minyard } 3758bfffbccSCorey Minyard return 1; 3768bfffbccSCorey Minyard } 3778bfffbccSCorey Minyard 3788bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 3798bfffbccSCorey Minyard { 3808bfffbccSCorey Minyard sel->reservation++; 3818bfffbccSCorey Minyard if (sel->reservation == 0) { 3828bfffbccSCorey Minyard sel->reservation = 1; 3838bfffbccSCorey Minyard } 3848bfffbccSCorey Minyard } 3858bfffbccSCorey Minyard 3868bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 3878bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 3888bfffbccSCorey Minyard { 3898bfffbccSCorey Minyard event[0] = 0xff; 3908bfffbccSCorey Minyard event[1] = 0xff; 3918bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 3928bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 3938bfffbccSCorey Minyard ibs->sel.overflow = 1; 3948bfffbccSCorey Minyard return 1; 3958bfffbccSCorey Minyard } 3968bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 3978bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 3988bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 3998bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4008bfffbccSCorey Minyard ibs->sel.next_free++; 4018bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4028bfffbccSCorey Minyard return 0; 4038bfffbccSCorey Minyard } 4048bfffbccSCorey Minyard 4058bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4068bfffbccSCorey Minyard { 4078bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4088bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4098bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4108bfffbccSCorey Minyard } 4118bfffbccSCorey Minyard 4128bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4138bfffbccSCorey Minyard { 4148bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4158bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4168bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4178bfffbccSCorey Minyard } 4188bfffbccSCorey Minyard 4198bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4208bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4218bfffbccSCorey Minyard { 4228bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4238bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4248bfffbccSCorey Minyard uint8_t evt[16]; 4258bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4268bfffbccSCorey Minyard 4278bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4288bfffbccSCorey Minyard return; 4298bfffbccSCorey Minyard } 4308bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4318bfffbccSCorey Minyard return; 4328bfffbccSCorey Minyard } 4338bfffbccSCorey Minyard 4348bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4358bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4368bfffbccSCorey Minyard evt[8] = 0; 4378bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4388bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4398bfffbccSCorey Minyard evt[11] = sens_num; 4408bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4418bfffbccSCorey Minyard evt[13] = evd1; 4428bfffbccSCorey Minyard evt[14] = evd2; 4438bfffbccSCorey Minyard evt[15] = evd3; 4448bfffbccSCorey Minyard 4458bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 4468bfffbccSCorey Minyard sel_add_event(ibs, evt); 4478bfffbccSCorey Minyard } 4488bfffbccSCorey Minyard 4498bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 450d13ada5dSCédric Le Goater return; 4518bfffbccSCorey Minyard } 4528bfffbccSCorey Minyard 4538bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 4548bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 4558bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 4568bfffbccSCorey Minyard } 4578bfffbccSCorey Minyard 4588bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 4598bfffbccSCorey Minyard unsigned int bit, unsigned int val, 4608bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4618bfffbccSCorey Minyard { 4628bfffbccSCorey Minyard IPMISensor *sens; 4638bfffbccSCorey Minyard uint16_t mask; 4648bfffbccSCorey Minyard 4658bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 4668bfffbccSCorey Minyard return; 4678bfffbccSCorey Minyard } 4688bfffbccSCorey Minyard if (bit >= 16) { 4698bfffbccSCorey Minyard return; 4708bfffbccSCorey Minyard } 4718bfffbccSCorey Minyard 4728bfffbccSCorey Minyard mask = (1 << bit); 4738bfffbccSCorey Minyard sens = ibs->sensors + sensor; 4748bfffbccSCorey Minyard if (val) { 4758bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 4768bfffbccSCorey Minyard if (sens->assert_states & mask) { 4778bfffbccSCorey Minyard return; /* Already asserted */ 4788bfffbccSCorey Minyard } 4798bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 4808bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 4818bfffbccSCorey Minyard /* Send an event on assert */ 4828bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 4838bfffbccSCorey Minyard } 4848bfffbccSCorey Minyard } else { 4858bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 4868bfffbccSCorey Minyard if (sens->deassert_states & mask) { 4878bfffbccSCorey Minyard return; /* Already deasserted */ 4888bfffbccSCorey Minyard } 4898bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 4908bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 4918bfffbccSCorey Minyard /* Send an event on deassert */ 4928bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 4938bfffbccSCorey Minyard } 4948bfffbccSCorey Minyard } 4958bfffbccSCorey Minyard } 4968bfffbccSCorey Minyard 4978bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 4988bfffbccSCorey Minyard { 4998bfffbccSCorey Minyard unsigned int i, pos; 5008bfffbccSCorey Minyard IPMISensor *sens; 5018bfffbccSCorey Minyard 5028bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5038bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5048bfffbccSCorey Minyard } 5058bfffbccSCorey Minyard 5068bfffbccSCorey Minyard pos = 0; 5078bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 5088bfffbccSCorey Minyard uint8_t *sdr = s->sdr.sdr + pos; 5098bfffbccSCorey Minyard unsigned int len = sdr[4]; 5108bfffbccSCorey Minyard 5118bfffbccSCorey Minyard if (len < 20) { 5128bfffbccSCorey Minyard continue; 5138bfffbccSCorey Minyard } 5148bfffbccSCorey Minyard if ((sdr[3] < 1) || (sdr[3] > 2)) { 5158bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5168bfffbccSCorey Minyard } 5178bfffbccSCorey Minyard 5188bfffbccSCorey Minyard if (sdr[7] > MAX_SENSORS) { 5198bfffbccSCorey Minyard continue; 5208bfffbccSCorey Minyard } 5218bfffbccSCorey Minyard sens = s->sensors + sdr[7]; 5228bfffbccSCorey Minyard 5238bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 5248bfffbccSCorey Minyard IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1); 5258bfffbccSCorey Minyard IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1); 5268bfffbccSCorey Minyard sens->assert_suppt = sdr[14] | (sdr[15] << 8); 5278bfffbccSCorey Minyard sens->deassert_suppt = sdr[16] | (sdr[17] << 8); 5288bfffbccSCorey Minyard sens->states_suppt = sdr[18] | (sdr[19] << 8); 5298bfffbccSCorey Minyard sens->sensor_type = sdr[12]; 5308bfffbccSCorey Minyard sens->evt_reading_type_code = sdr[13] & 0x7f; 5318bfffbccSCorey Minyard 5328bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5338bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5348bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5358bfffbccSCorey Minyard } 5368bfffbccSCorey Minyard } 5378bfffbccSCorey Minyard 5388bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5398bfffbccSCorey Minyard const IPMINetfn *netfnd) 5408bfffbccSCorey Minyard { 5418bfffbccSCorey Minyard if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) { 5428bfffbccSCorey Minyard return -1; 5438bfffbccSCorey Minyard } 5448bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 5458bfffbccSCorey Minyard return 0; 5468bfffbccSCorey Minyard } 5478bfffbccSCorey Minyard 5488bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 5498bfffbccSCorey Minyard { 5508bfffbccSCorey Minyard int64_t next; 5518bfffbccSCorey Minyard if (ibs->watchdog_running) { 5528bfffbccSCorey Minyard next = ibs->watchdog_expiry; 5538bfffbccSCorey Minyard } else { 5548bfffbccSCorey Minyard /* Wait a minute */ 5558bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 5568bfffbccSCorey Minyard } 5578bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 5588bfffbccSCorey Minyard } 5598bfffbccSCorey Minyard 5608bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 5618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 5628bfffbccSCorey Minyard unsigned int max_cmd_len, 5638bfffbccSCorey Minyard uint8_t msg_id) 5648bfffbccSCorey Minyard { 5658bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 5668bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 5678bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 5688bfffbccSCorey Minyard unsigned int netfn; 5698bfffbccSCorey Minyard uint8_t rsp[MAX_IPMI_MSG_SIZE]; 5708bfffbccSCorey Minyard unsigned int rsp_len_holder = 0; 5718bfffbccSCorey Minyard unsigned int *rsp_len = &rsp_len_holder; 5728bfffbccSCorey Minyard unsigned int max_rsp_len = sizeof(rsp); 5738bfffbccSCorey Minyard 5748bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 5758bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 576d13ada5dSCédric Le Goater if (max_rsp_len < 3) { 577d13ada5dSCédric Le Goater rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 578d13ada5dSCédric Le Goater goto out; 579d13ada5dSCédric Le Goater } 580d13ada5dSCédric Le Goater 5818bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[0] | 0x04); 5828bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[1]); 5838bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); /* Assume success */ 5848bfffbccSCorey Minyard 5858bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 5868bfffbccSCorey Minyard if (cmd_len < 2) { 5878bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 5888bfffbccSCorey Minyard goto out; 5898bfffbccSCorey Minyard } 5908bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 5918bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 5928bfffbccSCorey Minyard goto out; 5938bfffbccSCorey Minyard } 5948bfffbccSCorey Minyard 5958bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 5968bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 5978bfffbccSCorey Minyard rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN; 5988bfffbccSCorey Minyard goto out; 5998bfffbccSCorey Minyard } 6008bfffbccSCorey Minyard 6018bfffbccSCorey Minyard netfn = cmd[0] >> 2; 6028bfffbccSCorey Minyard 6038bfffbccSCorey Minyard /* Odd netfns are not valid, make sure the command is registered */ 6048bfffbccSCorey Minyard if ((netfn & 1) || !ibs->netfns[netfn / 2] || 6058bfffbccSCorey Minyard (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) || 6068bfffbccSCorey Minyard (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) { 6078bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_CMD; 6088bfffbccSCorey Minyard goto out; 6098bfffbccSCorey Minyard } 6108bfffbccSCorey Minyard 6118bfffbccSCorey Minyard ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len, 6128bfffbccSCorey Minyard max_rsp_len); 6138bfffbccSCorey Minyard 6148bfffbccSCorey Minyard out: 6158bfffbccSCorey Minyard k->handle_rsp(s, msg_id, rsp, *rsp_len); 6168bfffbccSCorey Minyard 6178bfffbccSCorey Minyard next_timeout(ibs); 6188bfffbccSCorey Minyard } 6198bfffbccSCorey Minyard 6208bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 6218bfffbccSCorey Minyard { 6228bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6238bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6248bfffbccSCorey Minyard 6258bfffbccSCorey Minyard if (!ibs->watchdog_running) { 6268bfffbccSCorey Minyard goto out; 6278bfffbccSCorey Minyard } 6288bfffbccSCorey Minyard 6298bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 6308bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 6318bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 6328bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6338bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 6348bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6358bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 6368bfffbccSCorey Minyard break; 6378bfffbccSCorey Minyard 6388bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 6398bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6408bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 6418bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6428bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 6438bfffbccSCorey Minyard break; 6448bfffbccSCorey Minyard 6458bfffbccSCorey Minyard default: 6468bfffbccSCorey Minyard goto do_full_expiry; 6478bfffbccSCorey Minyard } 6488bfffbccSCorey Minyard 6498bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 6508bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 6518bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 6528bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 6538bfffbccSCorey Minyard goto out; 6548bfffbccSCorey Minyard } 6558bfffbccSCorey Minyard 6568bfffbccSCorey Minyard do_full_expiry: 6578bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 6588bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 6598bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 6608bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 6618bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 6628bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 6638bfffbccSCorey Minyard break; 6648bfffbccSCorey Minyard 6658bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 6668bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 6678bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 6688bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 6698bfffbccSCorey Minyard break; 6708bfffbccSCorey Minyard 6718bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 6728bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 6738bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 6748bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 6758bfffbccSCorey Minyard break; 6768bfffbccSCorey Minyard 6778bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 6788bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 6798bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 6808bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 6818bfffbccSCorey Minyard break; 6828bfffbccSCorey Minyard } 6838bfffbccSCorey Minyard 6848bfffbccSCorey Minyard out: 6858bfffbccSCorey Minyard next_timeout(ibs); 6868bfffbccSCorey Minyard } 6878bfffbccSCorey Minyard 6888bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 6898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6908bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 6918bfffbccSCorey Minyard unsigned int max_rsp_len) 6928bfffbccSCorey Minyard { 6938bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 6948bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 6958bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 6968bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 6978bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 6988bfffbccSCorey Minyard } 6998bfffbccSCorey Minyard 7008bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7018bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7028bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7038bfffbccSCorey Minyard unsigned int max_rsp_len) 7048bfffbccSCorey Minyard { 7058bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */ 7068bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7078bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7088bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7098bfffbccSCorey Minyard } 7108bfffbccSCorey Minyard 7118bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7138bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7148bfffbccSCorey Minyard unsigned int max_rsp_len) 7158bfffbccSCorey Minyard { 7168bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7178bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7188bfffbccSCorey Minyard 7198bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 7208bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7218bfffbccSCorey Minyard case 0: /* power down */ 7228bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7238bfffbccSCorey Minyard break; 7248bfffbccSCorey Minyard case 1: /* power up */ 7258bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0); 7268bfffbccSCorey Minyard break; 7278bfffbccSCorey Minyard case 2: /* power cycle */ 7288bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7298bfffbccSCorey Minyard break; 7308bfffbccSCorey Minyard case 3: /* hard reset */ 7318bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7328bfffbccSCorey Minyard break; 7338bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 7348bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0); 7358bfffbccSCorey Minyard break; 7368bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 7378bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, 7388bfffbccSCorey Minyard IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0); 7398bfffbccSCorey Minyard break; 7408bfffbccSCorey Minyard default: 7418bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 7428bfffbccSCorey Minyard return; 7438bfffbccSCorey Minyard } 744d13ada5dSCédric Le Goater } 7458bfffbccSCorey Minyard 7468bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 7478bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7488bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7498bfffbccSCorey Minyard unsigned int max_rsp_len) 7508bfffbccSCorey Minyard { 7518bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_id); 7528bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf); 7538bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f); 7548bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev2); 7558bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->ipmi_version); 7568bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */ 7578bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[0]); 7588bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[1]); 7598bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[2]); 7608bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[0]); 7618bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[1]); 7628bfffbccSCorey Minyard } 7638bfffbccSCorey Minyard 7648bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 7658bfffbccSCorey Minyard { 7668bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7678bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7688bfffbccSCorey Minyard bool irqs_on; 7698bfffbccSCorey Minyard 7708bfffbccSCorey Minyard ibs->bmc_global_enables = val; 7718bfffbccSCorey Minyard 7728bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 7738bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 7748bfffbccSCorey Minyard 7758bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 7768bfffbccSCorey Minyard } 7778bfffbccSCorey Minyard 7788bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 7798bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7808bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7818bfffbccSCorey Minyard unsigned int max_rsp_len) 7828bfffbccSCorey Minyard { 7838bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7848bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7858bfffbccSCorey Minyard 7868bfffbccSCorey Minyard /* Disable all interrupts */ 7878bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 7888bfffbccSCorey Minyard 7898bfffbccSCorey Minyard if (k->reset) { 7908bfffbccSCorey Minyard k->reset(s, true); 7918bfffbccSCorey Minyard } 7928bfffbccSCorey Minyard } 7938bfffbccSCorey Minyard 7948bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 7958bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7968bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7978bfffbccSCorey Minyard unsigned int max_rsp_len) 7988bfffbccSCorey Minyard { 7998bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8008bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8018bfffbccSCorey Minyard 8028bfffbccSCorey Minyard if (k->reset) { 8038bfffbccSCorey Minyard k->reset(s, false); 8048bfffbccSCorey Minyard } 8058bfffbccSCorey Minyard } 8068bfffbccSCorey Minyard 8078bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 8088bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8098bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8108bfffbccSCorey Minyard unsigned int max_rsp_len) 8118bfffbccSCorey Minyard { 8128bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 8138bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 8148bfffbccSCorey Minyard } 8158bfffbccSCorey Minyard 8168bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 8178bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8188bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8198bfffbccSCorey Minyard unsigned int max_rsp_len) 8208bfffbccSCorey Minyard { 8218bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->bmc_global_enables); 8228bfffbccSCorey Minyard } 8238bfffbccSCorey Minyard 8248bfffbccSCorey Minyard static void clr_msg_flags(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 IPMI_CHECK_CMD_LEN(3); 8338bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 8348bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 8358bfffbccSCorey Minyard } 8368bfffbccSCorey Minyard 8378bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 8388bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8398bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8408bfffbccSCorey Minyard unsigned int max_rsp_len) 8418bfffbccSCorey Minyard { 8428bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->msg_flags); 8438bfffbccSCorey Minyard } 8448bfffbccSCorey Minyard 8458bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 8468bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8478bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8488bfffbccSCorey Minyard unsigned int max_rsp_len) 8498bfffbccSCorey Minyard { 8508bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8518bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8528bfffbccSCorey Minyard unsigned int i; 8538bfffbccSCorey Minyard 8548bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 8558bfffbccSCorey Minyard rsp[2] = 0x80; 856d13ada5dSCédric Le Goater return; 8578bfffbccSCorey Minyard } 8588bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 8598bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->evtbuf[i]); 8608bfffbccSCorey Minyard } 8618bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 8628bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 8638bfffbccSCorey Minyard } 8648bfffbccSCorey Minyard 8658bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 8668bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8678bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8688bfffbccSCorey Minyard unsigned int max_rsp_len) 8698bfffbccSCorey Minyard { 8708bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 8718bfffbccSCorey Minyard 8728bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 8738bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 8748bfffbccSCorey Minyard rsp[2] = 0x80; /* Queue empty */ 8758bfffbccSCorey Minyard goto out; 8768bfffbccSCorey Minyard } 8778bfffbccSCorey Minyard rsp[3] = 0; /* Channel 0 */ 8788bfffbccSCorey Minyard *rsp_len += 1; 8798bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 8808bfffbccSCorey Minyard memcpy(rsp + 4, msg->buf, msg->len); 8818bfffbccSCorey Minyard *rsp_len += msg->len; 8828bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 8838bfffbccSCorey Minyard g_free(msg); 8848bfffbccSCorey Minyard 8858bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 8868bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8878bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8888bfffbccSCorey Minyard 8898bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 8908bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 8918bfffbccSCorey Minyard } 8928bfffbccSCorey Minyard 8938bfffbccSCorey Minyard out: 8948bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 8958bfffbccSCorey Minyard return; 8968bfffbccSCorey Minyard } 8978bfffbccSCorey Minyard 8988bfffbccSCorey Minyard static unsigned char 8998bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 9008bfffbccSCorey Minyard { 9018bfffbccSCorey Minyard for (; size > 0; size--, data++) { 9028bfffbccSCorey Minyard csum += *data; 9038bfffbccSCorey Minyard } 9048bfffbccSCorey Minyard 9058bfffbccSCorey Minyard return -csum; 9068bfffbccSCorey Minyard } 9078bfffbccSCorey Minyard 9088bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 9098bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 9108bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 9118bfffbccSCorey Minyard unsigned int max_rsp_len) 9128bfffbccSCorey Minyard { 9138bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9148bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9158bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9168bfffbccSCorey Minyard uint8_t *buf; 9178bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 9188bfffbccSCorey Minyard 9198bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 9208bfffbccSCorey Minyard 9218bfffbccSCorey Minyard if (cmd[2] != 0) { 9228bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 9238bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 924d13ada5dSCédric Le Goater return; 9258bfffbccSCorey Minyard } 9268bfffbccSCorey Minyard 9278bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(10); 9288bfffbccSCorey Minyard if (cmd[3] != 0x40) { 9298bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 9308bfffbccSCorey Minyard rsp[2] = 0x83; /* NAK on write */ 931d13ada5dSCédric Le Goater return; 9328bfffbccSCorey Minyard } 9338bfffbccSCorey Minyard 9348bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 9358bfffbccSCorey Minyard cmd_len -= 3; 9368bfffbccSCorey Minyard 9378bfffbccSCorey Minyard /* 9388bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 9398bfffbccSCorey Minyard * be returned in the response. 9408bfffbccSCorey Minyard */ 9418bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 9428bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 943d13ada5dSCédric Le Goater return; /* No response */ 9448bfffbccSCorey Minyard } 9458bfffbccSCorey Minyard 9468bfffbccSCorey Minyard netfn = cmd[1] >> 2; 9478bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 9488bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 9498bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 9508bfffbccSCorey Minyard 9518bfffbccSCorey Minyard if (rqLun != 2) { 9528bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 953d13ada5dSCédric Le Goater return; 9548bfffbccSCorey Minyard } 9558bfffbccSCorey Minyard 9568bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 9578bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 9588bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 9598bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 9608bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 9618bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 9628bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 9638bfffbccSCorey Minyard msg->len = 6; 9648bfffbccSCorey Minyard 9658bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 9668bfffbccSCorey Minyard /* Not a command we handle. */ 9678bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 9688bfffbccSCorey Minyard goto end_msg; 9698bfffbccSCorey Minyard } 9708bfffbccSCorey Minyard 9718bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 9728bfffbccSCorey Minyard buf[0] = 0; 9738bfffbccSCorey Minyard buf[1] = 0; 9748bfffbccSCorey Minyard buf[2] = 0; 9758bfffbccSCorey Minyard buf[3] = 0; 9768bfffbccSCorey Minyard buf[4] = 0x51; 9778bfffbccSCorey Minyard buf[5] = 0; 9788bfffbccSCorey Minyard buf[6] = 0; 9798bfffbccSCorey Minyard buf[7] = 0; 9808bfffbccSCorey Minyard buf[8] = 0; 9818bfffbccSCorey Minyard buf[9] = 0; 9828bfffbccSCorey Minyard buf[10] = 0; 9838bfffbccSCorey Minyard msg->len += 11; 9848bfffbccSCorey Minyard 9858bfffbccSCorey Minyard end_msg: 9868bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 9878bfffbccSCorey Minyard msg->len++; 9888bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 9898bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 9908bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9918bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 9928bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 9938bfffbccSCorey Minyard } 9948bfffbccSCorey Minyard 9958bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 9968bfffbccSCorey Minyard { 9978bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 9988bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 9998bfffbccSCorey Minyard ibs->watchdog_running = 0; 10008bfffbccSCorey Minyard return; 10018bfffbccSCorey Minyard } 10028bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 10038bfffbccSCorey Minyard 10048bfffbccSCorey Minyard 10058bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 10068bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 10078bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 10088bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 10098bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 10108bfffbccSCorey Minyard } 10118bfffbccSCorey Minyard ibs->watchdog_running = 1; 10128bfffbccSCorey Minyard } 10138bfffbccSCorey Minyard 10148bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 10158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10168bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 10178bfffbccSCorey Minyard unsigned int max_rsp_len) 10188bfffbccSCorey Minyard { 10198bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 10208bfffbccSCorey Minyard rsp[2] = 0x80; 1021d13ada5dSCédric Le Goater return; 10228bfffbccSCorey Minyard } 10238bfffbccSCorey Minyard do_watchdog_reset(ibs); 10248bfffbccSCorey Minyard } 10258bfffbccSCorey Minyard 10268bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 10278bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10288bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 10298bfffbccSCorey Minyard unsigned int max_rsp_len) 10308bfffbccSCorey Minyard { 10318bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10328bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10338bfffbccSCorey Minyard unsigned int val; 10348bfffbccSCorey Minyard 10358bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 10368bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 10378bfffbccSCorey Minyard if (val == 0 || val > 5) { 10388bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1039d13ada5dSCédric Le Goater return; 10408bfffbccSCorey Minyard } 10418bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 10428bfffbccSCorey Minyard switch (val) { 10438bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 10448bfffbccSCorey Minyard break; 10458bfffbccSCorey Minyard 10468bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 10478bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1); 10488bfffbccSCorey Minyard break; 10498bfffbccSCorey Minyard 10508bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 10518bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1); 10528bfffbccSCorey Minyard break; 10538bfffbccSCorey Minyard 10548bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 10558bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1); 10568bfffbccSCorey Minyard break; 10578bfffbccSCorey Minyard 10588bfffbccSCorey Minyard default: 10598bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 10608bfffbccSCorey Minyard } 10618bfffbccSCorey Minyard if (rsp[2]) { 10628bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1063d13ada5dSCédric Le Goater return; 10648bfffbccSCorey Minyard } 10658bfffbccSCorey Minyard 10668bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 10678bfffbccSCorey Minyard switch (val) { 10688bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 10698bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 10708bfffbccSCorey Minyard break; 10718bfffbccSCorey Minyard 10728bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 10738bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 10748bfffbccSCorey Minyard /* NMI not supported. */ 10758bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1076d13ada5dSCédric Le Goater return; 10778bfffbccSCorey Minyard } 10788bfffbccSCorey Minyard default: 10798bfffbccSCorey Minyard /* We don't support PRE_SMI */ 10808bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1081d13ada5dSCédric Le Goater return; 10828bfffbccSCorey Minyard } 10838bfffbccSCorey Minyard 10848bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 10858bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 10868bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 10878bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 10888bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 10898bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 10908bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 10918bfffbccSCorey Minyard do_watchdog_reset(ibs); 10928bfffbccSCorey Minyard } else { 10938bfffbccSCorey Minyard ibs->watchdog_running = 0; 10948bfffbccSCorey Minyard } 10958bfffbccSCorey Minyard } 10968bfffbccSCorey Minyard 10978bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 10988bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10998bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11008bfffbccSCorey Minyard unsigned int max_rsp_len) 11018bfffbccSCorey Minyard { 11028bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_use); 11038bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_action); 11048bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout); 11058bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_expired); 11068bfffbccSCorey Minyard if (ibs->watchdog_running) { 11078bfffbccSCorey Minyard long timeout; 11088bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 11098bfffbccSCorey Minyard / 100000000); 11108bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(timeout & 0xff); 11118bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff); 11128bfffbccSCorey Minyard } else { 11138bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 11148bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 11158bfffbccSCorey Minyard } 11168bfffbccSCorey Minyard } 11178bfffbccSCorey Minyard 11188bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 11198bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11208bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11218bfffbccSCorey Minyard unsigned int max_rsp_len) 11228bfffbccSCorey Minyard { 11238bfffbccSCorey Minyard unsigned int i; 11248bfffbccSCorey Minyard 11258bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */ 11268bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff); 11278bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff); 11288bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 11298bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 11308bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 11318bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]); 11328bfffbccSCorey Minyard } 11338bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 11348bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]); 11358bfffbccSCorey Minyard } 11368bfffbccSCorey Minyard /* Only modal support, reserve supported */ 11378bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22); 11388bfffbccSCorey Minyard } 11398bfffbccSCorey Minyard 11408bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 11418bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11428bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11438bfffbccSCorey Minyard unsigned int max_rsp_len) 11448bfffbccSCorey Minyard { 11458bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff); 11468bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff); 11478bfffbccSCorey Minyard } 11488bfffbccSCorey Minyard 11498bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 11508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11518bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11528bfffbccSCorey Minyard unsigned int max_rsp_len) 11538bfffbccSCorey Minyard { 11548bfffbccSCorey Minyard unsigned int pos; 11558bfffbccSCorey Minyard uint16_t nextrec; 11568bfffbccSCorey Minyard 11578bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 11588bfffbccSCorey Minyard if (cmd[6]) { 11598bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 11608bfffbccSCorey Minyard } 11618bfffbccSCorey Minyard pos = 0; 11628bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 11638bfffbccSCorey Minyard &pos, &nextrec)) { 11648bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1165d13ada5dSCédric Le Goater return; 11668bfffbccSCorey Minyard } 1167*792afddbSCédric Le Goater if (cmd[6] > (ibs->sdr.sdr[pos + 4] + 5)) { 11688bfffbccSCorey Minyard rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; 1169d13ada5dSCédric Le Goater return; 11708bfffbccSCorey Minyard } 11718bfffbccSCorey Minyard 11728bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(nextrec & 0xff); 11738bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); 11748bfffbccSCorey Minyard 11758bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1176*792afddbSCédric Le Goater cmd[7] = ibs->sdr.sdr[pos + 4] + 5 - cmd[6]; 11778bfffbccSCorey Minyard } 11788bfffbccSCorey Minyard 11798bfffbccSCorey Minyard if ((cmd[7] + *rsp_len) > max_rsp_len) { 11808bfffbccSCorey Minyard rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 1181d13ada5dSCédric Le Goater return; 11828bfffbccSCorey Minyard } 11838bfffbccSCorey Minyard memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 11848bfffbccSCorey Minyard *rsp_len += cmd[7]; 11858bfffbccSCorey Minyard } 11868bfffbccSCorey Minyard 11878bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 11888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11898bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11908bfffbccSCorey Minyard unsigned int max_rsp_len) 11918bfffbccSCorey Minyard { 11928bfffbccSCorey Minyard uint16_t recid; 11938bfffbccSCorey Minyard 11948bfffbccSCorey Minyard if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) { 11958bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1196d13ada5dSCédric Le Goater return; 11978bfffbccSCorey Minyard } 11988bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(recid & 0xff); 11998bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((recid >> 8) & 0xff); 12008bfffbccSCorey Minyard } 12018bfffbccSCorey Minyard 12028bfffbccSCorey Minyard static void clear_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_CHECK_CMD_LEN(8); 12088bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 12098bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 12108bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1211d13ada5dSCédric Le Goater return; 12128bfffbccSCorey Minyard } 12138bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 12148bfffbccSCorey Minyard ibs->sdr.next_free = 0; 12158bfffbccSCorey Minyard ibs->sdr.overflow = 0; 12168bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 12178bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 12188bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 12198bfffbccSCorey Minyard } else if (cmd[7] == 0) { 12208bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 12218bfffbccSCorey Minyard } else { 12228bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 12238bfffbccSCorey Minyard return; 12248bfffbccSCorey Minyard } 1225d13ada5dSCédric Le Goater } 12268bfffbccSCorey Minyard 12278bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 12288bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12298bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12308bfffbccSCorey Minyard unsigned int max_rsp_len) 12318bfffbccSCorey Minyard { 12328bfffbccSCorey Minyard unsigned int i, val; 12338bfffbccSCorey Minyard 12348bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */ 12358bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff); 12368bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff); 12378bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 12388bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 12398bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 12408bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 12418bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]); 12428bfffbccSCorey Minyard } 12438bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 12448bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]); 12458bfffbccSCorey Minyard } 12468bfffbccSCorey Minyard /* Only support Reserve SEL */ 12478bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); 12488bfffbccSCorey Minyard } 12498bfffbccSCorey Minyard 12508bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 12518bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12528bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12538bfffbccSCorey Minyard unsigned int max_rsp_len) 12548bfffbccSCorey Minyard { 12558bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff); 12568bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff); 12578bfffbccSCorey Minyard } 12588bfffbccSCorey Minyard 12598bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 12608bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12618bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12628bfffbccSCorey Minyard unsigned int max_rsp_len) 12638bfffbccSCorey Minyard { 12648bfffbccSCorey Minyard unsigned int val; 12658bfffbccSCorey Minyard 12668bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 12678bfffbccSCorey Minyard if (cmd[6]) { 12688bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 12698bfffbccSCorey Minyard } 12708bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 12718bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1272d13ada5dSCédric Le Goater return; 12738bfffbccSCorey Minyard } 12748bfffbccSCorey Minyard if (cmd[6] > 15) { 12758bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1276d13ada5dSCédric Le Goater return; 12778bfffbccSCorey Minyard } 12788bfffbccSCorey Minyard if (cmd[7] == 0xff) { 12798bfffbccSCorey Minyard cmd[7] = 16; 12808bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 12818bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1282d13ada5dSCédric Le Goater return; 12838bfffbccSCorey Minyard } else { 12848bfffbccSCorey Minyard cmd[7] += cmd[6]; 12858bfffbccSCorey Minyard } 12868bfffbccSCorey Minyard 12878bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 12888bfffbccSCorey Minyard if (val == 0xffff) { 12898bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 12908bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 12918bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1292d13ada5dSCédric Le Goater return; 12938bfffbccSCorey Minyard } 12948bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 12958bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 12968bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 12978bfffbccSCorey Minyard } else { 12988bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val + 1) & 0xff); 12998bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff); 13008bfffbccSCorey Minyard } 13018bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 13028bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]); 13038bfffbccSCorey Minyard } 13048bfffbccSCorey Minyard } 13058bfffbccSCorey Minyard 13068bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 13078bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13088bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13098bfffbccSCorey Minyard unsigned int max_rsp_len) 13108bfffbccSCorey Minyard { 13118bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(18); 13128bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 13138bfffbccSCorey Minyard rsp[2] = IPMI_CC_OUT_OF_SPACE; 1314d13ada5dSCédric Le Goater return; 13158bfffbccSCorey Minyard } 13168bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 13178bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[2]); 13188bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[3]); 13198bfffbccSCorey Minyard } 13208bfffbccSCorey Minyard 13218bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 13228bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13238bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13248bfffbccSCorey Minyard unsigned int max_rsp_len) 13258bfffbccSCorey Minyard { 13268bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 13278bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 13288bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13298bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1330d13ada5dSCédric Le Goater return; 13318bfffbccSCorey Minyard } 13328bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 13338bfffbccSCorey Minyard ibs->sel.next_free = 0; 13348bfffbccSCorey Minyard ibs->sel.overflow = 0; 13358bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 13368bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 13378bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 13388bfffbccSCorey Minyard } else if (cmd[7] == 0) { 13398bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 13408bfffbccSCorey Minyard } else { 13418bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 13428bfffbccSCorey Minyard return; 13438bfffbccSCorey Minyard } 1344d13ada5dSCédric Le Goater } 13458bfffbccSCorey Minyard 13468bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 13478bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13488bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13498bfffbccSCorey Minyard unsigned int max_rsp_len) 13508bfffbccSCorey Minyard { 13518bfffbccSCorey Minyard uint32_t val; 13528bfffbccSCorey Minyard struct ipmi_time now; 13538bfffbccSCorey Minyard 13548bfffbccSCorey Minyard ipmi_gettime(&now); 13558bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 13568bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 13578bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 13588bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 16) & 0xff); 13598bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 24) & 0xff); 13608bfffbccSCorey Minyard } 13618bfffbccSCorey Minyard 13628bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 13638bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13648bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13658bfffbccSCorey Minyard unsigned int max_rsp_len) 13668bfffbccSCorey Minyard { 13678bfffbccSCorey Minyard uint32_t val; 13688bfffbccSCorey Minyard struct ipmi_time now; 13698bfffbccSCorey Minyard 13708bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(6); 13718bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 13728bfffbccSCorey Minyard ipmi_gettime(&now); 13738bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 13748bfffbccSCorey Minyard } 13758bfffbccSCorey Minyard 13768bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 13778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13788bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13798bfffbccSCorey Minyard unsigned int max_rsp_len) 13808bfffbccSCorey Minyard { 13818bfffbccSCorey Minyard IPMISensor *sens; 13828bfffbccSCorey Minyard 13838bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 13848bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 13858bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 13868bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1387d13ada5dSCédric Le Goater return; 13888bfffbccSCorey Minyard } 13898bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 13908bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 13918bfffbccSCorey Minyard case 0: /* Do not change */ 13928bfffbccSCorey Minyard break; 13938bfffbccSCorey Minyard case 1: /* Enable bits */ 13948bfffbccSCorey Minyard if (cmd_len > 4) { 13958bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 13968bfffbccSCorey Minyard } 13978bfffbccSCorey Minyard if (cmd_len > 5) { 13988bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 13998bfffbccSCorey Minyard } 14008bfffbccSCorey Minyard if (cmd_len > 6) { 14018bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 14028bfffbccSCorey Minyard } 14038bfffbccSCorey Minyard if (cmd_len > 7) { 14048bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 14058bfffbccSCorey Minyard } 14068bfffbccSCorey Minyard break; 14078bfffbccSCorey Minyard case 2: /* Disable bits */ 14088bfffbccSCorey Minyard if (cmd_len > 4) { 14098bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 14108bfffbccSCorey Minyard } 14118bfffbccSCorey Minyard if (cmd_len > 5) { 14128bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 14138bfffbccSCorey Minyard } 14148bfffbccSCorey Minyard if (cmd_len > 6) { 14158bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 14168bfffbccSCorey Minyard } 14178bfffbccSCorey Minyard if (cmd_len > 7) { 14188bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 14198bfffbccSCorey Minyard } 14208bfffbccSCorey Minyard break; 14218bfffbccSCorey Minyard case 3: 14228bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1423d13ada5dSCédric Le Goater return; 14248bfffbccSCorey Minyard } 14258bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 14268bfffbccSCorey Minyard } 14278bfffbccSCorey Minyard 14288bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 14298bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14308bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14318bfffbccSCorey Minyard unsigned int max_rsp_len) 14328bfffbccSCorey Minyard { 14338bfffbccSCorey Minyard IPMISensor *sens; 14348bfffbccSCorey Minyard 14358bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 14368bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 14378bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14388bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1439d13ada5dSCédric Le Goater return; 14408bfffbccSCorey Minyard } 14418bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14428bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 14438bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff); 14448bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff); 14458bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff); 14468bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff); 14478bfffbccSCorey Minyard } 14488bfffbccSCorey Minyard 14498bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 14508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14518bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14528bfffbccSCorey Minyard unsigned int max_rsp_len) 14538bfffbccSCorey Minyard { 14548bfffbccSCorey Minyard IPMISensor *sens; 14558bfffbccSCorey Minyard 14568bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 14578bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 14588bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14598bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1460d13ada5dSCédric Le Goater return; 14618bfffbccSCorey Minyard } 14628bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14638bfffbccSCorey Minyard 14648bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 14658bfffbccSCorey Minyard /* Just clear everything */ 14668bfffbccSCorey Minyard sens->states = 0; 14678bfffbccSCorey Minyard return; 14688bfffbccSCorey Minyard } 1469d13ada5dSCédric Le Goater } 14708bfffbccSCorey Minyard 14718bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 14728bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14738bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14748bfffbccSCorey Minyard unsigned int max_rsp_len) 14758bfffbccSCorey Minyard { 14768bfffbccSCorey Minyard IPMISensor *sens; 14778bfffbccSCorey Minyard 14788bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 14798bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 14808bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14818bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1482d13ada5dSCédric Le Goater return; 14838bfffbccSCorey Minyard } 14848bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14858bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 14868bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 14878bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_states & 0xff); 14888bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff); 14898bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff); 14908bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff); 14918bfffbccSCorey Minyard } 14928bfffbccSCorey Minyard 14938bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 14948bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14958bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14968bfffbccSCorey Minyard unsigned int max_rsp_len) 14978bfffbccSCorey Minyard { 14988bfffbccSCorey Minyard IPMISensor *sens; 14998bfffbccSCorey Minyard 15008bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 15018bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 15028bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15038bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1504d13ada5dSCédric Le Goater return; 15058bfffbccSCorey Minyard } 15068bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15078bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 15088bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 15098bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->states & 0xff); 15108bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 15118bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff); 15128bfffbccSCorey Minyard } 15138bfffbccSCorey Minyard } 15148bfffbccSCorey Minyard 151562a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 15168bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, 15178bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, 15188bfffbccSCorey Minyard [IPMI_CMD_CHASSIS_CONTROL] = chassis_control 15198bfffbccSCorey Minyard }; 15208bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 152162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 15228bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 15238bfffbccSCorey Minyard }; 15248bfffbccSCorey Minyard 152562a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 15268bfffbccSCorey Minyard [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable, 15278bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable, 15288bfffbccSCorey Minyard [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts, 15298bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status, 15308bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading 15318bfffbccSCorey Minyard }; 15328bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 153362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 15348bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 15358bfffbccSCorey Minyard }; 15368bfffbccSCorey Minyard 153762a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 15388bfffbccSCorey Minyard [IPMI_CMD_GET_DEVICE_ID] = get_device_id, 15398bfffbccSCorey Minyard [IPMI_CMD_COLD_RESET] = cold_reset, 15408bfffbccSCorey Minyard [IPMI_CMD_WARM_RESET] = warm_reset, 15418bfffbccSCorey Minyard [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables, 15428bfffbccSCorey Minyard [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables, 15438bfffbccSCorey Minyard [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags, 15448bfffbccSCorey Minyard [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags, 15458bfffbccSCorey Minyard [IPMI_CMD_GET_MSG] = get_msg, 15468bfffbccSCorey Minyard [IPMI_CMD_SEND_MSG] = send_msg, 15478bfffbccSCorey Minyard [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf, 15488bfffbccSCorey Minyard [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer, 15498bfffbccSCorey Minyard [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer, 15508bfffbccSCorey Minyard [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer, 15518bfffbccSCorey Minyard }; 15528bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 155362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 15548bfffbccSCorey Minyard .cmd_handlers = app_cmds 15558bfffbccSCorey Minyard }; 15568bfffbccSCorey Minyard 155762a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 15588bfffbccSCorey Minyard [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info, 15598bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep, 15608bfffbccSCorey Minyard [IPMI_CMD_GET_SDR] = get_sdr, 15618bfffbccSCorey Minyard [IPMI_CMD_ADD_SDR] = add_sdr, 15628bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep, 15638bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_INFO] = get_sel_info, 15648bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SEL] = reserve_sel, 15658bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry, 15668bfffbccSCorey Minyard [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry, 15678bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SEL] = clear_sel, 15688bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_TIME] = get_sel_time, 15698bfffbccSCorey Minyard [IPMI_CMD_SET_SEL_TIME] = set_sel_time, 15708bfffbccSCorey Minyard }; 15718bfffbccSCorey Minyard 15728bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 157362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 15748bfffbccSCorey Minyard .cmd_handlers = storage_cmds 15758bfffbccSCorey Minyard }; 15768bfffbccSCorey Minyard 15778bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 15788bfffbccSCorey Minyard { 15798bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 15808bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 15818bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 15828bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 15838bfffbccSCorey Minyard } 15848bfffbccSCorey Minyard 15858bfffbccSCorey Minyard static const uint8_t init_sdrs[] = { 15868bfffbccSCorey Minyard /* Watchdog device */ 15878bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 15888bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 15898bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 15908bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 15918bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 15928bfffbccSCorey Minyard /* End */ 15938bfffbccSCorey Minyard 0xff, 0xff, 0x00, 0x00, 0x00 15948bfffbccSCorey Minyard }; 15958bfffbccSCorey Minyard 1596bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1597bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1598bd66bcfcSCorey Minyard .version_id = 1, 1599bd66bcfcSCorey Minyard .minimum_version_id = 1, 1600bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1601bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1602bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1603bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1604bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1605bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1606bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1607bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1608bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1609bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1610bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1611bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1612bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1613bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1614bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1615bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1616bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1617bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1618bd66bcfcSCorey Minyard IPMIBmcSim), 1619bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1620bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1621bd66bcfcSCorey Minyard } 1622bd66bcfcSCorey Minyard }; 1623bd66bcfcSCorey Minyard 16248bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj) 16258bfffbccSCorey Minyard { 16268bfffbccSCorey Minyard IPMIBmc *b = IPMI_BMC(obj); 16278bfffbccSCorey Minyard unsigned int i; 16288bfffbccSCorey Minyard unsigned int recid; 16298bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 16308bfffbccSCorey Minyard 16318bfffbccSCorey Minyard qemu_mutex_init(&ibs->lock); 16328bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 16338bfffbccSCorey Minyard 16348bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 16358bfffbccSCorey Minyard ibs->device_id = 0x20; 16368bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 16378bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 16388bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 16398bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 16408bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 16418bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 16428bfffbccSCorey Minyard } 16438bfffbccSCorey Minyard 16448bfffbccSCorey Minyard for (i = 0;;) { 16458bfffbccSCorey Minyard int len; 16468bfffbccSCorey Minyard if ((i + 5) > sizeof(init_sdrs)) { 16477cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 16488bfffbccSCorey Minyard return; 16498bfffbccSCorey Minyard } 1650*792afddbSCédric Le Goater len = init_sdrs[i + 4] + 5; 16518bfffbccSCorey Minyard recid = init_sdrs[i] | (init_sdrs[i + 1] << 8); 16528bfffbccSCorey Minyard if (recid == 0xffff) { 16538bfffbccSCorey Minyard break; 16548bfffbccSCorey Minyard } 1655*792afddbSCédric Le Goater if ((i + len) > sizeof(init_sdrs)) { 16567cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 16578bfffbccSCorey Minyard return; 16588bfffbccSCorey Minyard } 16598bfffbccSCorey Minyard sdr_add_entry(ibs, init_sdrs + i, len, NULL); 1660*792afddbSCédric Le Goater i += len; 16618bfffbccSCorey Minyard } 16628bfffbccSCorey Minyard 16638bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 16648bfffbccSCorey Minyard register_cmds(ibs); 16658bfffbccSCorey Minyard 16668bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1667bd66bcfcSCorey Minyard 1668bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 16698bfffbccSCorey Minyard } 16708bfffbccSCorey Minyard 16718bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 16728bfffbccSCorey Minyard { 16738bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 16748bfffbccSCorey Minyard 16758bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 16768bfffbccSCorey Minyard } 16778bfffbccSCorey Minyard 16788bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 16798bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 16808bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 16818bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 16828bfffbccSCorey Minyard .instance_init = ipmi_sim_init, 16838bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 16848bfffbccSCorey Minyard }; 16858bfffbccSCorey Minyard 16868bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 16878bfffbccSCorey Minyard { 16888bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 16898bfffbccSCorey Minyard } 16908bfffbccSCorey Minyard 16918bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1692