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