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 35*b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 368bfffbccSCorey Minyard 378bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 388bfffbccSCorey Minyard 398bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 408bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 418bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 438bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 44728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e 45728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f 468bfffbccSCorey Minyard 478bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 488bfffbccSCorey Minyard 498bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 508bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 518bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 528bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 538bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 548bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 558bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 568bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 578bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 588bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 598bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 608bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 618bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 628bfffbccSCorey Minyard 638bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 648bfffbccSCorey Minyard 658bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 668bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 678bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 688bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 698bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 708bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 718bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 728bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 748bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 758bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 768bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 778bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 788bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 798bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 808bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 818bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 828bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 838bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 848bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 858bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 868bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 878bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 888bfffbccSCorey Minyard 898bfffbccSCorey Minyard 908bfffbccSCorey Minyard /* Same as a timespec struct. */ 918bfffbccSCorey Minyard struct ipmi_time { 928bfffbccSCorey Minyard long tv_sec; 938bfffbccSCorey Minyard long tv_nsec; 948bfffbccSCorey Minyard }; 958bfffbccSCorey Minyard 968bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 978bfffbccSCorey Minyard 988bfffbccSCorey Minyard typedef struct IPMISel { 998bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 1008bfffbccSCorey Minyard unsigned int next_free; 1018bfffbccSCorey Minyard long time_offset; 1028bfffbccSCorey Minyard uint16_t reservation; 1038bfffbccSCorey Minyard uint8_t last_addition[4]; 1048bfffbccSCorey Minyard uint8_t last_clear[4]; 1058bfffbccSCorey Minyard uint8_t overflow; 1068bfffbccSCorey Minyard } IPMISel; 1078bfffbccSCorey Minyard 1088bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1098bfffbccSCorey Minyard 1108bfffbccSCorey Minyard typedef struct IPMISdr { 1118bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1128bfffbccSCorey Minyard unsigned int next_free; 1138bfffbccSCorey Minyard uint16_t next_rec_id; 1148bfffbccSCorey Minyard uint16_t reservation; 1158bfffbccSCorey Minyard uint8_t last_addition[4]; 1168bfffbccSCorey Minyard uint8_t last_clear[4]; 1178bfffbccSCorey Minyard uint8_t overflow; 1188bfffbccSCorey Minyard } IPMISdr; 1198bfffbccSCorey Minyard 1208bfffbccSCorey Minyard typedef struct IPMISensor { 1218bfffbccSCorey Minyard uint8_t status; 1228bfffbccSCorey Minyard uint8_t reading; 1238bfffbccSCorey Minyard uint16_t states_suppt; 1248bfffbccSCorey Minyard uint16_t assert_suppt; 1258bfffbccSCorey Minyard uint16_t deassert_suppt; 1268bfffbccSCorey Minyard uint16_t states; 1278bfffbccSCorey Minyard uint16_t assert_states; 1288bfffbccSCorey Minyard uint16_t deassert_states; 1298bfffbccSCorey Minyard uint16_t assert_enable; 1308bfffbccSCorey Minyard uint16_t deassert_enable; 1318bfffbccSCorey Minyard uint8_t sensor_type; 1328bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1338bfffbccSCorey Minyard } IPMISensor; 1348bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1358bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1368bfffbccSCorey Minyard !!(v)) 1378bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1388bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1398bfffbccSCorey Minyard ((!!(v)) << 6)) 1408bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1418bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1428bfffbccSCorey Minyard ((!!(v)) << 7)) 1438bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1448bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1458bfffbccSCorey Minyard (v & 0xc0)) 1468bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1478bfffbccSCorey Minyard 1488bfffbccSCorey Minyard #define MAX_SENSORS 20 1498bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1508bfffbccSCorey Minyard 1518bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 1528bfffbccSCorey Minyard 1538bfffbccSCorey Minyard #define MAX_NETFNS 64 1548bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s, 1558bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1568bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1578bfffbccSCorey Minyard unsigned int max_rsp_len); 1588bfffbccSCorey Minyard typedef struct IPMINetfn { 1598bfffbccSCorey Minyard unsigned int cmd_nums; 1608bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1618bfffbccSCorey Minyard } IPMINetfn; 1628bfffbccSCorey Minyard 1638bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1648bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1658bfffbccSCorey Minyard uint8_t len; 1668bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1678bfffbccSCorey Minyard } IPMIRcvBufEntry; 1688bfffbccSCorey Minyard 1698bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1708bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1718bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1728bfffbccSCorey Minyard struct IPMIBmcSim { 1738bfffbccSCorey Minyard IPMIBmc parent; 1748bfffbccSCorey Minyard 1758bfffbccSCorey Minyard QEMUTimer *timer; 1768bfffbccSCorey Minyard 1778bfffbccSCorey Minyard uint8_t bmc_global_enables; 1788bfffbccSCorey Minyard uint8_t msg_flags; 1798bfffbccSCorey Minyard 1808bfffbccSCorey Minyard bool watchdog_initialized; 1818bfffbccSCorey Minyard uint8_t watchdog_use; 1828bfffbccSCorey Minyard uint8_t watchdog_action; 1838bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 1848bfffbccSCorey Minyard bool watchdog_expired; 1858bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 1868bfffbccSCorey Minyard 1878bfffbccSCorey Minyard bool watchdog_running; 1888bfffbccSCorey Minyard bool watchdog_preaction_ran; 1898bfffbccSCorey Minyard int64_t watchdog_expiry; 1908bfffbccSCorey Minyard 1918bfffbccSCorey Minyard uint8_t device_id; 1928bfffbccSCorey Minyard uint8_t ipmi_version; 1938bfffbccSCorey Minyard uint8_t device_rev; 1948bfffbccSCorey Minyard uint8_t fwrev1; 1958bfffbccSCorey Minyard uint8_t fwrev2; 1968bfffbccSCorey Minyard uint8_t mfg_id[3]; 1978bfffbccSCorey Minyard uint8_t product_id[2]; 1988bfffbccSCorey Minyard 199*b7088392SCédric Le Goater uint8_t restart_cause; 200*b7088392SCédric Le Goater 2018bfffbccSCorey Minyard IPMISel sel; 2028bfffbccSCorey Minyard IPMISdr sdr; 2038bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 2048bfffbccSCorey Minyard 2058bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2068bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2078bfffbccSCorey Minyard 2088bfffbccSCorey Minyard QemuMutex lock; 2098bfffbccSCorey Minyard /* We allow one event in the buffer */ 2108bfffbccSCorey Minyard uint8_t evtbuf[16]; 2118bfffbccSCorey Minyard 2128bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2138bfffbccSCorey Minyard }; 2148bfffbccSCorey Minyard 2158bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2168bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2178bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2188bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2198bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2208bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2218bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2228bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2238bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2248bfffbccSCorey Minyard 2258bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2268bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2278bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2288bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2308bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2318bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2328bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2338bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2348bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2358bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2368bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2378bfffbccSCorey Minyard 2388bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2398bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2408bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2418bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2428bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2438bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2448bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2458bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2468bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2478bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2488bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2498bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2508bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2538bfffbccSCorey Minyard 2548bfffbccSCorey Minyard 2558bfffbccSCorey Minyard /* Add a byte to the response. */ 2568bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \ 2578bfffbccSCorey Minyard do { \ 2588bfffbccSCorey Minyard if (*rsp_len >= max_rsp_len) { \ 2598bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \ 260d13ada5dSCédric Le Goater return; \ 2618bfffbccSCorey Minyard } \ 2628bfffbccSCorey Minyard rsp[(*rsp_len)++] = (b); \ 2638bfffbccSCorey Minyard } while (0) 2648bfffbccSCorey Minyard 2658bfffbccSCorey Minyard /* Verify that the received command is a certain length. */ 2668bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \ 2678bfffbccSCorey Minyard if (cmd_len < l) { \ 2688bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \ 269d13ada5dSCédric Le Goater return; \ 2708bfffbccSCorey Minyard } 2718bfffbccSCorey Minyard 2728bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */ 2738bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \ 2748bfffbccSCorey Minyard do { \ 2758bfffbccSCorey Minyard if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \ 2768bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_RESERVATION; \ 277d13ada5dSCédric Le Goater return; \ 2788bfffbccSCorey Minyard } \ 2798bfffbccSCorey Minyard } while (0) 2808bfffbccSCorey Minyard 2818bfffbccSCorey Minyard 2828bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 2838bfffbccSCorey Minyard 2848bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 2858bfffbccSCorey Minyard { 2868bfffbccSCorey Minyard int64_t stime; 2878bfffbccSCorey Minyard 2888bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 2898bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 2908bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 2918bfffbccSCorey Minyard } 2928bfffbccSCorey Minyard 2938bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 2948bfffbccSCorey Minyard { 2958bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 2968bfffbccSCorey Minyard } 2978bfffbccSCorey Minyard 2988bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 2998bfffbccSCorey Minyard { 3008bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3018bfffbccSCorey Minyard 3028bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3038bfffbccSCorey Minyard } 3048bfffbccSCorey Minyard 3058bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3068bfffbccSCorey Minyard { 3078bfffbccSCorey Minyard unsigned int val; 3088bfffbccSCorey Minyard struct ipmi_time now; 3098bfffbccSCorey Minyard 3108bfffbccSCorey Minyard ipmi_gettime(&now); 3118bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3128bfffbccSCorey Minyard ts[0] = val & 0xff; 3138bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3148bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3158bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3168bfffbccSCorey Minyard } 3178bfffbccSCorey Minyard 3188bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3198bfffbccSCorey Minyard { 3208bfffbccSCorey Minyard sdr->reservation++; 3218bfffbccSCorey Minyard if (sdr->reservation == 0) { 3228bfffbccSCorey Minyard sdr->reservation = 1; 3238bfffbccSCorey Minyard } 3248bfffbccSCorey Minyard } 3258bfffbccSCorey Minyard 326a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 327a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3288bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3298bfffbccSCorey Minyard { 330a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 331a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 332a2295f0aSCédric Le Goater 333a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3348bfffbccSCorey Minyard return 1; 3358bfffbccSCorey Minyard } 3368bfffbccSCorey Minyard 337a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3388bfffbccSCorey Minyard return 1; 3398bfffbccSCorey Minyard } 3408bfffbccSCorey Minyard 3418bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3428bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3438bfffbccSCorey Minyard return 1; 3448bfffbccSCorey Minyard } 3458bfffbccSCorey Minyard 346a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 347a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 348a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 349a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3508bfffbccSCorey Minyard 3518bfffbccSCorey Minyard if (recid) { 3528bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3538bfffbccSCorey Minyard } 3548bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3558bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3568bfffbccSCorey Minyard ibs->sdr.next_free += len; 3578bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3588bfffbccSCorey Minyard return 0; 3598bfffbccSCorey Minyard } 3608bfffbccSCorey Minyard 3618bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3628bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3638bfffbccSCorey Minyard { 3648bfffbccSCorey Minyard unsigned int pos = *retpos; 3658bfffbccSCorey Minyard 3668bfffbccSCorey Minyard while (pos < sdr->next_free) { 367a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 368a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 369a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 370a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 3718bfffbccSCorey Minyard 3728bfffbccSCorey Minyard if (trec == recid) { 3738bfffbccSCorey Minyard if (nextrec) { 3748bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3758bfffbccSCorey Minyard *nextrec = 0xffff; 3768bfffbccSCorey Minyard } else { 3778bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3788bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3798bfffbccSCorey Minyard } 3808bfffbccSCorey Minyard } 3818bfffbccSCorey Minyard *retpos = pos; 3828bfffbccSCorey Minyard return 0; 3838bfffbccSCorey Minyard } 3848bfffbccSCorey Minyard pos = nextpos; 3858bfffbccSCorey Minyard } 3868bfffbccSCorey Minyard return 1; 3878bfffbccSCorey Minyard } 3888bfffbccSCorey Minyard 3898bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 3908bfffbccSCorey Minyard { 3918bfffbccSCorey Minyard sel->reservation++; 3928bfffbccSCorey Minyard if (sel->reservation == 0) { 3938bfffbccSCorey Minyard sel->reservation = 1; 3948bfffbccSCorey Minyard } 3958bfffbccSCorey Minyard } 3968bfffbccSCorey Minyard 3978bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 3988bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 3998bfffbccSCorey Minyard { 4008bfffbccSCorey Minyard event[0] = 0xff; 4018bfffbccSCorey Minyard event[1] = 0xff; 4028bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 4038bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4048bfffbccSCorey Minyard ibs->sel.overflow = 1; 4058bfffbccSCorey Minyard return 1; 4068bfffbccSCorey Minyard } 4078bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4088bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4098bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 4108bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4118bfffbccSCorey Minyard ibs->sel.next_free++; 4128bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4138bfffbccSCorey Minyard return 0; 4148bfffbccSCorey Minyard } 4158bfffbccSCorey Minyard 4168bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4178bfffbccSCorey Minyard { 4188bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4198bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4208bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4218bfffbccSCorey Minyard } 4228bfffbccSCorey Minyard 4238bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4248bfffbccSCorey Minyard { 4258bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4268bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4278bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4288bfffbccSCorey Minyard } 4298bfffbccSCorey Minyard 4308bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4318bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4328bfffbccSCorey Minyard { 4338bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4348bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4358bfffbccSCorey Minyard uint8_t evt[16]; 4368bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4378bfffbccSCorey Minyard 4388bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4398bfffbccSCorey Minyard return; 4408bfffbccSCorey Minyard } 4418bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4428bfffbccSCorey Minyard return; 4438bfffbccSCorey Minyard } 4448bfffbccSCorey Minyard 4458bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4468bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4478bfffbccSCorey Minyard evt[8] = 0; 4488bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4498bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4508bfffbccSCorey Minyard evt[11] = sens_num; 4518bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4528bfffbccSCorey Minyard evt[13] = evd1; 4538bfffbccSCorey Minyard evt[14] = evd2; 4548bfffbccSCorey Minyard evt[15] = evd3; 4558bfffbccSCorey Minyard 4568bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 4578bfffbccSCorey Minyard sel_add_event(ibs, evt); 4588bfffbccSCorey Minyard } 4598bfffbccSCorey Minyard 4608bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 461d13ada5dSCédric Le Goater return; 4628bfffbccSCorey Minyard } 4638bfffbccSCorey Minyard 4648bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 4658bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 4668bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 4678bfffbccSCorey Minyard } 4688bfffbccSCorey Minyard 4698bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 4708bfffbccSCorey Minyard unsigned int bit, unsigned int val, 4718bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4728bfffbccSCorey Minyard { 4738bfffbccSCorey Minyard IPMISensor *sens; 4748bfffbccSCorey Minyard uint16_t mask; 4758bfffbccSCorey Minyard 4768bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 4778bfffbccSCorey Minyard return; 4788bfffbccSCorey Minyard } 4798bfffbccSCorey Minyard if (bit >= 16) { 4808bfffbccSCorey Minyard return; 4818bfffbccSCorey Minyard } 4828bfffbccSCorey Minyard 4838bfffbccSCorey Minyard mask = (1 << bit); 4848bfffbccSCorey Minyard sens = ibs->sensors + sensor; 4858bfffbccSCorey Minyard if (val) { 4868bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 4878bfffbccSCorey Minyard if (sens->assert_states & mask) { 4888bfffbccSCorey Minyard return; /* Already asserted */ 4898bfffbccSCorey Minyard } 4908bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 4918bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 4928bfffbccSCorey Minyard /* Send an event on assert */ 4938bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 4948bfffbccSCorey Minyard } 4958bfffbccSCorey Minyard } else { 4968bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 4978bfffbccSCorey Minyard if (sens->deassert_states & mask) { 4988bfffbccSCorey Minyard return; /* Already deasserted */ 4998bfffbccSCorey Minyard } 5008bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5018bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5028bfffbccSCorey Minyard /* Send an event on deassert */ 5038bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5048bfffbccSCorey Minyard } 5058bfffbccSCorey Minyard } 5068bfffbccSCorey Minyard } 5078bfffbccSCorey Minyard 5088bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5098bfffbccSCorey Minyard { 5108bfffbccSCorey Minyard unsigned int i, pos; 5118bfffbccSCorey Minyard IPMISensor *sens; 5128bfffbccSCorey Minyard 5138bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5148bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5158bfffbccSCorey Minyard } 5168bfffbccSCorey Minyard 5178bfffbccSCorey Minyard pos = 0; 5188bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 519a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 520a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 521a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5228bfffbccSCorey Minyard 5238bfffbccSCorey Minyard if (len < 20) { 5248bfffbccSCorey Minyard continue; 5258bfffbccSCorey Minyard } 526a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5278bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5288bfffbccSCorey Minyard } 5298bfffbccSCorey Minyard 530a2295f0aSCédric Le Goater if (sdr->sensor_owner_number > MAX_SENSORS) { 5318bfffbccSCorey Minyard continue; 5328bfffbccSCorey Minyard } 533a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5348bfffbccSCorey Minyard 5358bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 536a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 537a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 538a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 539a2295f0aSCédric Le Goater sens->deassert_suppt = 540a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 541a2295f0aSCédric Le Goater sens->states_suppt = 542a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 543a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 544a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5458bfffbccSCorey Minyard 5468bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5478bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5488bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5498bfffbccSCorey Minyard } 5508bfffbccSCorey Minyard } 5518bfffbccSCorey Minyard 5528bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5538bfffbccSCorey Minyard const IPMINetfn *netfnd) 5548bfffbccSCorey Minyard { 5558bfffbccSCorey Minyard if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) { 5568bfffbccSCorey Minyard return -1; 5578bfffbccSCorey Minyard } 5588bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 5598bfffbccSCorey Minyard return 0; 5608bfffbccSCorey Minyard } 5618bfffbccSCorey Minyard 5628bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 5638bfffbccSCorey Minyard { 5648bfffbccSCorey Minyard int64_t next; 5658bfffbccSCorey Minyard if (ibs->watchdog_running) { 5668bfffbccSCorey Minyard next = ibs->watchdog_expiry; 5678bfffbccSCorey Minyard } else { 5688bfffbccSCorey Minyard /* Wait a minute */ 5698bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 5708bfffbccSCorey Minyard } 5718bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 5728bfffbccSCorey Minyard } 5738bfffbccSCorey Minyard 5748bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 5758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 5768bfffbccSCorey Minyard unsigned int max_cmd_len, 5778bfffbccSCorey Minyard uint8_t msg_id) 5788bfffbccSCorey Minyard { 5798bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 5808bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 5818bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 5828bfffbccSCorey Minyard unsigned int netfn; 5838bfffbccSCorey Minyard uint8_t rsp[MAX_IPMI_MSG_SIZE]; 5848bfffbccSCorey Minyard unsigned int rsp_len_holder = 0; 5858bfffbccSCorey Minyard unsigned int *rsp_len = &rsp_len_holder; 5868bfffbccSCorey Minyard unsigned int max_rsp_len = sizeof(rsp); 5878bfffbccSCorey Minyard 5888bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 5898bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 590d13ada5dSCédric Le Goater if (max_rsp_len < 3) { 591d13ada5dSCédric Le Goater rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 592d13ada5dSCédric Le Goater goto out; 593d13ada5dSCédric Le Goater } 594d13ada5dSCédric Le Goater 5958bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[0] | 0x04); 5968bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[1]); 5978bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); /* Assume success */ 5988bfffbccSCorey Minyard 5998bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6008bfffbccSCorey Minyard if (cmd_len < 2) { 6018bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 6028bfffbccSCorey Minyard goto out; 6038bfffbccSCorey Minyard } 6048bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6058bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 6068bfffbccSCorey Minyard goto out; 6078bfffbccSCorey Minyard } 6088bfffbccSCorey Minyard 6098bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6108bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 6118bfffbccSCorey Minyard rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN; 6128bfffbccSCorey Minyard goto out; 6138bfffbccSCorey Minyard } 6148bfffbccSCorey Minyard 6158bfffbccSCorey Minyard netfn = cmd[0] >> 2; 6168bfffbccSCorey Minyard 6178bfffbccSCorey Minyard /* Odd netfns are not valid, make sure the command is registered */ 6188bfffbccSCorey Minyard if ((netfn & 1) || !ibs->netfns[netfn / 2] || 6198bfffbccSCorey Minyard (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) || 6208bfffbccSCorey Minyard (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) { 6218bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_CMD; 6228bfffbccSCorey Minyard goto out; 6238bfffbccSCorey Minyard } 6248bfffbccSCorey Minyard 6258bfffbccSCorey Minyard ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len, 6268bfffbccSCorey Minyard max_rsp_len); 6278bfffbccSCorey Minyard 6288bfffbccSCorey Minyard out: 6298bfffbccSCorey Minyard k->handle_rsp(s, msg_id, rsp, *rsp_len); 6308bfffbccSCorey Minyard 6318bfffbccSCorey Minyard next_timeout(ibs); 6328bfffbccSCorey Minyard } 6338bfffbccSCorey Minyard 6348bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 6358bfffbccSCorey Minyard { 6368bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6378bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6388bfffbccSCorey Minyard 6398bfffbccSCorey Minyard if (!ibs->watchdog_running) { 6408bfffbccSCorey Minyard goto out; 6418bfffbccSCorey Minyard } 6428bfffbccSCorey Minyard 6438bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 6448bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 6458bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 6468bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6478bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 6488bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6498bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 6508bfffbccSCorey Minyard break; 6518bfffbccSCorey Minyard 6528bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 6538bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6548bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 6558bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6568bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 6578bfffbccSCorey Minyard break; 6588bfffbccSCorey Minyard 6598bfffbccSCorey Minyard default: 6608bfffbccSCorey Minyard goto do_full_expiry; 6618bfffbccSCorey Minyard } 6628bfffbccSCorey Minyard 6638bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 6648bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 6658bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 6668bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 6678bfffbccSCorey Minyard goto out; 6688bfffbccSCorey Minyard } 6698bfffbccSCorey Minyard 6708bfffbccSCorey Minyard do_full_expiry: 6718bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 6728bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 6738bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 6748bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 6758bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 6768bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 6778bfffbccSCorey Minyard break; 6788bfffbccSCorey Minyard 6798bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 6808bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 6818bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 6828bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 6838bfffbccSCorey Minyard break; 6848bfffbccSCorey Minyard 6858bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 6868bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 6878bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 6888bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 6898bfffbccSCorey Minyard break; 6908bfffbccSCorey Minyard 6918bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 6928bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 6938bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 6948bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 6958bfffbccSCorey Minyard break; 6968bfffbccSCorey Minyard } 6978bfffbccSCorey Minyard 6988bfffbccSCorey Minyard out: 6998bfffbccSCorey Minyard next_timeout(ibs); 7008bfffbccSCorey Minyard } 7018bfffbccSCorey Minyard 7028bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7048bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7058bfffbccSCorey Minyard unsigned int max_rsp_len) 7068bfffbccSCorey Minyard { 7078bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7088bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7098bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7108bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7118bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 7128bfffbccSCorey Minyard } 7138bfffbccSCorey Minyard 7148bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7168bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7178bfffbccSCorey Minyard unsigned int max_rsp_len) 7188bfffbccSCorey Minyard { 7198bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */ 7208bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7218bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7228bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 7238bfffbccSCorey Minyard } 7248bfffbccSCorey Minyard 7258bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7278bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7288bfffbccSCorey Minyard unsigned int max_rsp_len) 7298bfffbccSCorey Minyard { 7308bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7318bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7328bfffbccSCorey Minyard 7338bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 7348bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7358bfffbccSCorey Minyard case 0: /* power down */ 7368bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7378bfffbccSCorey Minyard break; 7388bfffbccSCorey Minyard case 1: /* power up */ 7398bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0); 7408bfffbccSCorey Minyard break; 7418bfffbccSCorey Minyard case 2: /* power cycle */ 7428bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7438bfffbccSCorey Minyard break; 7448bfffbccSCorey Minyard case 3: /* hard reset */ 7458bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7468bfffbccSCorey Minyard break; 7478bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 7488bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0); 7498bfffbccSCorey Minyard break; 7508bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 7518bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, 7528bfffbccSCorey Minyard IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0); 7538bfffbccSCorey Minyard break; 7548bfffbccSCorey Minyard default: 7558bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 7568bfffbccSCorey Minyard return; 7578bfffbccSCorey Minyard } 758d13ada5dSCédric Le Goater } 7598bfffbccSCorey Minyard 760*b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 761*b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 762*b7088392SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 763*b7088392SCédric Le Goater unsigned int max_rsp_len) 764*b7088392SCédric Le Goater { 765*b7088392SCédric Le Goater IPMI_ADD_RSP_DATA(ibs->restart_cause & 0xf); /* Restart Cause */ 766*b7088392SCédric Le Goater IPMI_ADD_RSP_DATA(0); /* Channel 0 */ 767*b7088392SCédric Le Goater } 768*b7088392SCédric Le Goater 7698bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 7708bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 7718bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 7728bfffbccSCorey Minyard unsigned int max_rsp_len) 7738bfffbccSCorey Minyard { 7748bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_id); 7758bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf); 7768bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f); 7778bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev2); 7788bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->ipmi_version); 7798bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */ 7808bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[0]); 7818bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[1]); 7828bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[2]); 7838bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[0]); 7848bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[1]); 7858bfffbccSCorey Minyard } 7868bfffbccSCorey Minyard 7878bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 7888bfffbccSCorey Minyard { 7898bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7908bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7918bfffbccSCorey Minyard bool irqs_on; 7928bfffbccSCorey Minyard 7938bfffbccSCorey Minyard ibs->bmc_global_enables = val; 7948bfffbccSCorey Minyard 7958bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 7968bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 7978bfffbccSCorey Minyard 7988bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 7998bfffbccSCorey Minyard } 8008bfffbccSCorey Minyard 8018bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8028bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8038bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8048bfffbccSCorey Minyard unsigned int max_rsp_len) 8058bfffbccSCorey Minyard { 8068bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8078bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8088bfffbccSCorey Minyard 8098bfffbccSCorey Minyard /* Disable all interrupts */ 8108bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8118bfffbccSCorey Minyard 8128bfffbccSCorey Minyard if (k->reset) { 8138bfffbccSCorey Minyard k->reset(s, true); 8148bfffbccSCorey Minyard } 8158bfffbccSCorey Minyard } 8168bfffbccSCorey Minyard 8178bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8188bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8198bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8208bfffbccSCorey Minyard unsigned int max_rsp_len) 8218bfffbccSCorey Minyard { 8228bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8238bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8248bfffbccSCorey Minyard 8258bfffbccSCorey Minyard if (k->reset) { 8268bfffbccSCorey Minyard k->reset(s, false); 8278bfffbccSCorey Minyard } 8288bfffbccSCorey Minyard } 8298bfffbccSCorey Minyard 8308bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 8318bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8328bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8338bfffbccSCorey Minyard unsigned int max_rsp_len) 8348bfffbccSCorey Minyard { 8358bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 8368bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 8378bfffbccSCorey Minyard } 8388bfffbccSCorey Minyard 8398bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 8408bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8418bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8428bfffbccSCorey Minyard unsigned int max_rsp_len) 8438bfffbccSCorey Minyard { 8448bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->bmc_global_enables); 8458bfffbccSCorey Minyard } 8468bfffbccSCorey Minyard 8478bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 8488bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8498bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8508bfffbccSCorey Minyard unsigned int max_rsp_len) 8518bfffbccSCorey Minyard { 8528bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8538bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8548bfffbccSCorey Minyard 8558bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 8568bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 8578bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 8588bfffbccSCorey Minyard } 8598bfffbccSCorey Minyard 8608bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 8618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8628bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8638bfffbccSCorey Minyard unsigned int max_rsp_len) 8648bfffbccSCorey Minyard { 8658bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->msg_flags); 8668bfffbccSCorey Minyard } 8678bfffbccSCorey Minyard 8688bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 8698bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8708bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8718bfffbccSCorey Minyard unsigned int max_rsp_len) 8728bfffbccSCorey Minyard { 8738bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8748bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8758bfffbccSCorey Minyard unsigned int i; 8768bfffbccSCorey Minyard 8778bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 8788bfffbccSCorey Minyard rsp[2] = 0x80; 879d13ada5dSCédric Le Goater return; 8808bfffbccSCorey Minyard } 8818bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 8828bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->evtbuf[i]); 8838bfffbccSCorey Minyard } 8848bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 8858bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 8868bfffbccSCorey Minyard } 8878bfffbccSCorey Minyard 8888bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 8898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 8908bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 8918bfffbccSCorey Minyard unsigned int max_rsp_len) 8928bfffbccSCorey Minyard { 8938bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 8948bfffbccSCorey Minyard 8958bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 8968bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 8978bfffbccSCorey Minyard rsp[2] = 0x80; /* Queue empty */ 8988bfffbccSCorey Minyard goto out; 8998bfffbccSCorey Minyard } 9008bfffbccSCorey Minyard rsp[3] = 0; /* Channel 0 */ 9018bfffbccSCorey Minyard *rsp_len += 1; 9028bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 9038bfffbccSCorey Minyard memcpy(rsp + 4, msg->buf, msg->len); 9048bfffbccSCorey Minyard *rsp_len += msg->len; 9058bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9068bfffbccSCorey Minyard g_free(msg); 9078bfffbccSCorey Minyard 9088bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9098bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9108bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9118bfffbccSCorey Minyard 9128bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9138bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9148bfffbccSCorey Minyard } 9158bfffbccSCorey Minyard 9168bfffbccSCorey Minyard out: 9178bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 9188bfffbccSCorey Minyard return; 9198bfffbccSCorey Minyard } 9208bfffbccSCorey Minyard 9218bfffbccSCorey Minyard static unsigned char 9228bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 9238bfffbccSCorey Minyard { 9248bfffbccSCorey Minyard for (; size > 0; size--, data++) { 9258bfffbccSCorey Minyard csum += *data; 9268bfffbccSCorey Minyard } 9278bfffbccSCorey Minyard 9288bfffbccSCorey Minyard return -csum; 9298bfffbccSCorey Minyard } 9308bfffbccSCorey Minyard 9318bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 9328bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 9338bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 9348bfffbccSCorey Minyard unsigned int max_rsp_len) 9358bfffbccSCorey Minyard { 9368bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9378bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9388bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9398bfffbccSCorey Minyard uint8_t *buf; 9408bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 9418bfffbccSCorey Minyard 9428bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 9438bfffbccSCorey Minyard 9448bfffbccSCorey Minyard if (cmd[2] != 0) { 9458bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 9468bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 947d13ada5dSCédric Le Goater return; 9488bfffbccSCorey Minyard } 9498bfffbccSCorey Minyard 9508bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(10); 9518bfffbccSCorey Minyard if (cmd[3] != 0x40) { 9528bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 9538bfffbccSCorey Minyard rsp[2] = 0x83; /* NAK on write */ 954d13ada5dSCédric Le Goater return; 9558bfffbccSCorey Minyard } 9568bfffbccSCorey Minyard 9578bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 9588bfffbccSCorey Minyard cmd_len -= 3; 9598bfffbccSCorey Minyard 9608bfffbccSCorey Minyard /* 9618bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 9628bfffbccSCorey Minyard * be returned in the response. 9638bfffbccSCorey Minyard */ 9648bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 9658bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 966d13ada5dSCédric Le Goater return; /* No response */ 9678bfffbccSCorey Minyard } 9688bfffbccSCorey Minyard 9698bfffbccSCorey Minyard netfn = cmd[1] >> 2; 9708bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 9718bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 9728bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 9738bfffbccSCorey Minyard 9748bfffbccSCorey Minyard if (rqLun != 2) { 9758bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 976d13ada5dSCédric Le Goater return; 9778bfffbccSCorey Minyard } 9788bfffbccSCorey Minyard 9798bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 9808bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 9818bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 9828bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 9838bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 9848bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 9858bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 9868bfffbccSCorey Minyard msg->len = 6; 9878bfffbccSCorey Minyard 9888bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 9898bfffbccSCorey Minyard /* Not a command we handle. */ 9908bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 9918bfffbccSCorey Minyard goto end_msg; 9928bfffbccSCorey Minyard } 9938bfffbccSCorey Minyard 9948bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 9958bfffbccSCorey Minyard buf[0] = 0; 9968bfffbccSCorey Minyard buf[1] = 0; 9978bfffbccSCorey Minyard buf[2] = 0; 9988bfffbccSCorey Minyard buf[3] = 0; 9998bfffbccSCorey Minyard buf[4] = 0x51; 10008bfffbccSCorey Minyard buf[5] = 0; 10018bfffbccSCorey Minyard buf[6] = 0; 10028bfffbccSCorey Minyard buf[7] = 0; 10038bfffbccSCorey Minyard buf[8] = 0; 10048bfffbccSCorey Minyard buf[9] = 0; 10058bfffbccSCorey Minyard buf[10] = 0; 10068bfffbccSCorey Minyard msg->len += 11; 10078bfffbccSCorey Minyard 10088bfffbccSCorey Minyard end_msg: 10098bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 10108bfffbccSCorey Minyard msg->len++; 10118bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 10128bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 10138bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10148bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 10158bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 10168bfffbccSCorey Minyard } 10178bfffbccSCorey Minyard 10188bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 10198bfffbccSCorey Minyard { 10208bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 10218bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 10228bfffbccSCorey Minyard ibs->watchdog_running = 0; 10238bfffbccSCorey Minyard return; 10248bfffbccSCorey Minyard } 10258bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 10268bfffbccSCorey Minyard 10278bfffbccSCorey Minyard 10288bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 10298bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 10308bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 10318bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 10328bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 10338bfffbccSCorey Minyard } 10348bfffbccSCorey Minyard ibs->watchdog_running = 1; 10358bfffbccSCorey Minyard } 10368bfffbccSCorey Minyard 10378bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 10388bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10398bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 10408bfffbccSCorey Minyard unsigned int max_rsp_len) 10418bfffbccSCorey Minyard { 10428bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 10438bfffbccSCorey Minyard rsp[2] = 0x80; 1044d13ada5dSCédric Le Goater return; 10458bfffbccSCorey Minyard } 10468bfffbccSCorey Minyard do_watchdog_reset(ibs); 10478bfffbccSCorey Minyard } 10488bfffbccSCorey Minyard 10498bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 10508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 10518bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 10528bfffbccSCorey Minyard unsigned int max_rsp_len) 10538bfffbccSCorey Minyard { 10548bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10558bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10568bfffbccSCorey Minyard unsigned int val; 10578bfffbccSCorey Minyard 10588bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 10598bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 10608bfffbccSCorey Minyard if (val == 0 || val > 5) { 10618bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1062d13ada5dSCédric Le Goater return; 10638bfffbccSCorey Minyard } 10648bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 10658bfffbccSCorey Minyard switch (val) { 10668bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 10678bfffbccSCorey Minyard break; 10688bfffbccSCorey Minyard 10698bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 10708bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1); 10718bfffbccSCorey Minyard break; 10728bfffbccSCorey Minyard 10738bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 10748bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1); 10758bfffbccSCorey Minyard break; 10768bfffbccSCorey Minyard 10778bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 10788bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1); 10798bfffbccSCorey Minyard break; 10808bfffbccSCorey Minyard 10818bfffbccSCorey Minyard default: 10828bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 10838bfffbccSCorey Minyard } 10848bfffbccSCorey Minyard if (rsp[2]) { 10858bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1086d13ada5dSCédric Le Goater return; 10878bfffbccSCorey Minyard } 10888bfffbccSCorey Minyard 10898bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 10908bfffbccSCorey Minyard switch (val) { 10918bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 10928bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 10938bfffbccSCorey Minyard break; 10948bfffbccSCorey Minyard 10958bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 10968bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 10978bfffbccSCorey Minyard /* NMI not supported. */ 10988bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1099d13ada5dSCédric Le Goater return; 11008bfffbccSCorey Minyard } 11018bfffbccSCorey Minyard default: 11028bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11038bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1104d13ada5dSCédric Le Goater return; 11058bfffbccSCorey Minyard } 11068bfffbccSCorey Minyard 11078bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11088bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11098bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11108bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 11118bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 11128bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 11138bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 11148bfffbccSCorey Minyard do_watchdog_reset(ibs); 11158bfffbccSCorey Minyard } else { 11168bfffbccSCorey Minyard ibs->watchdog_running = 0; 11178bfffbccSCorey Minyard } 11188bfffbccSCorey Minyard } 11198bfffbccSCorey Minyard 11208bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 11218bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11228bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11238bfffbccSCorey Minyard unsigned int max_rsp_len) 11248bfffbccSCorey Minyard { 11258bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_use); 11268bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_action); 11278bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout); 11288bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_expired); 11298bfffbccSCorey Minyard if (ibs->watchdog_running) { 11308bfffbccSCorey Minyard long timeout; 11318bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 11328bfffbccSCorey Minyard / 100000000); 11338bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(timeout & 0xff); 11348bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff); 11358bfffbccSCorey Minyard } else { 11368bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 11378bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 11388bfffbccSCorey Minyard } 11398bfffbccSCorey Minyard } 11408bfffbccSCorey Minyard 11418bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 11428bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11438bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11448bfffbccSCorey Minyard unsigned int max_rsp_len) 11458bfffbccSCorey Minyard { 11468bfffbccSCorey Minyard unsigned int i; 11478bfffbccSCorey Minyard 11488bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */ 11498bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff); 11508bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff); 11518bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 11528bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 11538bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 11548bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]); 11558bfffbccSCorey Minyard } 11568bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 11578bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]); 11588bfffbccSCorey Minyard } 11598bfffbccSCorey Minyard /* Only modal support, reserve supported */ 11608bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22); 11618bfffbccSCorey Minyard } 11628bfffbccSCorey Minyard 11638bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 11648bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11658bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11668bfffbccSCorey Minyard unsigned int max_rsp_len) 11678bfffbccSCorey Minyard { 11688bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff); 11698bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff); 11708bfffbccSCorey Minyard } 11718bfffbccSCorey Minyard 11728bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 11738bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 11748bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 11758bfffbccSCorey Minyard unsigned int max_rsp_len) 11768bfffbccSCorey Minyard { 11778bfffbccSCorey Minyard unsigned int pos; 11788bfffbccSCorey Minyard uint16_t nextrec; 1179a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 11808bfffbccSCorey Minyard 11818bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 11828bfffbccSCorey Minyard if (cmd[6]) { 11838bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 11848bfffbccSCorey Minyard } 11858bfffbccSCorey Minyard pos = 0; 11868bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 11878bfffbccSCorey Minyard &pos, &nextrec)) { 11888bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1189d13ada5dSCédric Le Goater return; 11908bfffbccSCorey Minyard } 1191a2295f0aSCédric Le Goater 1192a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1193a2295f0aSCédric Le Goater 1194a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 11958bfffbccSCorey Minyard rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; 1196d13ada5dSCédric Le Goater return; 11978bfffbccSCorey Minyard } 11988bfffbccSCorey Minyard 11998bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(nextrec & 0xff); 12008bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); 12018bfffbccSCorey Minyard 12028bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1203a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 12048bfffbccSCorey Minyard } 12058bfffbccSCorey Minyard 12068bfffbccSCorey Minyard if ((cmd[7] + *rsp_len) > max_rsp_len) { 12078bfffbccSCorey Minyard rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 1208d13ada5dSCédric Le Goater return; 12098bfffbccSCorey Minyard } 12108bfffbccSCorey Minyard memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 12118bfffbccSCorey Minyard *rsp_len += cmd[7]; 12128bfffbccSCorey Minyard } 12138bfffbccSCorey Minyard 12148bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 12158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12168bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12178bfffbccSCorey Minyard unsigned int max_rsp_len) 12188bfffbccSCorey Minyard { 12198bfffbccSCorey Minyard uint16_t recid; 1220a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 12218bfffbccSCorey Minyard 1222a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 12238bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1224d13ada5dSCédric Le Goater return; 12258bfffbccSCorey Minyard } 12268bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(recid & 0xff); 12278bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((recid >> 8) & 0xff); 12288bfffbccSCorey Minyard } 12298bfffbccSCorey Minyard 12308bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 12318bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12328bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12338bfffbccSCorey Minyard unsigned int max_rsp_len) 12348bfffbccSCorey Minyard { 12358bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 12368bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 12378bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 12388bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1239d13ada5dSCédric Le Goater return; 12408bfffbccSCorey Minyard } 12418bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 12428bfffbccSCorey Minyard ibs->sdr.next_free = 0; 12438bfffbccSCorey Minyard ibs->sdr.overflow = 0; 12448bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 12458bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 12468bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 12478bfffbccSCorey Minyard } else if (cmd[7] == 0) { 12488bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 12498bfffbccSCorey Minyard } else { 12508bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 12518bfffbccSCorey Minyard return; 12528bfffbccSCorey Minyard } 1253d13ada5dSCédric Le Goater } 12548bfffbccSCorey Minyard 12558bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 12568bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12578bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12588bfffbccSCorey Minyard unsigned int max_rsp_len) 12598bfffbccSCorey Minyard { 12608bfffbccSCorey Minyard unsigned int i, val; 12618bfffbccSCorey Minyard 12628bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */ 12638bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff); 12648bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff); 12658bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 12668bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 12678bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 12688bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 12698bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]); 12708bfffbccSCorey Minyard } 12718bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 12728bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]); 12738bfffbccSCorey Minyard } 12748bfffbccSCorey Minyard /* Only support Reserve SEL */ 12758bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); 12768bfffbccSCorey Minyard } 12778bfffbccSCorey Minyard 12788bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 12798bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12808bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12818bfffbccSCorey Minyard unsigned int max_rsp_len) 12828bfffbccSCorey Minyard { 12838bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff); 12848bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff); 12858bfffbccSCorey Minyard } 12868bfffbccSCorey Minyard 12878bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 12888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 12898bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 12908bfffbccSCorey Minyard unsigned int max_rsp_len) 12918bfffbccSCorey Minyard { 12928bfffbccSCorey Minyard unsigned int val; 12938bfffbccSCorey Minyard 12948bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 12958bfffbccSCorey Minyard if (cmd[6]) { 12968bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 12978bfffbccSCorey Minyard } 12988bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 12998bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1300d13ada5dSCédric Le Goater return; 13018bfffbccSCorey Minyard } 13028bfffbccSCorey Minyard if (cmd[6] > 15) { 13038bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1304d13ada5dSCédric Le Goater return; 13058bfffbccSCorey Minyard } 13068bfffbccSCorey Minyard if (cmd[7] == 0xff) { 13078bfffbccSCorey Minyard cmd[7] = 16; 13088bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 13098bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1310d13ada5dSCédric Le Goater return; 13118bfffbccSCorey Minyard } else { 13128bfffbccSCorey Minyard cmd[7] += cmd[6]; 13138bfffbccSCorey Minyard } 13148bfffbccSCorey Minyard 13158bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 13168bfffbccSCorey Minyard if (val == 0xffff) { 13178bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 13188bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 13198bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1320d13ada5dSCédric Le Goater return; 13218bfffbccSCorey Minyard } 13228bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 13238bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 13248bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 13258bfffbccSCorey Minyard } else { 13268bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val + 1) & 0xff); 13278bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff); 13288bfffbccSCorey Minyard } 13298bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 13308bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]); 13318bfffbccSCorey Minyard } 13328bfffbccSCorey Minyard } 13338bfffbccSCorey Minyard 13348bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 13358bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13368bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13378bfffbccSCorey Minyard unsigned int max_rsp_len) 13388bfffbccSCorey Minyard { 13398bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(18); 13408bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 13418bfffbccSCorey Minyard rsp[2] = IPMI_CC_OUT_OF_SPACE; 1342d13ada5dSCédric Le Goater return; 13438bfffbccSCorey Minyard } 13448bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 13458bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[2]); 13468bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[3]); 13478bfffbccSCorey Minyard } 13488bfffbccSCorey Minyard 13498bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 13508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13518bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13528bfffbccSCorey Minyard unsigned int max_rsp_len) 13538bfffbccSCorey Minyard { 13548bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 13558bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 13568bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13578bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1358d13ada5dSCédric Le Goater return; 13598bfffbccSCorey Minyard } 13608bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 13618bfffbccSCorey Minyard ibs->sel.next_free = 0; 13628bfffbccSCorey Minyard ibs->sel.overflow = 0; 13638bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 13648bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 13658bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 13668bfffbccSCorey Minyard } else if (cmd[7] == 0) { 13678bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 13688bfffbccSCorey Minyard } else { 13698bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 13708bfffbccSCorey Minyard return; 13718bfffbccSCorey Minyard } 1372d13ada5dSCédric Le Goater } 13738bfffbccSCorey Minyard 13748bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 13758bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13768bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13778bfffbccSCorey Minyard unsigned int max_rsp_len) 13788bfffbccSCorey Minyard { 13798bfffbccSCorey Minyard uint32_t val; 13808bfffbccSCorey Minyard struct ipmi_time now; 13818bfffbccSCorey Minyard 13828bfffbccSCorey Minyard ipmi_gettime(&now); 13838bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 13848bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 13858bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 13868bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 16) & 0xff); 13878bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 24) & 0xff); 13888bfffbccSCorey Minyard } 13898bfffbccSCorey Minyard 13908bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 13918bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 13928bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 13938bfffbccSCorey Minyard unsigned int max_rsp_len) 13948bfffbccSCorey Minyard { 13958bfffbccSCorey Minyard uint32_t val; 13968bfffbccSCorey Minyard struct ipmi_time now; 13978bfffbccSCorey Minyard 13988bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(6); 13998bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 14008bfffbccSCorey Minyard ipmi_gettime(&now); 14018bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 14028bfffbccSCorey Minyard } 14038bfffbccSCorey Minyard 14048bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 14058bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14068bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14078bfffbccSCorey Minyard unsigned int max_rsp_len) 14088bfffbccSCorey Minyard { 14098bfffbccSCorey Minyard IPMISensor *sens; 14108bfffbccSCorey Minyard 14118bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 14128bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 14138bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14148bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1415d13ada5dSCédric Le Goater return; 14168bfffbccSCorey Minyard } 14178bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14188bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 14198bfffbccSCorey Minyard case 0: /* Do not change */ 14208bfffbccSCorey Minyard break; 14218bfffbccSCorey Minyard case 1: /* Enable bits */ 14228bfffbccSCorey Minyard if (cmd_len > 4) { 14238bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 14248bfffbccSCorey Minyard } 14258bfffbccSCorey Minyard if (cmd_len > 5) { 14268bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 14278bfffbccSCorey Minyard } 14288bfffbccSCorey Minyard if (cmd_len > 6) { 14298bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 14308bfffbccSCorey Minyard } 14318bfffbccSCorey Minyard if (cmd_len > 7) { 14328bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 14338bfffbccSCorey Minyard } 14348bfffbccSCorey Minyard break; 14358bfffbccSCorey Minyard case 2: /* Disable bits */ 14368bfffbccSCorey Minyard if (cmd_len > 4) { 14378bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 14388bfffbccSCorey Minyard } 14398bfffbccSCorey Minyard if (cmd_len > 5) { 14408bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 14418bfffbccSCorey Minyard } 14428bfffbccSCorey Minyard if (cmd_len > 6) { 14438bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 14448bfffbccSCorey Minyard } 14458bfffbccSCorey Minyard if (cmd_len > 7) { 14468bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 14478bfffbccSCorey Minyard } 14488bfffbccSCorey Minyard break; 14498bfffbccSCorey Minyard case 3: 14508bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1451d13ada5dSCédric Le Goater return; 14528bfffbccSCorey Minyard } 14538bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 14548bfffbccSCorey Minyard } 14558bfffbccSCorey Minyard 14568bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 14578bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14588bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14598bfffbccSCorey Minyard unsigned int max_rsp_len) 14608bfffbccSCorey Minyard { 14618bfffbccSCorey Minyard IPMISensor *sens; 14628bfffbccSCorey Minyard 14638bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 14648bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 14658bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14668bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1467d13ada5dSCédric Le Goater return; 14688bfffbccSCorey Minyard } 14698bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14708bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 14718bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff); 14728bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff); 14738bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff); 14748bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff); 14758bfffbccSCorey Minyard } 14768bfffbccSCorey Minyard 14778bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 14788bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 14798bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 14808bfffbccSCorey Minyard unsigned int max_rsp_len) 14818bfffbccSCorey Minyard { 14828bfffbccSCorey Minyard IPMISensor *sens; 14838bfffbccSCorey Minyard 14848bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 14858bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 14868bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14878bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1488d13ada5dSCédric Le Goater return; 14898bfffbccSCorey Minyard } 14908bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14918bfffbccSCorey Minyard 14928bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 14938bfffbccSCorey Minyard /* Just clear everything */ 14948bfffbccSCorey Minyard sens->states = 0; 14958bfffbccSCorey Minyard return; 14968bfffbccSCorey Minyard } 1497d13ada5dSCédric Le Goater } 14988bfffbccSCorey Minyard 14998bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 15008bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 15018bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 15028bfffbccSCorey Minyard unsigned int max_rsp_len) 15038bfffbccSCorey Minyard { 15048bfffbccSCorey Minyard IPMISensor *sens; 15058bfffbccSCorey Minyard 15068bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 15078bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 15088bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15098bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1510d13ada5dSCédric Le Goater return; 15118bfffbccSCorey Minyard } 15128bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15138bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 15148bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 15158bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_states & 0xff); 15168bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff); 15178bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff); 15188bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff); 15198bfffbccSCorey Minyard } 15208bfffbccSCorey Minyard 15218bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 15228bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 15238bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 15248bfffbccSCorey Minyard unsigned int max_rsp_len) 15258bfffbccSCorey Minyard { 15268bfffbccSCorey Minyard IPMISensor *sens; 15278bfffbccSCorey Minyard 15288bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 15298bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 15308bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15318bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1532d13ada5dSCédric Le Goater return; 15338bfffbccSCorey Minyard } 15348bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15358bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 15368bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 15378bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->states & 0xff); 15388bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 15398bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff); 15408bfffbccSCorey Minyard } 15418bfffbccSCorey Minyard } 15428bfffbccSCorey Minyard 1543728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1544728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1545728710e1SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 1546728710e1SCédric Le Goater unsigned int max_rsp_len) 1547728710e1SCédric Le Goater { 1548728710e1SCédric Le Goater IPMISensor *sens; 1549728710e1SCédric Le Goater 1550728710e1SCédric Le Goater 1551728710e1SCédric Le Goater IPMI_CHECK_CMD_LEN(5); 1552728710e1SCédric Le Goater if ((cmd[2] > MAX_SENSORS) || 1553728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1554728710e1SCédric Le Goater rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1555728710e1SCédric Le Goater return; 1556728710e1SCédric Le Goater } 1557728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1558728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1559728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1560728710e1SCédric Le Goater } 1561728710e1SCédric Le Goater 1562728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1563728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1564728710e1SCédric Le Goater uint8_t *rsp, unsigned int *rsp_len, 1565728710e1SCédric Le Goater unsigned int max_rsp_len) 1566728710e1SCédric Le Goater { 1567728710e1SCédric Le Goater IPMISensor *sens; 1568728710e1SCédric Le Goater 1569728710e1SCédric Le Goater 1570728710e1SCédric Le Goater IPMI_CHECK_CMD_LEN(3); 1571728710e1SCédric Le Goater if ((cmd[2] > MAX_SENSORS) || 1572728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1573728710e1SCédric Le Goater rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1574728710e1SCédric Le Goater return; 1575728710e1SCédric Le Goater } 1576728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1577728710e1SCédric Le Goater IPMI_ADD_RSP_DATA(sens->sensor_type); 1578728710e1SCédric Le Goater IPMI_ADD_RSP_DATA(sens->evt_reading_type_code); 1579728710e1SCédric Le Goater } 1580728710e1SCédric Le Goater 1581728710e1SCédric Le Goater 158262a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 15838bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, 15848bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, 1585*b7088392SCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = chassis_control, 1586*b7088392SCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = chassis_get_sys_restart_cause 15878bfffbccSCorey Minyard }; 15888bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 158962a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 15908bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 15918bfffbccSCorey Minyard }; 15928bfffbccSCorey Minyard 159362a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 15948bfffbccSCorey Minyard [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable, 15958bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable, 15968bfffbccSCorey Minyard [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts, 15978bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status, 1598728710e1SCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading, 1599728710e1SCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = set_sensor_type, 1600728710e1SCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = get_sensor_type, 16018bfffbccSCorey Minyard }; 16028bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 160362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 16048bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 16058bfffbccSCorey Minyard }; 16068bfffbccSCorey Minyard 160762a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 16088bfffbccSCorey Minyard [IPMI_CMD_GET_DEVICE_ID] = get_device_id, 16098bfffbccSCorey Minyard [IPMI_CMD_COLD_RESET] = cold_reset, 16108bfffbccSCorey Minyard [IPMI_CMD_WARM_RESET] = warm_reset, 16118bfffbccSCorey Minyard [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables, 16128bfffbccSCorey Minyard [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables, 16138bfffbccSCorey Minyard [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags, 16148bfffbccSCorey Minyard [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags, 16158bfffbccSCorey Minyard [IPMI_CMD_GET_MSG] = get_msg, 16168bfffbccSCorey Minyard [IPMI_CMD_SEND_MSG] = send_msg, 16178bfffbccSCorey Minyard [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf, 16188bfffbccSCorey Minyard [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer, 16198bfffbccSCorey Minyard [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer, 16208bfffbccSCorey Minyard [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer, 16218bfffbccSCorey Minyard }; 16228bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 162362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 16248bfffbccSCorey Minyard .cmd_handlers = app_cmds 16258bfffbccSCorey Minyard }; 16268bfffbccSCorey Minyard 162762a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 16288bfffbccSCorey Minyard [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info, 16298bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep, 16308bfffbccSCorey Minyard [IPMI_CMD_GET_SDR] = get_sdr, 16318bfffbccSCorey Minyard [IPMI_CMD_ADD_SDR] = add_sdr, 16328bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep, 16338bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_INFO] = get_sel_info, 16348bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SEL] = reserve_sel, 16358bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry, 16368bfffbccSCorey Minyard [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry, 16378bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SEL] = clear_sel, 16388bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_TIME] = get_sel_time, 16398bfffbccSCorey Minyard [IPMI_CMD_SET_SEL_TIME] = set_sel_time, 16408bfffbccSCorey Minyard }; 16418bfffbccSCorey Minyard 16428bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 164362a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 16448bfffbccSCorey Minyard .cmd_handlers = storage_cmds 16458bfffbccSCorey Minyard }; 16468bfffbccSCorey Minyard 16478bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 16488bfffbccSCorey Minyard { 16498bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 16508bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 16518bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 16528bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 16538bfffbccSCorey Minyard } 16548bfffbccSCorey Minyard 16558bfffbccSCorey Minyard static const uint8_t init_sdrs[] = { 16568bfffbccSCorey Minyard /* Watchdog device */ 16578bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 16588bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 16598bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16608bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 16618bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 16628bfffbccSCorey Minyard /* End */ 16638bfffbccSCorey Minyard 0xff, 0xff, 0x00, 0x00, 0x00 16648bfffbccSCorey Minyard }; 16658bfffbccSCorey Minyard 1666bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1667bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1668bd66bcfcSCorey Minyard .version_id = 1, 1669bd66bcfcSCorey Minyard .minimum_version_id = 1, 1670bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1671bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1672bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1673bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1674bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1675bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1676bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1677bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1678bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1679bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1680bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1681bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1682bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1683bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1684bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1685bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1686bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1687bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1688bd66bcfcSCorey Minyard IPMIBmcSim), 1689bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1690bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1691bd66bcfcSCorey Minyard } 1692bd66bcfcSCorey Minyard }; 1693bd66bcfcSCorey Minyard 16948bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj) 16958bfffbccSCorey Minyard { 16968bfffbccSCorey Minyard IPMIBmc *b = IPMI_BMC(obj); 16978bfffbccSCorey Minyard unsigned int i; 16988bfffbccSCorey Minyard unsigned int recid; 16998bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 17008bfffbccSCorey Minyard 17018bfffbccSCorey Minyard qemu_mutex_init(&ibs->lock); 17028bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 17038bfffbccSCorey Minyard 17048bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 17058bfffbccSCorey Minyard ibs->device_id = 0x20; 17068bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1707*b7088392SCédric Le Goater ibs->restart_cause = 0; 17088bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 17098bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 17108bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 17118bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 17128bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 17138bfffbccSCorey Minyard } 17148bfffbccSCorey Minyard 17158bfffbccSCorey Minyard for (i = 0;;) { 1716a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 17178bfffbccSCorey Minyard int len; 1718a2295f0aSCédric Le Goater if ((i + IPMI_SDR_HEADER_SIZE) > sizeof(init_sdrs)) { 17197cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 17208bfffbccSCorey Minyard return; 17218bfffbccSCorey Minyard } 1722a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &init_sdrs[i]; 1723a2295f0aSCédric Le Goater len = ipmi_sdr_length(sdrh); 1724a2295f0aSCédric Le Goater recid = ipmi_sdr_recid(sdrh); 17258bfffbccSCorey Minyard if (recid == 0xffff) { 17268bfffbccSCorey Minyard break; 17278bfffbccSCorey Minyard } 1728792afddbSCédric Le Goater if ((i + len) > sizeof(init_sdrs)) { 17297cfa06a2SCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 17308bfffbccSCorey Minyard return; 17318bfffbccSCorey Minyard } 1732a2295f0aSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 1733792afddbSCédric Le Goater i += len; 17348bfffbccSCorey Minyard } 17358bfffbccSCorey Minyard 17368bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 17378bfffbccSCorey Minyard register_cmds(ibs); 17388bfffbccSCorey Minyard 17398bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1740bd66bcfcSCorey Minyard 1741bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 17428bfffbccSCorey Minyard } 17438bfffbccSCorey Minyard 17448bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 17458bfffbccSCorey Minyard { 17468bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 17478bfffbccSCorey Minyard 17488bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 17498bfffbccSCorey Minyard } 17508bfffbccSCorey Minyard 17518bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 17528bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 17538bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 17548bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 17558bfffbccSCorey Minyard .instance_init = ipmi_sim_init, 17568bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 17578bfffbccSCorey Minyard }; 17588bfffbccSCorey Minyard 17598bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 17608bfffbccSCorey Minyard { 17618bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 17628bfffbccSCorey Minyard } 17638bfffbccSCorey Minyard 17648bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1765