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