18bfffbccSCorey Minyard /* 28bfffbccSCorey Minyard * IPMI BMC emulation 38bfffbccSCorey Minyard * 48bfffbccSCorey Minyard * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC 58bfffbccSCorey Minyard * 68bfffbccSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 78bfffbccSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 88bfffbccSCorey Minyard * in the Software without restriction, including without limitation the rights 98bfffbccSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108bfffbccSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 118bfffbccSCorey Minyard * furnished to do so, subject to the following conditions: 128bfffbccSCorey Minyard * 138bfffbccSCorey Minyard * The above copyright notice and this permission notice shall be included in 148bfffbccSCorey Minyard * all copies or substantial portions of the Software. 158bfffbccSCorey Minyard * 168bfffbccSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178bfffbccSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188bfffbccSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198bfffbccSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208bfffbccSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218bfffbccSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228bfffbccSCorey Minyard * THE SOFTWARE. 238bfffbccSCorey Minyard */ 248bfffbccSCorey Minyard 250430891cSPeter Maydell #include "qemu/osdep.h" 2652ba4d50SCédric Le Goater #include "sysemu/sysemu.h" 278bfffbccSCorey Minyard #include "qemu/timer.h" 288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 298bfffbccSCorey Minyard #include "qemu/error-report.h" 30*8c6fd7f3SCédric Le Goater #include "hw/loader.h" 318bfffbccSCorey Minyard 328bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 338bfffbccSCorey Minyard 348bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 358bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 368bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 37b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 388bfffbccSCorey Minyard 398bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 408bfffbccSCorey Minyard 418bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 428bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 438bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 448bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 458bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 46728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e 47728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f 488bfffbccSCorey Minyard 498bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 508bfffbccSCorey Minyard 518bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 528bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 538bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 5452ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06 5552ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07 5652ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID 0x08 578bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 588bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 598bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 608bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 618bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 628bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 638bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 648bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 658bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 668bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 678bfffbccSCorey Minyard 688bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 698bfffbccSCorey Minyard 708bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 718bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 728bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 738bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 748bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 758bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 768bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 778bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 798bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 808bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 818bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 828bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 838bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 848bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 858bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 868bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 878bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 888bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 898bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 908bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 918bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 928bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 938bfffbccSCorey Minyard 948bfffbccSCorey Minyard 958bfffbccSCorey Minyard /* Same as a timespec struct. */ 968bfffbccSCorey Minyard struct ipmi_time { 978bfffbccSCorey Minyard long tv_sec; 988bfffbccSCorey Minyard long tv_nsec; 998bfffbccSCorey Minyard }; 1008bfffbccSCorey Minyard 1018bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 1028bfffbccSCorey Minyard 1038bfffbccSCorey Minyard typedef struct IPMISel { 1048bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 1058bfffbccSCorey Minyard unsigned int next_free; 1068bfffbccSCorey Minyard long time_offset; 1078bfffbccSCorey Minyard uint16_t reservation; 1088bfffbccSCorey Minyard uint8_t last_addition[4]; 1098bfffbccSCorey Minyard uint8_t last_clear[4]; 1108bfffbccSCorey Minyard uint8_t overflow; 1118bfffbccSCorey Minyard } IPMISel; 1128bfffbccSCorey Minyard 1138bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1148bfffbccSCorey Minyard 1158bfffbccSCorey Minyard typedef struct IPMISdr { 1168bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1178bfffbccSCorey Minyard unsigned int next_free; 1188bfffbccSCorey Minyard uint16_t next_rec_id; 1198bfffbccSCorey Minyard uint16_t reservation; 1208bfffbccSCorey Minyard uint8_t last_addition[4]; 1218bfffbccSCorey Minyard uint8_t last_clear[4]; 1228bfffbccSCorey Minyard uint8_t overflow; 1238bfffbccSCorey Minyard } IPMISdr; 1248bfffbccSCorey Minyard 1258bfffbccSCorey Minyard typedef struct IPMISensor { 1268bfffbccSCorey Minyard uint8_t status; 1278bfffbccSCorey Minyard uint8_t reading; 1288bfffbccSCorey Minyard uint16_t states_suppt; 1298bfffbccSCorey Minyard uint16_t assert_suppt; 1308bfffbccSCorey Minyard uint16_t deassert_suppt; 1318bfffbccSCorey Minyard uint16_t states; 1328bfffbccSCorey Minyard uint16_t assert_states; 1338bfffbccSCorey Minyard uint16_t deassert_states; 1348bfffbccSCorey Minyard uint16_t assert_enable; 1358bfffbccSCorey Minyard uint16_t deassert_enable; 1368bfffbccSCorey Minyard uint8_t sensor_type; 1378bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1388bfffbccSCorey Minyard } IPMISensor; 1398bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1408bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1418bfffbccSCorey Minyard !!(v)) 1428bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1438bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1448bfffbccSCorey Minyard ((!!(v)) << 6)) 1458bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1468bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1478bfffbccSCorey Minyard ((!!(v)) << 7)) 1488bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1498bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1508bfffbccSCorey Minyard (v & 0xc0)) 1518bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1528bfffbccSCorey Minyard 1538bfffbccSCorey Minyard #define MAX_SENSORS 20 1548bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1558bfffbccSCorey Minyard 1568bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 157a580d820SCédric Le Goater typedef struct RspBuffer RspBuffer; 1588bfffbccSCorey Minyard 1598bfffbccSCorey Minyard #define MAX_NETFNS 64 1604f298a4bSCédric Le Goater 1614f298a4bSCédric Le Goater typedef struct IPMICmdHandler { 1624f298a4bSCédric Le Goater void (*cmd_handler)(IPMIBmcSim *s, 1638bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 164a580d820SCédric Le Goater RspBuffer *rsp); 1654f298a4bSCédric Le Goater unsigned int cmd_len_min; 1664f298a4bSCédric Le Goater } IPMICmdHandler; 1674f298a4bSCédric Le Goater 1688bfffbccSCorey Minyard typedef struct IPMINetfn { 1698bfffbccSCorey Minyard unsigned int cmd_nums; 1708bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 1718bfffbccSCorey Minyard } IPMINetfn; 1728bfffbccSCorey Minyard 1738bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1748bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1758bfffbccSCorey Minyard uint8_t len; 1768bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1778bfffbccSCorey Minyard } IPMIRcvBufEntry; 1788bfffbccSCorey Minyard 1798bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 1808bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 1818bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 1828bfffbccSCorey Minyard struct IPMIBmcSim { 1838bfffbccSCorey Minyard IPMIBmc parent; 1848bfffbccSCorey Minyard 1858bfffbccSCorey Minyard QEMUTimer *timer; 1868bfffbccSCorey Minyard 1878bfffbccSCorey Minyard uint8_t bmc_global_enables; 1888bfffbccSCorey Minyard uint8_t msg_flags; 1898bfffbccSCorey Minyard 1908bfffbccSCorey Minyard bool watchdog_initialized; 1918bfffbccSCorey Minyard uint8_t watchdog_use; 1928bfffbccSCorey Minyard uint8_t watchdog_action; 1938bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 1948bfffbccSCorey Minyard bool watchdog_expired; 1958bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 1968bfffbccSCorey Minyard 1978bfffbccSCorey Minyard bool watchdog_running; 1988bfffbccSCorey Minyard bool watchdog_preaction_ran; 1998bfffbccSCorey Minyard int64_t watchdog_expiry; 2008bfffbccSCorey Minyard 2018bfffbccSCorey Minyard uint8_t device_id; 2028bfffbccSCorey Minyard uint8_t ipmi_version; 2038bfffbccSCorey Minyard uint8_t device_rev; 2048bfffbccSCorey Minyard uint8_t fwrev1; 2058bfffbccSCorey Minyard uint8_t fwrev2; 2068bfffbccSCorey Minyard uint8_t mfg_id[3]; 2078bfffbccSCorey Minyard uint8_t product_id[2]; 2088bfffbccSCorey Minyard 209b7088392SCédric Le Goater uint8_t restart_cause; 210b7088392SCédric Le Goater 21152ba4d50SCédric Le Goater uint8_t acpi_power_state[2]; 21252ba4d50SCédric Le Goater uint8_t uuid[16]; 21352ba4d50SCédric Le Goater 2148bfffbccSCorey Minyard IPMISel sel; 2158bfffbccSCorey Minyard IPMISdr sdr; 2168bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 217*8c6fd7f3SCédric Le Goater char *sdr_filename; 2188bfffbccSCorey Minyard 2198bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 2208bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 2218bfffbccSCorey Minyard 2228bfffbccSCorey Minyard /* We allow one event in the buffer */ 2238bfffbccSCorey Minyard uint8_t evtbuf[16]; 2248bfffbccSCorey Minyard 2258bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 2268bfffbccSCorey Minyard }; 2278bfffbccSCorey Minyard 2288bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 2298bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 2308bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 2318bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 2328bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 2338bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 2348bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 2358bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 2368bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 2378bfffbccSCorey Minyard 2388bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 2398bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 2408bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 2418bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 2428bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 2438bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 2448bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 2458bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 2468bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 2478bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 2488bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 2498bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 2508bfffbccSCorey Minyard 2518bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 2668bfffbccSCorey Minyard 267a580d820SCédric Le Goater struct RspBuffer { 268a580d820SCédric Le Goater uint8_t buffer[MAX_IPMI_MSG_SIZE]; 269a580d820SCédric Le Goater unsigned int len; 270a580d820SCédric Le Goater }; 271a580d820SCédric Le Goater 272a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { } 2738bfffbccSCorey Minyard 2746acb971aSCédric Le Goater static inline void rsp_buffer_set_error(RspBuffer *rsp, uint8_t byte) 2756acb971aSCédric Le Goater { 2766acb971aSCédric Le Goater rsp->buffer[2] = byte; 2776acb971aSCédric Le Goater } 2786acb971aSCédric Le Goater 2798bfffbccSCorey Minyard /* Add a byte to the response. */ 280a580d820SCédric Le Goater static inline void rsp_buffer_push(RspBuffer *rsp, uint8_t byte) 281a580d820SCédric Le Goater { 282a580d820SCédric Le Goater if (rsp->len >= sizeof(rsp->buffer)) { 2836acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 284a580d820SCédric Le Goater return; 285a580d820SCédric Le Goater } 286a580d820SCédric Le Goater rsp->buffer[rsp->len++] = byte; 287a580d820SCédric Le Goater } 288a580d820SCédric Le Goater 289a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes, 290a580d820SCédric Le Goater unsigned int n) 291a580d820SCédric Le Goater { 292a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) { 2936acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 294a580d820SCédric Le Goater return; 295a580d820SCédric Le Goater } 296a580d820SCédric Le Goater 297a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n); 298a580d820SCédric Le Goater rsp->len += n; 299a580d820SCédric Le Goater } 3008bfffbccSCorey Minyard 3018bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 3028bfffbccSCorey Minyard 3038bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 3048bfffbccSCorey Minyard { 3058bfffbccSCorey Minyard int64_t stime; 3068bfffbccSCorey Minyard 3078bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 3088bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 3098bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 3108bfffbccSCorey Minyard } 3118bfffbccSCorey Minyard 3128bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 3138bfffbccSCorey Minyard { 3148bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 3158bfffbccSCorey Minyard } 3168bfffbccSCorey Minyard 3178bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 3188bfffbccSCorey Minyard { 3198bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3208bfffbccSCorey Minyard 3218bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3228bfffbccSCorey Minyard } 3238bfffbccSCorey Minyard 3248bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3258bfffbccSCorey Minyard { 3268bfffbccSCorey Minyard unsigned int val; 3278bfffbccSCorey Minyard struct ipmi_time now; 3288bfffbccSCorey Minyard 3298bfffbccSCorey Minyard ipmi_gettime(&now); 3308bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3318bfffbccSCorey Minyard ts[0] = val & 0xff; 3328bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3338bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3348bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3358bfffbccSCorey Minyard } 3368bfffbccSCorey Minyard 3378bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3388bfffbccSCorey Minyard { 3398bfffbccSCorey Minyard sdr->reservation++; 3408bfffbccSCorey Minyard if (sdr->reservation == 0) { 3418bfffbccSCorey Minyard sdr->reservation = 1; 3428bfffbccSCorey Minyard } 3438bfffbccSCorey Minyard } 3448bfffbccSCorey Minyard 345a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 346a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3478bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3488bfffbccSCorey Minyard { 349a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 350a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 351a2295f0aSCédric Le Goater 352a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3538bfffbccSCorey Minyard return 1; 3548bfffbccSCorey Minyard } 3558bfffbccSCorey Minyard 356a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3578bfffbccSCorey Minyard return 1; 3588bfffbccSCorey Minyard } 3598bfffbccSCorey Minyard 3608bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3618bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3628bfffbccSCorey Minyard return 1; 3638bfffbccSCorey Minyard } 3648bfffbccSCorey Minyard 365a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 366a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 367a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 368a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3698bfffbccSCorey Minyard 3708bfffbccSCorey Minyard if (recid) { 3718bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3728bfffbccSCorey Minyard } 3738bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3748bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3758bfffbccSCorey Minyard ibs->sdr.next_free += len; 3768bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3778bfffbccSCorey Minyard return 0; 3788bfffbccSCorey Minyard } 3798bfffbccSCorey Minyard 3808bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3818bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3828bfffbccSCorey Minyard { 3838bfffbccSCorey Minyard unsigned int pos = *retpos; 3848bfffbccSCorey Minyard 3858bfffbccSCorey Minyard while (pos < sdr->next_free) { 386a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 387a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 388a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 389a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 3908bfffbccSCorey Minyard 3918bfffbccSCorey Minyard if (trec == recid) { 3928bfffbccSCorey Minyard if (nextrec) { 3938bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3948bfffbccSCorey Minyard *nextrec = 0xffff; 3958bfffbccSCorey Minyard } else { 3968bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3978bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3988bfffbccSCorey Minyard } 3998bfffbccSCorey Minyard } 4008bfffbccSCorey Minyard *retpos = pos; 4018bfffbccSCorey Minyard return 0; 4028bfffbccSCorey Minyard } 4038bfffbccSCorey Minyard pos = nextpos; 4048bfffbccSCorey Minyard } 4058bfffbccSCorey Minyard return 1; 4068bfffbccSCorey Minyard } 4078bfffbccSCorey Minyard 4088bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 4098bfffbccSCorey Minyard { 4108bfffbccSCorey Minyard sel->reservation++; 4118bfffbccSCorey Minyard if (sel->reservation == 0) { 4128bfffbccSCorey Minyard sel->reservation = 1; 4138bfffbccSCorey Minyard } 4148bfffbccSCorey Minyard } 4158bfffbccSCorey Minyard 4168bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4178bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4188bfffbccSCorey Minyard { 4198bfffbccSCorey Minyard event[0] = 0xff; 4208bfffbccSCorey Minyard event[1] = 0xff; 4218bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 4228bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4238bfffbccSCorey Minyard ibs->sel.overflow = 1; 4248bfffbccSCorey Minyard return 1; 4258bfffbccSCorey Minyard } 4268bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4278bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4288bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 4298bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4308bfffbccSCorey Minyard ibs->sel.next_free++; 4318bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4328bfffbccSCorey Minyard return 0; 4338bfffbccSCorey Minyard } 4348bfffbccSCorey Minyard 4358bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4368bfffbccSCorey Minyard { 4378bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4388bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4398bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4408bfffbccSCorey Minyard } 4418bfffbccSCorey Minyard 4428bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4438bfffbccSCorey Minyard { 4448bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 4458bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4468bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4478bfffbccSCorey Minyard } 4488bfffbccSCorey Minyard 4498bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4508bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4518bfffbccSCorey Minyard { 4528bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4538bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4548bfffbccSCorey Minyard uint8_t evt[16]; 4558bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4568bfffbccSCorey Minyard 4578bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4588bfffbccSCorey Minyard return; 4598bfffbccSCorey Minyard } 4608bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4618bfffbccSCorey Minyard return; 4628bfffbccSCorey Minyard } 4638bfffbccSCorey Minyard 4648bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4658bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4668bfffbccSCorey Minyard evt[8] = 0; 4678bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4688bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4698bfffbccSCorey Minyard evt[11] = sens_num; 4708bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4718bfffbccSCorey Minyard evt[13] = evd1; 4728bfffbccSCorey Minyard evt[14] = evd2; 4738bfffbccSCorey Minyard evt[15] = evd3; 4748bfffbccSCorey Minyard 4758bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 4768bfffbccSCorey Minyard sel_add_event(ibs, evt); 4778bfffbccSCorey Minyard } 4788bfffbccSCorey Minyard 4798bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 480d13ada5dSCédric Le Goater return; 4818bfffbccSCorey Minyard } 4828bfffbccSCorey Minyard 4838bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 4848bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 4858bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 4868bfffbccSCorey Minyard } 4878bfffbccSCorey Minyard 4888bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 4898bfffbccSCorey Minyard unsigned int bit, unsigned int val, 4908bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4918bfffbccSCorey Minyard { 4928bfffbccSCorey Minyard IPMISensor *sens; 4938bfffbccSCorey Minyard uint16_t mask; 4948bfffbccSCorey Minyard 4958bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 4968bfffbccSCorey Minyard return; 4978bfffbccSCorey Minyard } 4988bfffbccSCorey Minyard if (bit >= 16) { 4998bfffbccSCorey Minyard return; 5008bfffbccSCorey Minyard } 5018bfffbccSCorey Minyard 5028bfffbccSCorey Minyard mask = (1 << bit); 5038bfffbccSCorey Minyard sens = ibs->sensors + sensor; 5048bfffbccSCorey Minyard if (val) { 5058bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5068bfffbccSCorey Minyard if (sens->assert_states & mask) { 5078bfffbccSCorey Minyard return; /* Already asserted */ 5088bfffbccSCorey Minyard } 5098bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 5108bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 5118bfffbccSCorey Minyard /* Send an event on assert */ 5128bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5138bfffbccSCorey Minyard } 5148bfffbccSCorey Minyard } else { 5158bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5168bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5178bfffbccSCorey Minyard return; /* Already deasserted */ 5188bfffbccSCorey Minyard } 5198bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5208bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5218bfffbccSCorey Minyard /* Send an event on deassert */ 5228bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5238bfffbccSCorey Minyard } 5248bfffbccSCorey Minyard } 5258bfffbccSCorey Minyard } 5268bfffbccSCorey Minyard 5278bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5288bfffbccSCorey Minyard { 5298bfffbccSCorey Minyard unsigned int i, pos; 5308bfffbccSCorey Minyard IPMISensor *sens; 5318bfffbccSCorey Minyard 5328bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5338bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5348bfffbccSCorey Minyard } 5358bfffbccSCorey Minyard 5368bfffbccSCorey Minyard pos = 0; 5378bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 538a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 539a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 540a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5418bfffbccSCorey Minyard 5428bfffbccSCorey Minyard if (len < 20) { 5438bfffbccSCorey Minyard continue; 5448bfffbccSCorey Minyard } 545a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5468bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5478bfffbccSCorey Minyard } 5488bfffbccSCorey Minyard 54973d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 5508bfffbccSCorey Minyard continue; 5518bfffbccSCorey Minyard } 552a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5538bfffbccSCorey Minyard 5548bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 555a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 556a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 557a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 558a2295f0aSCédric Le Goater sens->deassert_suppt = 559a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 560a2295f0aSCédric Le Goater sens->states_suppt = 561a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 562a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 563a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5648bfffbccSCorey Minyard 5658bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5668bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5678bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5688bfffbccSCorey Minyard } 5698bfffbccSCorey Minyard } 5708bfffbccSCorey Minyard 5718bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5728bfffbccSCorey Minyard const IPMINetfn *netfnd) 5738bfffbccSCorey Minyard { 57493a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 5758bfffbccSCorey Minyard return -1; 5768bfffbccSCorey Minyard } 5778bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 5788bfffbccSCorey Minyard return 0; 5798bfffbccSCorey Minyard } 5808bfffbccSCorey Minyard 5814f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 5824f298a4bSCédric Le Goater unsigned int netfn, 5834f298a4bSCédric Le Goater unsigned int cmd) 5844f298a4bSCédric Le Goater { 5854f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 5864f298a4bSCédric Le Goater 5874f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 5884f298a4bSCédric Le Goater return NULL; 5894f298a4bSCédric Le Goater } 5904f298a4bSCédric Le Goater 5914f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 5924f298a4bSCédric Le Goater return NULL; 5934f298a4bSCédric Le Goater } 5944f298a4bSCédric Le Goater 5954f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 5964f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 5974f298a4bSCédric Le Goater return NULL; 5984f298a4bSCédric Le Goater } 5994f298a4bSCédric Le Goater 6004f298a4bSCédric Le Goater return hdl; 6014f298a4bSCédric Le Goater } 6024f298a4bSCédric Le Goater 6038bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 6048bfffbccSCorey Minyard { 6058bfffbccSCorey Minyard int64_t next; 6068bfffbccSCorey Minyard if (ibs->watchdog_running) { 6078bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6088bfffbccSCorey Minyard } else { 6098bfffbccSCorey Minyard /* Wait a minute */ 6108bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6118bfffbccSCorey Minyard } 6128bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6138bfffbccSCorey Minyard } 6148bfffbccSCorey Minyard 6158bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6168bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6178bfffbccSCorey Minyard unsigned int max_cmd_len, 6188bfffbccSCorey Minyard uint8_t msg_id) 6198bfffbccSCorey Minyard { 6208bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6218bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6228bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6234f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 624a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6258bfffbccSCorey Minyard 6268bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6278bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 628a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 6296acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 630d13ada5dSCédric Le Goater goto out; 631d13ada5dSCédric Le Goater } 632d13ada5dSCédric Le Goater 633a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 634a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 635a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6368bfffbccSCorey Minyard 6378bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6388bfffbccSCorey Minyard if (cmd_len < 2) { 6396acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6408bfffbccSCorey Minyard goto out; 6418bfffbccSCorey Minyard } 6428bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6436acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 6448bfffbccSCorey Minyard goto out; 6458bfffbccSCorey Minyard } 6468bfffbccSCorey Minyard 6478bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6488bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 6496acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN); 6508bfffbccSCorey Minyard goto out; 6518bfffbccSCorey Minyard } 6528bfffbccSCorey Minyard 6534f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 6544f298a4bSCédric Le Goater if (!hdl) { 6556acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD); 6568bfffbccSCorey Minyard goto out; 6578bfffbccSCorey Minyard } 6588bfffbccSCorey Minyard 6594f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 6606acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6614f298a4bSCédric Le Goater goto out; 6624f298a4bSCédric Le Goater } 6634f298a4bSCédric Le Goater 664a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 6658bfffbccSCorey Minyard 6668bfffbccSCorey Minyard out: 667a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 6688bfffbccSCorey Minyard 6698bfffbccSCorey Minyard next_timeout(ibs); 6708bfffbccSCorey Minyard } 6718bfffbccSCorey Minyard 6728bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 6738bfffbccSCorey Minyard { 6748bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6758bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6768bfffbccSCorey Minyard 6778bfffbccSCorey Minyard if (!ibs->watchdog_running) { 6788bfffbccSCorey Minyard goto out; 6798bfffbccSCorey Minyard } 6808bfffbccSCorey Minyard 6818bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 6828bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 6838bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 6848bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6858bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 6868bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6878bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 6888bfffbccSCorey Minyard break; 6898bfffbccSCorey Minyard 6908bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 6918bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 6928bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 6938bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 6948bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 6958bfffbccSCorey Minyard break; 6968bfffbccSCorey Minyard 6978bfffbccSCorey Minyard default: 6988bfffbccSCorey Minyard goto do_full_expiry; 6998bfffbccSCorey Minyard } 7008bfffbccSCorey Minyard 7018bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 7028bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 7038bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 7048bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 7058bfffbccSCorey Minyard goto out; 7068bfffbccSCorey Minyard } 7078bfffbccSCorey Minyard 7088bfffbccSCorey Minyard do_full_expiry: 7098bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7108bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7118bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7128bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7138bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 7148bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 7158bfffbccSCorey Minyard break; 7168bfffbccSCorey Minyard 7178bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7188bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 7198bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 7208bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7218bfffbccSCorey Minyard break; 7228bfffbccSCorey Minyard 7238bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7248bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7258bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 7268bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7278bfffbccSCorey Minyard break; 7288bfffbccSCorey Minyard 7298bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7308bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7318bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7328bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7338bfffbccSCorey Minyard break; 7348bfffbccSCorey Minyard } 7358bfffbccSCorey Minyard 7368bfffbccSCorey Minyard out: 7378bfffbccSCorey Minyard next_timeout(ibs); 7388bfffbccSCorey Minyard } 7398bfffbccSCorey Minyard 7408bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7418bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 742a580d820SCédric Le Goater RspBuffer *rsp) 7438bfffbccSCorey Minyard { 744a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 745a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 746a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 747a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 748a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 7498bfffbccSCorey Minyard } 7508bfffbccSCorey Minyard 7518bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7528bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 753a580d820SCédric Le Goater RspBuffer *rsp) 7548bfffbccSCorey Minyard { 755a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 756a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 757a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 758a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 7598bfffbccSCorey Minyard } 7608bfffbccSCorey Minyard 7618bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7628bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 763a580d820SCédric Le Goater RspBuffer *rsp) 7648bfffbccSCorey Minyard { 7658bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7668bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7678bfffbccSCorey Minyard 7688bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7698bfffbccSCorey Minyard case 0: /* power down */ 7706acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0)); 7718bfffbccSCorey Minyard break; 7728bfffbccSCorey Minyard case 1: /* power up */ 7736acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0)); 7748bfffbccSCorey Minyard break; 7758bfffbccSCorey Minyard case 2: /* power cycle */ 7766acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0)); 7778bfffbccSCorey Minyard break; 7788bfffbccSCorey Minyard case 3: /* hard reset */ 7796acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0)); 7808bfffbccSCorey Minyard break; 7818bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 7826acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0)); 7838bfffbccSCorey Minyard break; 7848bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 7856acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, 7866acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0)); 7878bfffbccSCorey Minyard break; 7888bfffbccSCorey Minyard default: 7896acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 7908bfffbccSCorey Minyard return; 7918bfffbccSCorey Minyard } 792d13ada5dSCédric Le Goater } 7938bfffbccSCorey Minyard 794b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 795b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 796a580d820SCédric Le Goater RspBuffer *rsp) 797a580d820SCédric Le Goater 798b7088392SCédric Le Goater { 799a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 800a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 801b7088392SCédric Le Goater } 802b7088392SCédric Le Goater 8038bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 8048bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 805a580d820SCédric Le Goater RspBuffer *rsp) 8068bfffbccSCorey Minyard { 807a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 808a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 809a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 810a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 811a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 812a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 813a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[0]); 814a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[1]); 815a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->mfg_id[2]); 816a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[0]); 817a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->product_id[1]); 8188bfffbccSCorey Minyard } 8198bfffbccSCorey Minyard 8208bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8218bfffbccSCorey Minyard { 8228bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8238bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8248bfffbccSCorey Minyard bool irqs_on; 8258bfffbccSCorey Minyard 8268bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8278bfffbccSCorey Minyard 8288bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8298bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8308bfffbccSCorey Minyard 8318bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8328bfffbccSCorey Minyard } 8338bfffbccSCorey Minyard 8348bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8358bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 836a580d820SCédric Le Goater RspBuffer *rsp) 8378bfffbccSCorey Minyard { 8388bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8398bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8408bfffbccSCorey Minyard 8418bfffbccSCorey Minyard /* Disable all interrupts */ 8428bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8438bfffbccSCorey Minyard 8448bfffbccSCorey Minyard if (k->reset) { 8458bfffbccSCorey Minyard k->reset(s, true); 8468bfffbccSCorey Minyard } 8478bfffbccSCorey Minyard } 8488bfffbccSCorey Minyard 8498bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 851a580d820SCédric Le Goater RspBuffer *rsp) 8528bfffbccSCorey Minyard { 8538bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8548bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8558bfffbccSCorey Minyard 8568bfffbccSCorey Minyard if (k->reset) { 8578bfffbccSCorey Minyard k->reset(s, false); 8588bfffbccSCorey Minyard } 8598bfffbccSCorey Minyard } 86052ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 86152ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 862a580d820SCédric Le Goater RspBuffer *rsp) 86352ba4d50SCédric Le Goater { 86452ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 86552ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 86652ba4d50SCédric Le Goater } 86752ba4d50SCédric Le Goater 86852ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 86952ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 870a580d820SCédric Le Goater RspBuffer *rsp) 87152ba4d50SCédric Le Goater { 872a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 873a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 87452ba4d50SCédric Le Goater } 87552ba4d50SCédric Le Goater 87652ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 87752ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 878a580d820SCédric Le Goater RspBuffer *rsp) 87952ba4d50SCédric Le Goater { 88052ba4d50SCédric Le Goater unsigned int i; 88152ba4d50SCédric Le Goater 88252ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 883a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->uuid[i]); 88452ba4d50SCédric Le Goater } 88552ba4d50SCédric Le Goater } 8868bfffbccSCorey Minyard 8878bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 8888bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 889a580d820SCédric Le Goater RspBuffer *rsp) 8908bfffbccSCorey Minyard { 8918bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 8928bfffbccSCorey Minyard } 8938bfffbccSCorey Minyard 8948bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 8958bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 896a580d820SCédric Le Goater RspBuffer *rsp) 8978bfffbccSCorey Minyard { 898a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 8998bfffbccSCorey Minyard } 9008bfffbccSCorey Minyard 9018bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 9028bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 903a580d820SCédric Le Goater RspBuffer *rsp) 9048bfffbccSCorey Minyard { 9058bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9068bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9078bfffbccSCorey Minyard 9088bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9098bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9108bfffbccSCorey Minyard } 9118bfffbccSCorey Minyard 9128bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9138bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 914a580d820SCédric Le Goater RspBuffer *rsp) 9158bfffbccSCorey Minyard { 916a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9178bfffbccSCorey Minyard } 9188bfffbccSCorey Minyard 9198bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9208bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 921a580d820SCédric Le Goater RspBuffer *rsp) 9228bfffbccSCorey Minyard { 9238bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9248bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9258bfffbccSCorey Minyard unsigned int i; 9268bfffbccSCorey Minyard 9278bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 9286acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 929d13ada5dSCédric Le Goater return; 9308bfffbccSCorey Minyard } 9318bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 932a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 9338bfffbccSCorey Minyard } 9348bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9358bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9368bfffbccSCorey Minyard } 9378bfffbccSCorey Minyard 9388bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9398bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 940a580d820SCédric Le Goater RspBuffer *rsp) 9418bfffbccSCorey Minyard { 9428bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9438bfffbccSCorey Minyard 9448bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9456acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ 9468bfffbccSCorey Minyard goto out; 9478bfffbccSCorey Minyard } 948a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 9498bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 950a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 9518bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9528bfffbccSCorey Minyard g_free(msg); 9538bfffbccSCorey Minyard 9548bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9558bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9568bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9578bfffbccSCorey Minyard 9588bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9598bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9608bfffbccSCorey Minyard } 9618bfffbccSCorey Minyard 9628bfffbccSCorey Minyard out: 9638bfffbccSCorey Minyard return; 9648bfffbccSCorey Minyard } 9658bfffbccSCorey Minyard 9668bfffbccSCorey Minyard static unsigned char 9678bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 9688bfffbccSCorey Minyard { 9698bfffbccSCorey Minyard for (; size > 0; size--, data++) { 9708bfffbccSCorey Minyard csum += *data; 9718bfffbccSCorey Minyard } 9728bfffbccSCorey Minyard 9738bfffbccSCorey Minyard return -csum; 9748bfffbccSCorey Minyard } 9758bfffbccSCorey Minyard 9768bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 9778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 978a580d820SCédric Le Goater RspBuffer *rsp) 9798bfffbccSCorey Minyard { 9808bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9818bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9828bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9838bfffbccSCorey Minyard uint8_t *buf; 9848bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 9858bfffbccSCorey Minyard 9868bfffbccSCorey Minyard if (cmd[2] != 0) { 9878bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 9886acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 989d13ada5dSCédric Le Goater return; 9908bfffbccSCorey Minyard } 9918bfffbccSCorey Minyard 9924f298a4bSCédric Le Goater if (cmd_len < 10) { 9936acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 9944f298a4bSCédric Le Goater return; 9954f298a4bSCédric Le Goater } 9964f298a4bSCédric Le Goater 9978bfffbccSCorey Minyard if (cmd[3] != 0x40) { 9988bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 9996acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */ 1000d13ada5dSCédric Le Goater return; 10018bfffbccSCorey Minyard } 10028bfffbccSCorey Minyard 10038bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10048bfffbccSCorey Minyard cmd_len -= 3; 10058bfffbccSCorey Minyard 10068bfffbccSCorey Minyard /* 10078bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10088bfffbccSCorey Minyard * be returned in the response. 10098bfffbccSCorey Minyard */ 10108bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10118bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1012d13ada5dSCédric Le Goater return; /* No response */ 10138bfffbccSCorey Minyard } 10148bfffbccSCorey Minyard 10158bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10168bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10178bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10188bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10198bfffbccSCorey Minyard 10208bfffbccSCorey Minyard if (rqLun != 2) { 10218bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1022d13ada5dSCédric Le Goater return; 10238bfffbccSCorey Minyard } 10248bfffbccSCorey Minyard 10258bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10268bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10278bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10288bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10298bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10308bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10318bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10328bfffbccSCorey Minyard msg->len = 6; 10338bfffbccSCorey Minyard 10348bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10358bfffbccSCorey Minyard /* Not a command we handle. */ 10368bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10378bfffbccSCorey Minyard goto end_msg; 10388bfffbccSCorey Minyard } 10398bfffbccSCorey Minyard 10408bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10418bfffbccSCorey Minyard buf[0] = 0; 10428bfffbccSCorey Minyard buf[1] = 0; 10438bfffbccSCorey Minyard buf[2] = 0; 10448bfffbccSCorey Minyard buf[3] = 0; 10458bfffbccSCorey Minyard buf[4] = 0x51; 10468bfffbccSCorey Minyard buf[5] = 0; 10478bfffbccSCorey Minyard buf[6] = 0; 10488bfffbccSCorey Minyard buf[7] = 0; 10498bfffbccSCorey Minyard buf[8] = 0; 10508bfffbccSCorey Minyard buf[9] = 0; 10518bfffbccSCorey Minyard buf[10] = 0; 10528bfffbccSCorey Minyard msg->len += 11; 10538bfffbccSCorey Minyard 10548bfffbccSCorey Minyard end_msg: 10558bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 10568bfffbccSCorey Minyard msg->len++; 10578bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 10588bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10598bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 10608bfffbccSCorey Minyard } 10618bfffbccSCorey Minyard 10628bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 10638bfffbccSCorey Minyard { 10648bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 10658bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 10668bfffbccSCorey Minyard ibs->watchdog_running = 0; 10678bfffbccSCorey Minyard return; 10688bfffbccSCorey Minyard } 10698bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 10708bfffbccSCorey Minyard 10718bfffbccSCorey Minyard 10728bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 10738bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 10748bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 10758bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 10768bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 10778bfffbccSCorey Minyard } 10788bfffbccSCorey Minyard ibs->watchdog_running = 1; 10798bfffbccSCorey Minyard } 10808bfffbccSCorey Minyard 10818bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 10828bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1083a580d820SCédric Le Goater RspBuffer *rsp) 10848bfffbccSCorey Minyard { 10858bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 10866acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1087d13ada5dSCédric Le Goater return; 10888bfffbccSCorey Minyard } 10898bfffbccSCorey Minyard do_watchdog_reset(ibs); 10908bfffbccSCorey Minyard } 10918bfffbccSCorey Minyard 10928bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 10938bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1094a580d820SCédric Le Goater RspBuffer *rsp) 10958bfffbccSCorey Minyard { 10968bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10978bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10988bfffbccSCorey Minyard unsigned int val; 10998bfffbccSCorey Minyard 11008bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 11018bfffbccSCorey Minyard if (val == 0 || val > 5) { 11026acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1103d13ada5dSCédric Le Goater return; 11048bfffbccSCorey Minyard } 11058bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11068bfffbccSCorey Minyard switch (val) { 11078bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11088bfffbccSCorey Minyard break; 11098bfffbccSCorey Minyard 11108bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11116acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1)); 11128bfffbccSCorey Minyard break; 11138bfffbccSCorey Minyard 11148bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11156acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1)); 11168bfffbccSCorey Minyard break; 11178bfffbccSCorey Minyard 11188bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11196acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1)); 11208bfffbccSCorey Minyard break; 11218bfffbccSCorey Minyard 11228bfffbccSCorey Minyard default: 11236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 11248bfffbccSCorey Minyard } 1125a580d820SCédric Le Goater if (rsp->buffer[2]) { 11266acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1127d13ada5dSCédric Le Goater return; 11288bfffbccSCorey Minyard } 11298bfffbccSCorey Minyard 11308bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11318bfffbccSCorey Minyard switch (val) { 11328bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11338bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11348bfffbccSCorey Minyard break; 11358bfffbccSCorey Minyard 11368bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11378bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11388bfffbccSCorey Minyard /* NMI not supported. */ 11396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1140d13ada5dSCédric Le Goater return; 11418bfffbccSCorey Minyard } 114237eebb86SCorey Minyard break; 114337eebb86SCorey Minyard 11448bfffbccSCorey Minyard default: 11458bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11466acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1147d13ada5dSCédric Le Goater return; 11488bfffbccSCorey Minyard } 11498bfffbccSCorey Minyard 11508bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11518bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11528bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11538bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 11548bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 11558bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 11568bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 11578bfffbccSCorey Minyard do_watchdog_reset(ibs); 11588bfffbccSCorey Minyard } else { 11598bfffbccSCorey Minyard ibs->watchdog_running = 0; 11608bfffbccSCorey Minyard } 11618bfffbccSCorey Minyard } 11628bfffbccSCorey Minyard 11638bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 11648bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1165a580d820SCédric Le Goater RspBuffer *rsp) 11668bfffbccSCorey Minyard { 1167a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1168a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1169a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1170a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 11718bfffbccSCorey Minyard if (ibs->watchdog_running) { 11728bfffbccSCorey Minyard long timeout; 11738bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 11748bfffbccSCorey Minyard / 100000000); 1175a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff); 1176a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff); 11778bfffbccSCorey Minyard } else { 1178a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 1179a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 11808bfffbccSCorey Minyard } 11818bfffbccSCorey Minyard } 11828bfffbccSCorey Minyard 11838bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 11848bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1185a580d820SCédric Le Goater RspBuffer *rsp) 11868bfffbccSCorey Minyard { 11878bfffbccSCorey Minyard unsigned int i; 11888bfffbccSCorey Minyard 1189a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1190a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1191a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1192a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1193a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 11948bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1195a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 11968bfffbccSCorey Minyard } 11978bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1198a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 11998bfffbccSCorey Minyard } 12008bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1201a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 12028bfffbccSCorey Minyard } 12038bfffbccSCorey Minyard 12048bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 12058bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1206a580d820SCédric Le Goater RspBuffer *rsp) 12078bfffbccSCorey Minyard { 1208a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1209a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 12108bfffbccSCorey Minyard } 12118bfffbccSCorey Minyard 12128bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 12138bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1214a580d820SCédric Le Goater RspBuffer *rsp) 12158bfffbccSCorey Minyard { 12168bfffbccSCorey Minyard unsigned int pos; 12178bfffbccSCorey Minyard uint16_t nextrec; 1218a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 12198bfffbccSCorey Minyard 12208bfffbccSCorey Minyard if (cmd[6]) { 12217f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 12226acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 12237f996411SCédric Le Goater return; 12248bfffbccSCorey Minyard } 12257f996411SCédric Le Goater } 12267f996411SCédric Le Goater 12278bfffbccSCorey Minyard pos = 0; 12288bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 12298bfffbccSCorey Minyard &pos, &nextrec)) { 12306acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1231d13ada5dSCédric Le Goater return; 12328bfffbccSCorey Minyard } 1233a2295f0aSCédric Le Goater 1234a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1235a2295f0aSCédric Le Goater 1236a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 12376acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE); 1238d13ada5dSCédric Le Goater return; 12398bfffbccSCorey Minyard } 12408bfffbccSCorey Minyard 1241a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1242a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 12438bfffbccSCorey Minyard 12448bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1245a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 12468bfffbccSCorey Minyard } 12478bfffbccSCorey Minyard 1248a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 12496acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES); 1250d13ada5dSCédric Le Goater return; 12518bfffbccSCorey Minyard } 1252a580d820SCédric Le Goater 1253a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 12548bfffbccSCorey Minyard } 12558bfffbccSCorey Minyard 12568bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 12578bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1258a580d820SCédric Le Goater RspBuffer *rsp) 12598bfffbccSCorey Minyard { 12608bfffbccSCorey Minyard uint16_t recid; 1261a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 12628bfffbccSCorey Minyard 1263a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 12646acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1265d13ada5dSCédric Le Goater return; 12668bfffbccSCorey Minyard } 1267a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1268a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 12698bfffbccSCorey Minyard } 12708bfffbccSCorey Minyard 12718bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 12728bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1273a580d820SCédric Le Goater RspBuffer *rsp) 12748bfffbccSCorey Minyard { 12757f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 12766acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 12777f996411SCédric Le Goater return; 12787f996411SCédric Le Goater } 12797f996411SCédric Le Goater 12808bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 12816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1282d13ada5dSCédric Le Goater return; 12838bfffbccSCorey Minyard } 12848bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 12858bfffbccSCorey Minyard ibs->sdr.next_free = 0; 12868bfffbccSCorey Minyard ibs->sdr.overflow = 0; 12878bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1288a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 12898bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 12908bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1291a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 12928bfffbccSCorey Minyard } else { 12936acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 12948bfffbccSCorey Minyard return; 12958bfffbccSCorey Minyard } 1296d13ada5dSCédric Le Goater } 12978bfffbccSCorey Minyard 12988bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 12998bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1300a580d820SCédric Le Goater RspBuffer *rsp) 13018bfffbccSCorey Minyard { 13028bfffbccSCorey Minyard unsigned int i, val; 13038bfffbccSCorey Minyard 1304a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1305a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1306a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 13078bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1308a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1309a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 13108bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1311a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 13128bfffbccSCorey Minyard } 13138bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1314a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 13158bfffbccSCorey Minyard } 13168bfffbccSCorey Minyard /* Only support Reserve SEL */ 1317a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 13188bfffbccSCorey Minyard } 13198bfffbccSCorey Minyard 13208bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 13218bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1322a580d820SCédric Le Goater RspBuffer *rsp) 13238bfffbccSCorey Minyard { 1324a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1325a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 13268bfffbccSCorey Minyard } 13278bfffbccSCorey Minyard 13288bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 13298bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1330a580d820SCédric Le Goater RspBuffer *rsp) 13318bfffbccSCorey Minyard { 13328bfffbccSCorey Minyard unsigned int val; 13338bfffbccSCorey Minyard 13348bfffbccSCorey Minyard if (cmd[6]) { 13357f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 13366acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13377f996411SCédric Le Goater return; 13387f996411SCédric Le Goater } 13398bfffbccSCorey Minyard } 13408bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 13416acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1342d13ada5dSCédric Le Goater return; 13438bfffbccSCorey Minyard } 13448bfffbccSCorey Minyard if (cmd[6] > 15) { 13456acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1346d13ada5dSCédric Le Goater return; 13478bfffbccSCorey Minyard } 13488bfffbccSCorey Minyard if (cmd[7] == 0xff) { 13498bfffbccSCorey Minyard cmd[7] = 16; 13508bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 13516acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1352d13ada5dSCédric Le Goater return; 13538bfffbccSCorey Minyard } else { 13548bfffbccSCorey Minyard cmd[7] += cmd[6]; 13558bfffbccSCorey Minyard } 13568bfffbccSCorey Minyard 13578bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 13588bfffbccSCorey Minyard if (val == 0xffff) { 13598bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 13608bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 13616acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1362d13ada5dSCédric Le Goater return; 13638bfffbccSCorey Minyard } 13648bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1365a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1366a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 13678bfffbccSCorey Minyard } else { 1368a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1369a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 13708bfffbccSCorey Minyard } 13718bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1372a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 13738bfffbccSCorey Minyard } 13748bfffbccSCorey Minyard } 13758bfffbccSCorey Minyard 13768bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 13778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1378a580d820SCédric Le Goater RspBuffer *rsp) 13798bfffbccSCorey Minyard { 13808bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 13816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 1382d13ada5dSCédric Le Goater return; 13838bfffbccSCorey Minyard } 13848bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1385a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1386a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 13878bfffbccSCorey Minyard } 13888bfffbccSCorey Minyard 13898bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 13908bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1391a580d820SCédric Le Goater RspBuffer *rsp) 13928bfffbccSCorey Minyard { 13937f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 13946acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13957f996411SCédric Le Goater return; 13967f996411SCédric Le Goater } 13977f996411SCédric Le Goater 13988bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13996acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1400d13ada5dSCédric Le Goater return; 14018bfffbccSCorey Minyard } 14028bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 14038bfffbccSCorey Minyard ibs->sel.next_free = 0; 14048bfffbccSCorey Minyard ibs->sel.overflow = 0; 14058bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1406a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14078bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 14088bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1409a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14108bfffbccSCorey Minyard } else { 14116acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 14128bfffbccSCorey Minyard return; 14138bfffbccSCorey Minyard } 1414d13ada5dSCédric Le Goater } 14158bfffbccSCorey Minyard 14168bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 14178bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1418a580d820SCédric Le Goater RspBuffer *rsp) 14198bfffbccSCorey Minyard { 14208bfffbccSCorey Minyard uint32_t val; 14218bfffbccSCorey Minyard struct ipmi_time now; 14228bfffbccSCorey Minyard 14238bfffbccSCorey Minyard ipmi_gettime(&now); 14248bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1425a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1426a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1427a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1428a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 14298bfffbccSCorey Minyard } 14308bfffbccSCorey Minyard 14318bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 14328bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1433a580d820SCédric Le Goater RspBuffer *rsp) 14348bfffbccSCorey Minyard { 14358bfffbccSCorey Minyard uint32_t val; 14368bfffbccSCorey Minyard struct ipmi_time now; 14378bfffbccSCorey Minyard 14388bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 14398bfffbccSCorey Minyard ipmi_gettime(&now); 14408bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 14418bfffbccSCorey Minyard } 14428bfffbccSCorey Minyard 14438bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 14448bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1445a580d820SCédric Le Goater RspBuffer *rsp) 14468bfffbccSCorey Minyard { 14478bfffbccSCorey Minyard IPMISensor *sens; 14488bfffbccSCorey Minyard 144973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 14508bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 14516acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1452d13ada5dSCédric Le Goater return; 14538bfffbccSCorey Minyard } 14548bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 14558bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 14568bfffbccSCorey Minyard case 0: /* Do not change */ 14578bfffbccSCorey Minyard break; 14588bfffbccSCorey Minyard case 1: /* Enable bits */ 14598bfffbccSCorey Minyard if (cmd_len > 4) { 14608bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 14618bfffbccSCorey Minyard } 14628bfffbccSCorey Minyard if (cmd_len > 5) { 14638bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 14648bfffbccSCorey Minyard } 14658bfffbccSCorey Minyard if (cmd_len > 6) { 14668bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 14678bfffbccSCorey Minyard } 14688bfffbccSCorey Minyard if (cmd_len > 7) { 14698bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 14708bfffbccSCorey Minyard } 14718bfffbccSCorey Minyard break; 14728bfffbccSCorey Minyard case 2: /* Disable bits */ 14738bfffbccSCorey Minyard if (cmd_len > 4) { 14748bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 14758bfffbccSCorey Minyard } 14768bfffbccSCorey Minyard if (cmd_len > 5) { 14778bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 14788bfffbccSCorey Minyard } 14798bfffbccSCorey Minyard if (cmd_len > 6) { 14808bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 14818bfffbccSCorey Minyard } 14828bfffbccSCorey Minyard if (cmd_len > 7) { 14838bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 14848bfffbccSCorey Minyard } 14858bfffbccSCorey Minyard break; 14868bfffbccSCorey Minyard case 3: 14876acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1488d13ada5dSCédric Le Goater return; 14898bfffbccSCorey Minyard } 14908bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 14918bfffbccSCorey Minyard } 14928bfffbccSCorey Minyard 14938bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 14948bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1495a580d820SCédric Le Goater RspBuffer *rsp) 14968bfffbccSCorey Minyard { 14978bfffbccSCorey Minyard IPMISensor *sens; 14988bfffbccSCorey Minyard 149973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15008bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15016acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1502d13ada5dSCédric Le Goater return; 15038bfffbccSCorey Minyard } 15048bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1505a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1506a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1507a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1508a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1509a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 15108bfffbccSCorey Minyard } 15118bfffbccSCorey Minyard 15128bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 15138bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1514a580d820SCédric Le Goater RspBuffer *rsp) 15158bfffbccSCorey Minyard { 15168bfffbccSCorey Minyard IPMISensor *sens; 15178bfffbccSCorey Minyard 151873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15198bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15206acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1521d13ada5dSCédric Le Goater return; 15228bfffbccSCorey Minyard } 15238bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 15248bfffbccSCorey Minyard 15258bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 15268bfffbccSCorey Minyard /* Just clear everything */ 15278bfffbccSCorey Minyard sens->states = 0; 15288bfffbccSCorey Minyard return; 15298bfffbccSCorey Minyard } 1530d13ada5dSCédric Le Goater } 15318bfffbccSCorey Minyard 15328bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 15338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1534a580d820SCédric Le Goater RspBuffer *rsp) 15358bfffbccSCorey Minyard { 15368bfffbccSCorey Minyard IPMISensor *sens; 15378bfffbccSCorey Minyard 153873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15398bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1541d13ada5dSCédric Le Goater return; 15428bfffbccSCorey Minyard } 15438bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1544a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1545a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1546a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1547a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1548a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1549a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 15508bfffbccSCorey Minyard } 15518bfffbccSCorey Minyard 15528bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 15538bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1554a580d820SCédric Le Goater RspBuffer *rsp) 15558bfffbccSCorey Minyard { 15568bfffbccSCorey Minyard IPMISensor *sens; 15578bfffbccSCorey Minyard 155873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 15598bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15606acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1561d13ada5dSCédric Le Goater return; 15628bfffbccSCorey Minyard } 15638bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1564a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1565a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1566a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 15678bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1568a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 15698bfffbccSCorey Minyard } 15708bfffbccSCorey Minyard } 15718bfffbccSCorey Minyard 1572728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1573728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1574a580d820SCédric Le Goater RspBuffer *rsp) 1575728710e1SCédric Le Goater { 1576728710e1SCédric Le Goater IPMISensor *sens; 1577728710e1SCédric Le Goater 1578728710e1SCédric Le Goater 157973d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1580728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1582728710e1SCédric Le Goater return; 1583728710e1SCédric Le Goater } 1584728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1585728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1586728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1587728710e1SCédric Le Goater } 1588728710e1SCédric Le Goater 1589728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1590728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1591a580d820SCédric Le Goater RspBuffer *rsp) 1592728710e1SCédric Le Goater { 1593728710e1SCédric Le Goater IPMISensor *sens; 1594728710e1SCédric Le Goater 1595728710e1SCédric Le Goater 159673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1597728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 15986acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1599728710e1SCédric Le Goater return; 1600728710e1SCédric Le Goater } 1601728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1602a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1603a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1604728710e1SCédric Le Goater } 1605728710e1SCédric Le Goater 1606728710e1SCédric Le Goater 160762a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 16084f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 16094f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 16104f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 16114f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 16128bfffbccSCorey Minyard }; 16138bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 161462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 16158bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 16168bfffbccSCorey Minyard }; 16178bfffbccSCorey Minyard 161862a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 16194f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 16204f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 16214f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 16224f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 16234f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 16244f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 16254f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 16268bfffbccSCorey Minyard }; 16278bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 162862a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 16298bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 16308bfffbccSCorey Minyard }; 16318bfffbccSCorey Minyard 163262a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 16334f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 16344f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 16354f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 16364f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 16374f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 16384f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 16394f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 16404f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 16414f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 16424f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 16434f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 16444f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 16454f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 16464f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 16474f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 16484f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 16498bfffbccSCorey Minyard }; 16508bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 165162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 16528bfffbccSCorey Minyard .cmd_handlers = app_cmds 16538bfffbccSCorey Minyard }; 16548bfffbccSCorey Minyard 165562a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 16564f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 16574f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 16584f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 16594f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 16604f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 16614f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 16624f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 16634f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 16644f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 16654f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 16664f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 }, 16674f298a4bSCédric Le Goater [IPMI_CMD_SET_SEL_TIME] = { set_sel_time }, 16688bfffbccSCorey Minyard }; 16698bfffbccSCorey Minyard 16708bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 167162a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 16728bfffbccSCorey Minyard .cmd_handlers = storage_cmds 16738bfffbccSCorey Minyard }; 16748bfffbccSCorey Minyard 16758bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 16768bfffbccSCorey Minyard { 16778bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 16788bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 16798bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 16808bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 16818bfffbccSCorey Minyard } 16828bfffbccSCorey Minyard 16835167560bSCédric Le Goater static uint8_t init_sdrs[] = { 16848bfffbccSCorey Minyard /* Watchdog device */ 16858bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 16868bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 16878bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16888bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 16898bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 16908bfffbccSCorey Minyard }; 16918bfffbccSCorey Minyard 16924fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs) 16934fa9f08eSCédric Le Goater { 16944fa9f08eSCédric Le Goater unsigned int i; 16954fa9f08eSCédric Le Goater int len; 16965167560bSCédric Le Goater size_t sdrs_size; 16975167560bSCédric Le Goater uint8_t *sdrs; 169852fc01d9SCédric Le Goater 16995167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs); 17005167560bSCédric Le Goater sdrs = init_sdrs; 1701*8c6fd7f3SCédric Le Goater if (ibs->sdr_filename && 1702*8c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size, 1703*8c6fd7f3SCédric Le Goater NULL)) { 1704*8c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename); 1705*8c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs); 1706*8c6fd7f3SCédric Le Goater sdrs = init_sdrs; 1707*8c6fd7f3SCédric Le Goater } 17085167560bSCédric Le Goater 17095167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) { 171052fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh; 171152fc01d9SCédric Le Goater 17125167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) { 17134fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 1714*8c6fd7f3SCédric Le Goater break; 17154fa9f08eSCédric Le Goater } 17165167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i]; 17174fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh); 17185167560bSCédric Le Goater if (i + len > sdrs_size) { 17194fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 1720*8c6fd7f3SCédric Le Goater break; 17214fa9f08eSCédric Le Goater } 17224fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 17234fa9f08eSCédric Le Goater } 1724*8c6fd7f3SCédric Le Goater 1725*8c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) { 1726*8c6fd7f3SCédric Le Goater g_free(sdrs); 1727*8c6fd7f3SCédric Le Goater } 17284fa9f08eSCédric Le Goater } 17294fa9f08eSCédric Le Goater 1730bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 1731bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1732bd66bcfcSCorey Minyard .version_id = 1, 1733bd66bcfcSCorey Minyard .minimum_version_id = 1, 1734bd66bcfcSCorey Minyard .fields = (VMStateField[]) { 1735bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 1736bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 1737bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 1738bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 1739bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 1740bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 1741bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_expired, IPMIBmcSim), 1742bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 1743bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 1744bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 1745bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 1746bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 1747bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 1748bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 1749bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 1750bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 1751bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 1752bd66bcfcSCorey Minyard IPMIBmcSim), 1753bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 1754bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 1755bd66bcfcSCorey Minyard } 1756bd66bcfcSCorey Minyard }; 1757bd66bcfcSCorey Minyard 17580bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp) 17598bfffbccSCorey Minyard { 17600bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev); 17618bfffbccSCorey Minyard unsigned int i; 17628bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 17638bfffbccSCorey Minyard 17648bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 17658bfffbccSCorey Minyard 17668bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 17678bfffbccSCorey Minyard ibs->device_id = 0x20; 17688bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1769b7088392SCédric Le Goater ibs->restart_cause = 0; 17708bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 17718bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 17728bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 17738bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 17748bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 17758bfffbccSCorey Minyard } 17768bfffbccSCorey Minyard 17774fa9f08eSCédric Le Goater ipmi_sdr_init(ibs); 17788bfffbccSCorey Minyard 177952ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 178052ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 178152ba4d50SCédric Le Goater 178252ba4d50SCédric Le Goater if (qemu_uuid_set) { 17839c5ce8dbSFam Zheng memcpy(&ibs->uuid, &qemu_uuid, 16); 178452ba4d50SCédric Le Goater } else { 178552ba4d50SCédric Le Goater memset(&ibs->uuid, 0, 16); 178652ba4d50SCédric Le Goater } 178752ba4d50SCédric Le Goater 17888bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 17898bfffbccSCorey Minyard register_cmds(ibs); 17908bfffbccSCorey Minyard 17918bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1792bd66bcfcSCorey Minyard 1793bd66bcfcSCorey Minyard vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); 17948bfffbccSCorey Minyard } 17958bfffbccSCorey Minyard 1796*8c6fd7f3SCédric Le Goater static Property ipmi_sim_properties[] = { 1797*8c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename), 1798*8c6fd7f3SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1799*8c6fd7f3SCédric Le Goater }; 1800*8c6fd7f3SCédric Le Goater 18018bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 18028bfffbccSCorey Minyard { 18030bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc); 18048bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 18058bfffbccSCorey Minyard 180666abfddbSCorey Minyard dc->hotpluggable = false; 18070bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize; 1808*8c6fd7f3SCédric Le Goater dc->props = ipmi_sim_properties; 18098bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 18108bfffbccSCorey Minyard } 18118bfffbccSCorey Minyard 18128bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 18138bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 18148bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 18158bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 18168bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 18178bfffbccSCorey Minyard }; 18188bfffbccSCorey Minyard 18198bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 18208bfffbccSCorey Minyard { 18218bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 18228bfffbccSCorey Minyard } 18238bfffbccSCorey Minyard 18248bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1825