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" 2632cad1ffSPhilippe Mathieu-Daudé #include "system/system.h" 278bfffbccSCorey Minyard #include "qemu/timer.h" 288bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 298bfffbccSCorey Minyard #include "qemu/error-report.h" 300b8fa32fSMarkus Armbruster #include "qemu/module.h" 318c6fd7f3SCédric Le Goater #include "hw/loader.h" 32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 33ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 34d6454270SMarkus Armbruster #include "migration/vmstate.h" 358bfffbccSCorey Minyard 368bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 378bfffbccSCorey Minyard 388bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 398bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 408bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 41b7088392SCédric Le Goater #define IPMI_CMD_GET_SYS_RESTART_CAUSE 0x09 428bfffbccSCorey Minyard 438bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 448bfffbccSCorey Minyard 459380d2edSCorey Minyard #define IPMI_CMD_PLATFORM_EVENT_MSG 0x02 468bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 478bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 488bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 498bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 508bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 51728710e1SCédric Le Goater #define IPMI_CMD_SET_SENSOR_TYPE 0x2e 52728710e1SCédric Le Goater #define IPMI_CMD_GET_SENSOR_TYPE 0x2f 53e3f7320cSCédric Le Goater #define IPMI_CMD_SET_SENSOR_READING 0x30 548bfffbccSCorey Minyard 558bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 568bfffbccSCorey Minyard 578bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 588bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 598bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 6052ba4d50SCédric Le Goater #define IPMI_CMD_SET_ACPI_POWER_STATE 0x06 6152ba4d50SCédric Le Goater #define IPMI_CMD_GET_ACPI_POWER_STATE 0x07 6252ba4d50SCédric Le Goater #define IPMI_CMD_GET_DEVICE_GUID 0x08 638bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 648bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 658bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 668bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 678bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 688bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 698bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 708bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 718bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 728bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 73*7f9e7af4SNicholas Piggin #define IPMI_CMD_GET_CHANNEL_INFO 0x42 748bfffbccSCorey Minyard 758bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 768bfffbccSCorey Minyard 778bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 788bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 798bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 808bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 818bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 828bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 838bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 848bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 858bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 868bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 878bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 888bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 898bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 90540c07d3SCédric Le Goater #define IPMI_CMD_GET_FRU_AREA_INFO 0x10 91540c07d3SCédric Le Goater #define IPMI_CMD_READ_FRU_DATA 0x11 92540c07d3SCédric Le Goater #define IPMI_CMD_WRITE_FRU_DATA 0x12 938bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 948bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 958bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 968bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 978bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 988bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 998bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 1008bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 1018bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 1028bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 1038bfffbccSCorey Minyard 1048bfffbccSCorey Minyard 1058bfffbccSCorey Minyard /* Same as a timespec struct. */ 1068bfffbccSCorey Minyard struct ipmi_time { 1078bfffbccSCorey Minyard long tv_sec; 1088bfffbccSCorey Minyard long tv_nsec; 1098bfffbccSCorey Minyard }; 1108bfffbccSCorey Minyard 1118bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 1128bfffbccSCorey Minyard 1138bfffbccSCorey Minyard typedef struct IPMISel { 1148bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 1158bfffbccSCorey Minyard unsigned int next_free; 1168bfffbccSCorey Minyard long time_offset; 1178bfffbccSCorey Minyard uint16_t reservation; 1188bfffbccSCorey Minyard uint8_t last_addition[4]; 1198bfffbccSCorey Minyard uint8_t last_clear[4]; 1208bfffbccSCorey Minyard uint8_t overflow; 1218bfffbccSCorey Minyard } IPMISel; 1228bfffbccSCorey Minyard 1238bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 1248bfffbccSCorey Minyard 1258bfffbccSCorey Minyard typedef struct IPMISdr { 1268bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 1278bfffbccSCorey Minyard unsigned int next_free; 1288bfffbccSCorey Minyard uint16_t next_rec_id; 1298bfffbccSCorey Minyard uint16_t reservation; 1308bfffbccSCorey Minyard uint8_t last_addition[4]; 1318bfffbccSCorey Minyard uint8_t last_clear[4]; 1328bfffbccSCorey Minyard uint8_t overflow; 1338bfffbccSCorey Minyard } IPMISdr; 1348bfffbccSCorey Minyard 135540c07d3SCédric Le Goater typedef struct IPMIFru { 136540c07d3SCédric Le Goater char *filename; 137540c07d3SCédric Le Goater unsigned int nentries; 138540c07d3SCédric Le Goater uint16_t areasize; 139540c07d3SCédric Le Goater uint8_t *data; 140540c07d3SCédric Le Goater } IPMIFru; 141540c07d3SCédric Le Goater 1428bfffbccSCorey Minyard typedef struct IPMISensor { 1438bfffbccSCorey Minyard uint8_t status; 1448bfffbccSCorey Minyard uint8_t reading; 1458bfffbccSCorey Minyard uint16_t states_suppt; 1468bfffbccSCorey Minyard uint16_t assert_suppt; 1478bfffbccSCorey Minyard uint16_t deassert_suppt; 1488bfffbccSCorey Minyard uint16_t states; 1498bfffbccSCorey Minyard uint16_t assert_states; 1508bfffbccSCorey Minyard uint16_t deassert_states; 1518bfffbccSCorey Minyard uint16_t assert_enable; 1528bfffbccSCorey Minyard uint16_t deassert_enable; 1538bfffbccSCorey Minyard uint8_t sensor_type; 1548bfffbccSCorey Minyard uint8_t evt_reading_type_code; 1558bfffbccSCorey Minyard } IPMISensor; 1568bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 1578bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 1588bfffbccSCorey Minyard !!(v)) 1598bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 1608bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 1618bfffbccSCorey Minyard ((!!(v)) << 6)) 1628bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 1638bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 1648bfffbccSCorey Minyard ((!!(v)) << 7)) 1658bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 1668bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 1678bfffbccSCorey Minyard (v & 0xc0)) 1688bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 1698bfffbccSCorey Minyard 1708bfffbccSCorey Minyard #define MAX_SENSORS 20 1718bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 1728bfffbccSCorey Minyard 1738bfffbccSCorey Minyard #define MAX_NETFNS 64 1744f298a4bSCédric Le Goater 1758bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 1768bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 1778bfffbccSCorey Minyard uint8_t len; 1788bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 1798bfffbccSCorey Minyard } IPMIRcvBufEntry; 1808bfffbccSCorey Minyard 1818bfffbccSCorey Minyard struct IPMIBmcSim { 1828bfffbccSCorey Minyard IPMIBmc parent; 1838bfffbccSCorey Minyard 1848bfffbccSCorey Minyard QEMUTimer *timer; 1858bfffbccSCorey Minyard 1868bfffbccSCorey Minyard uint8_t bmc_global_enables; 1878bfffbccSCorey Minyard uint8_t msg_flags; 1888bfffbccSCorey Minyard 1898bfffbccSCorey Minyard bool watchdog_initialized; 1908bfffbccSCorey Minyard uint8_t watchdog_use; 1918bfffbccSCorey Minyard uint8_t watchdog_action; 1928bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 1939e744990SJinhua Cao uint8_t watchdog_expired; 1948bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 1958bfffbccSCorey Minyard 1968bfffbccSCorey Minyard bool watchdog_running; 1978bfffbccSCorey Minyard bool watchdog_preaction_ran; 1988bfffbccSCorey Minyard int64_t watchdog_expiry; 1998bfffbccSCorey Minyard 2008bfffbccSCorey Minyard uint8_t device_id; 2018bfffbccSCorey Minyard uint8_t ipmi_version; 2028bfffbccSCorey Minyard uint8_t device_rev; 2038bfffbccSCorey Minyard uint8_t fwrev1; 2048bfffbccSCorey Minyard uint8_t fwrev2; 20520b23364SCorey Minyard uint32_t mfg_id; 20620b23364SCorey Minyard uint16_t product_id; 2078bfffbccSCorey Minyard 208b7088392SCédric Le Goater uint8_t restart_cause; 209b7088392SCédric Le Goater 21052ba4d50SCédric Le Goater uint8_t acpi_power_state[2]; 2117b0cd78bSCorey Minyard QemuUUID uuid; 21252ba4d50SCédric Le Goater 2138bfffbccSCorey Minyard IPMISel sel; 2148bfffbccSCorey Minyard IPMISdr sdr; 215540c07d3SCédric Le Goater IPMIFru fru; 2168bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 2178c6fd7f3SCé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 #define RSP_BUFFER_INITIALIZER { } 2688bfffbccSCorey Minyard 269a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes, 270a580d820SCédric Le Goater unsigned int n) 271a580d820SCédric Le Goater { 272a580d820SCédric Le Goater if (rsp->len + n >= sizeof(rsp->buffer)) { 2736acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 274a580d820SCédric Le Goater return; 275a580d820SCédric Le Goater } 276a580d820SCédric Le Goater 277a580d820SCédric Le Goater memcpy(&rsp->buffer[rsp->len], bytes, n); 278a580d820SCédric Le Goater rsp->len += n; 279a580d820SCédric Le Goater } 2808bfffbccSCorey Minyard 2818bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 2828bfffbccSCorey Minyard 2838bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 2848bfffbccSCorey Minyard { 2858bfffbccSCorey Minyard int64_t stime; 2868bfffbccSCorey Minyard 2878bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 2888bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 2898bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 2908bfffbccSCorey Minyard } 2918bfffbccSCorey Minyard 2928bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 2938bfffbccSCorey Minyard { 2948bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 2958bfffbccSCorey Minyard } 2968bfffbccSCorey Minyard 2978bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 2988bfffbccSCorey Minyard { 2998bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 3008bfffbccSCorey Minyard 3018bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 3028bfffbccSCorey Minyard } 3038bfffbccSCorey Minyard 3048bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 3058bfffbccSCorey Minyard { 3068bfffbccSCorey Minyard unsigned int val; 3078bfffbccSCorey Minyard struct ipmi_time now; 3088bfffbccSCorey Minyard 3098bfffbccSCorey Minyard ipmi_gettime(&now); 3108bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 3118bfffbccSCorey Minyard ts[0] = val & 0xff; 3128bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 3138bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 3148bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 3158bfffbccSCorey Minyard } 3168bfffbccSCorey Minyard 3178bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 3188bfffbccSCorey Minyard { 3198bfffbccSCorey Minyard sdr->reservation++; 3208bfffbccSCorey Minyard if (sdr->reservation == 0) { 3218bfffbccSCorey Minyard sdr->reservation = 1; 3228bfffbccSCorey Minyard } 3238bfffbccSCorey Minyard } 3248bfffbccSCorey Minyard 325a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs, 326a2295f0aSCédric Le Goater const struct ipmi_sdr_header *sdrh_entry, 3278bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 3288bfffbccSCorey Minyard { 329a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 330a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free]; 331a2295f0aSCédric Le Goater 332a2295f0aSCédric Le Goater if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) { 3338bfffbccSCorey Minyard return 1; 3348bfffbccSCorey Minyard } 3358bfffbccSCorey Minyard 336a2295f0aSCédric Le Goater if (ipmi_sdr_length(sdrh_entry) != len) { 3378bfffbccSCorey Minyard return 1; 3388bfffbccSCorey Minyard } 3398bfffbccSCorey Minyard 3408bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 3418bfffbccSCorey Minyard ibs->sdr.overflow = 1; 3428bfffbccSCorey Minyard return 1; 3438bfffbccSCorey Minyard } 3448bfffbccSCorey Minyard 345a2295f0aSCédric Le Goater memcpy(sdrh, sdrh_entry, len); 346a2295f0aSCédric Le Goater sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff; 347a2295f0aSCédric Le Goater sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 348a2295f0aSCédric Le Goater sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */ 3498bfffbccSCorey Minyard 3508bfffbccSCorey Minyard if (recid) { 3518bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 3528bfffbccSCorey Minyard } 3538bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 3548bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 3558bfffbccSCorey Minyard ibs->sdr.next_free += len; 3568bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 3578bfffbccSCorey Minyard return 0; 3588bfffbccSCorey Minyard } 3598bfffbccSCorey Minyard 3608bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 3618bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 3628bfffbccSCorey Minyard { 3638bfffbccSCorey Minyard unsigned int pos = *retpos; 3648bfffbccSCorey Minyard 3658bfffbccSCorey Minyard while (pos < sdr->next_free) { 366a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = 367a2295f0aSCédric Le Goater (struct ipmi_sdr_header *) &sdr->sdr[pos]; 368a2295f0aSCédric Le Goater uint16_t trec = ipmi_sdr_recid(sdrh); 369a2295f0aSCédric Le Goater unsigned int nextpos = pos + ipmi_sdr_length(sdrh); 3708bfffbccSCorey Minyard 3718bfffbccSCorey Minyard if (trec == recid) { 3728bfffbccSCorey Minyard if (nextrec) { 3738bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 3748bfffbccSCorey Minyard *nextrec = 0xffff; 3758bfffbccSCorey Minyard } else { 3768bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 3778bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 3788bfffbccSCorey Minyard } 3798bfffbccSCorey Minyard } 3808bfffbccSCorey Minyard *retpos = pos; 3818bfffbccSCorey Minyard return 0; 3828bfffbccSCorey Minyard } 3838bfffbccSCorey Minyard pos = nextpos; 3848bfffbccSCorey Minyard } 3858bfffbccSCorey Minyard return 1; 3868bfffbccSCorey Minyard } 3878bfffbccSCorey Minyard 3887fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid, 3897fabcdb9SCédric Le Goater const struct ipmi_sdr_compact **sdr, uint16_t *nextrec) 3907fabcdb9SCédric Le Goater 3917fabcdb9SCédric Le Goater { 3927fabcdb9SCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 3937fabcdb9SCédric Le Goater unsigned int pos; 3947fabcdb9SCédric Le Goater 3957fabcdb9SCédric Le Goater pos = 0; 3967fabcdb9SCédric Le Goater if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) { 3977fabcdb9SCédric Le Goater return -1; 3987fabcdb9SCédric Le Goater } 3997fabcdb9SCédric Le Goater 4007fabcdb9SCédric Le Goater *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos]; 4017fabcdb9SCédric Le Goater return 0; 4027fabcdb9SCédric Le Goater } 4037fabcdb9SCédric Le Goater 4048bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 4058bfffbccSCorey Minyard { 4068bfffbccSCorey Minyard sel->reservation++; 4078bfffbccSCorey Minyard if (sel->reservation == 0) { 4088bfffbccSCorey Minyard sel->reservation = 1; 4098bfffbccSCorey Minyard } 4108bfffbccSCorey Minyard } 4118bfffbccSCorey Minyard 4128bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 4138bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 4148bfffbccSCorey Minyard { 4159f7d1d92SCorey Minyard uint8_t ts[4]; 4169f7d1d92SCorey Minyard 4178bfffbccSCorey Minyard event[0] = 0xff; 4188bfffbccSCorey Minyard event[1] = 0xff; 4199f7d1d92SCorey Minyard set_timestamp(ibs, ts); 4209f7d1d92SCorey Minyard if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */ 4219f7d1d92SCorey Minyard memcpy(event + 3, ts, 4); 4229f7d1d92SCorey Minyard } 4238bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 4248bfffbccSCorey Minyard ibs->sel.overflow = 1; 4258bfffbccSCorey Minyard return 1; 4268bfffbccSCorey Minyard } 4278bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 4288bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 4299f7d1d92SCorey Minyard memcpy(ibs->sel.last_addition, ts, 4); 4308bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 4318bfffbccSCorey Minyard ibs->sel.next_free++; 4328bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 4338bfffbccSCorey Minyard return 0; 4348bfffbccSCorey Minyard } 4358bfffbccSCorey Minyard 4368bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 4378bfffbccSCorey Minyard { 4388bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 4398bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 4408bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 4418bfffbccSCorey Minyard } 4428bfffbccSCorey Minyard 4438bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 4448bfffbccSCorey Minyard { 4458bc8af69SCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && 4468bc8af69SCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) || 4478bc8af69SCorey Minyard IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs))) 4488bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 4498bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 4508bfffbccSCorey Minyard } 4518bfffbccSCorey Minyard 452cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log) 453cd60d85eSCédric Le Goater { 454cd60d85eSCédric Le Goater IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 455cd60d85eSCédric Le Goater IPMIInterface *s = ibs->parent.intf; 456cd60d85eSCédric Le Goater IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 457cd60d85eSCédric Le Goater 458cd60d85eSCédric Le Goater if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 459cd60d85eSCédric Le Goater return; 460cd60d85eSCédric Le Goater } 461cd60d85eSCédric Le Goater 462cd60d85eSCédric Le Goater if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 463cd60d85eSCédric Le Goater sel_add_event(ibs, evt); 464cd60d85eSCédric Le Goater } 465cd60d85eSCédric Le Goater 466cd60d85eSCédric Le Goater if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 467cd60d85eSCédric Le Goater goto out; 468cd60d85eSCédric Le Goater } 469cd60d85eSCédric Le Goater 470cd60d85eSCédric Le Goater memcpy(ibs->evtbuf, evt, 16); 471cd60d85eSCédric Le Goater ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 472cd60d85eSCédric Le Goater k->set_atn(s, 1, attn_irq_enabled(ibs)); 473cd60d85eSCédric Le Goater out: 474cd60d85eSCédric Le Goater return; 475cd60d85eSCédric Le Goater } 4768bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 4778bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 4788bfffbccSCorey Minyard { 4798bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 4808bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 4818bfffbccSCorey Minyard uint8_t evt[16]; 4828bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 4838bfffbccSCorey Minyard 4848bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 4858bfffbccSCorey Minyard return; 4868bfffbccSCorey Minyard } 4878bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 4888bfffbccSCorey Minyard return; 4898bfffbccSCorey Minyard } 4908bfffbccSCorey Minyard 4918bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 4928bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 4938bfffbccSCorey Minyard evt[8] = 0; 4948bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 4958bfffbccSCorey Minyard evt[10] = sens->sensor_type; 4968bfffbccSCorey Minyard evt[11] = sens_num; 4978bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 4988bfffbccSCorey Minyard evt[13] = evd1; 4998bfffbccSCorey Minyard evt[14] = evd2; 5008bfffbccSCorey Minyard evt[15] = evd3; 5018bfffbccSCorey Minyard 5028bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 5038bfffbccSCorey Minyard sel_add_event(ibs, evt); 5048bfffbccSCorey Minyard } 5058bfffbccSCorey Minyard 5068bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 507d13ada5dSCédric Le Goater return; 5088bfffbccSCorey Minyard } 5098bfffbccSCorey Minyard 5108bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 5118bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 5128bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 5138bfffbccSCorey Minyard } 5148bfffbccSCorey Minyard 5158bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 5168bfffbccSCorey Minyard unsigned int bit, unsigned int val, 5178bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 5188bfffbccSCorey Minyard { 5198bfffbccSCorey Minyard IPMISensor *sens; 5208bfffbccSCorey Minyard uint16_t mask; 5218bfffbccSCorey Minyard 5228bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 5238bfffbccSCorey Minyard return; 5248bfffbccSCorey Minyard } 5258bfffbccSCorey Minyard if (bit >= 16) { 5268bfffbccSCorey Minyard return; 5278bfffbccSCorey Minyard } 5288bfffbccSCorey Minyard 5298bfffbccSCorey Minyard mask = (1 << bit); 5308bfffbccSCorey Minyard sens = ibs->sensors + sensor; 5318bfffbccSCorey Minyard if (val) { 5328bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5338bfffbccSCorey Minyard if (sens->assert_states & mask) { 5348bfffbccSCorey Minyard return; /* Already asserted */ 5358bfffbccSCorey Minyard } 5368bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 5378bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 5388bfffbccSCorey Minyard /* Send an event on assert */ 5398bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5408bfffbccSCorey Minyard } 5418bfffbccSCorey Minyard } else { 5428bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5438bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5448bfffbccSCorey Minyard return; /* Already deasserted */ 5458bfffbccSCorey Minyard } 5468bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 5478bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 5488bfffbccSCorey Minyard /* Send an event on deassert */ 5498bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5508bfffbccSCorey Minyard } 5518bfffbccSCorey Minyard } 5528bfffbccSCorey Minyard } 5538bfffbccSCorey Minyard 5548bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5558bfffbccSCorey Minyard { 5568bfffbccSCorey Minyard unsigned int i, pos; 5578bfffbccSCorey Minyard IPMISensor *sens; 5588bfffbccSCorey Minyard 5598bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5608bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5618bfffbccSCorey Minyard } 5628bfffbccSCorey Minyard 5638bfffbccSCorey Minyard pos = 0; 5648bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 565a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 566a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 567a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5688bfffbccSCorey Minyard 5698bfffbccSCorey Minyard if (len < 20) { 5708bfffbccSCorey Minyard continue; 5718bfffbccSCorey Minyard } 572a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5738bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5748bfffbccSCorey Minyard } 5758bfffbccSCorey Minyard 57673d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 5778bfffbccSCorey Minyard continue; 5788bfffbccSCorey Minyard } 579a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5808bfffbccSCorey Minyard 5818bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 582a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 583a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 584a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 585a2295f0aSCédric Le Goater sens->deassert_suppt = 586a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 587a2295f0aSCédric Le Goater sens->states_suppt = 588a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 589a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 590a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5918bfffbccSCorey Minyard 5928bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5938bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5948bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5958bfffbccSCorey Minyard } 5968bfffbccSCorey Minyard } 5978bfffbccSCorey Minyard 598ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn, 5998bfffbccSCorey Minyard const IPMINetfn *netfnd) 6008bfffbccSCorey Minyard { 60193a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 6028bfffbccSCorey Minyard return -1; 6038bfffbccSCorey Minyard } 6048bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 6058bfffbccSCorey Minyard return 0; 6068bfffbccSCorey Minyard } 6078bfffbccSCorey Minyard 6084f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 6094f298a4bSCédric Le Goater unsigned int netfn, 6104f298a4bSCédric Le Goater unsigned int cmd) 6114f298a4bSCédric Le Goater { 6124f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 6134f298a4bSCédric Le Goater 6144f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 6154f298a4bSCédric Le Goater return NULL; 6164f298a4bSCédric Le Goater } 6174f298a4bSCédric Le Goater 6184f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 6194f298a4bSCédric Le Goater return NULL; 6204f298a4bSCédric Le Goater } 6214f298a4bSCédric Le Goater 6224f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 6234f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 6244f298a4bSCédric Le Goater return NULL; 6254f298a4bSCédric Le Goater } 6264f298a4bSCédric Le Goater 6274f298a4bSCédric Le Goater return hdl; 6284f298a4bSCédric Le Goater } 6294f298a4bSCédric Le Goater 6308bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 6318bfffbccSCorey Minyard { 6328bfffbccSCorey Minyard int64_t next; 6338bfffbccSCorey Minyard if (ibs->watchdog_running) { 6348bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6358bfffbccSCorey Minyard } else { 6368bfffbccSCorey Minyard /* Wait a minute */ 6378bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6388bfffbccSCorey Minyard } 6398bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6408bfffbccSCorey Minyard } 6418bfffbccSCorey Minyard 6428bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6438bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6448bfffbccSCorey Minyard unsigned int max_cmd_len, 6458bfffbccSCorey Minyard uint8_t msg_id) 6468bfffbccSCorey Minyard { 6478bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6488bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6498bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6504f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 651a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6528bfffbccSCorey Minyard 6538bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6548bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 655a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 6566acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 657d13ada5dSCédric Le Goater goto out; 658d13ada5dSCédric Le Goater } 659d13ada5dSCédric Le Goater 660a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 661a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 662a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6638bfffbccSCorey Minyard 6648bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6658bfffbccSCorey Minyard if (cmd_len < 2) { 6666acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6678bfffbccSCorey Minyard goto out; 6688bfffbccSCorey Minyard } 6698bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6706acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 6718bfffbccSCorey Minyard goto out; 6728bfffbccSCorey Minyard } 6738bfffbccSCorey Minyard 6748bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6758bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 6766acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN); 6778bfffbccSCorey Minyard goto out; 6788bfffbccSCorey Minyard } 6798bfffbccSCorey Minyard 6804f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 6814f298a4bSCédric Le Goater if (!hdl) { 6826acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD); 6838bfffbccSCorey Minyard goto out; 6848bfffbccSCorey Minyard } 6858bfffbccSCorey Minyard 6864f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 6876acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6884f298a4bSCédric Le Goater goto out; 6894f298a4bSCédric Le Goater } 6904f298a4bSCédric Le Goater 691a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 6928bfffbccSCorey Minyard 6938bfffbccSCorey Minyard out: 694a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 6958bfffbccSCorey Minyard 6968bfffbccSCorey Minyard next_timeout(ibs); 6978bfffbccSCorey Minyard } 6988bfffbccSCorey Minyard 6998bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 7008bfffbccSCorey Minyard { 7018bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7028bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7038bfffbccSCorey Minyard 7048bfffbccSCorey Minyard if (!ibs->watchdog_running) { 7058bfffbccSCorey Minyard goto out; 7068bfffbccSCorey Minyard } 7078bfffbccSCorey Minyard 7088bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 7098bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 7108bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 7118bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7128bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 7138bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 7148bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 7158bfffbccSCorey Minyard break; 7168bfffbccSCorey Minyard 7178bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 7188bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7198bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 7208bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 7218bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 7228bfffbccSCorey Minyard break; 7238bfffbccSCorey Minyard 7248bfffbccSCorey Minyard default: 7258bfffbccSCorey Minyard goto do_full_expiry; 7268bfffbccSCorey Minyard } 7278bfffbccSCorey Minyard 7288bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 7298bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 7308bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 7318bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 7328bfffbccSCorey Minyard goto out; 7338bfffbccSCorey Minyard } 7348bfffbccSCorey Minyard 7358bfffbccSCorey Minyard do_full_expiry: 7368bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7378bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7388bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7398bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7408bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 7418bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 7428bfffbccSCorey Minyard break; 7438bfffbccSCorey Minyard 7448bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7458bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 7468bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 7478bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7488bfffbccSCorey Minyard break; 7498bfffbccSCorey Minyard 7508bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7518bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7528bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 7538bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7548bfffbccSCorey Minyard break; 7558bfffbccSCorey Minyard 7568bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7578bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 7588bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 7598bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7608bfffbccSCorey Minyard break; 7618bfffbccSCorey Minyard } 7628bfffbccSCorey Minyard 7638bfffbccSCorey Minyard out: 7648bfffbccSCorey Minyard next_timeout(ibs); 7658bfffbccSCorey Minyard } 7668bfffbccSCorey Minyard 7678bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7688bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 769a580d820SCédric Le Goater RspBuffer *rsp) 7708bfffbccSCorey Minyard { 771a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 772a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 773a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 774a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 775a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 7768bfffbccSCorey Minyard } 7778bfffbccSCorey Minyard 7788bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7798bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 780a580d820SCédric Le Goater RspBuffer *rsp) 7818bfffbccSCorey Minyard { 782a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 783a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 784a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 785a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 7868bfffbccSCorey Minyard } 7878bfffbccSCorey Minyard 7888bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7898bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 790a580d820SCédric Le Goater RspBuffer *rsp) 7918bfffbccSCorey Minyard { 7928bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7938bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 7948bfffbccSCorey Minyard 7958bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 7968bfffbccSCorey Minyard case 0: /* power down */ 7976acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0)); 7988bfffbccSCorey Minyard break; 7998bfffbccSCorey Minyard case 1: /* power up */ 8006acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0)); 8018bfffbccSCorey Minyard break; 8028bfffbccSCorey Minyard case 2: /* power cycle */ 8036acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0)); 8048bfffbccSCorey Minyard break; 8058bfffbccSCorey Minyard case 3: /* hard reset */ 8066acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0)); 8078bfffbccSCorey Minyard break; 8088bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 8096acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0)); 8108bfffbccSCorey Minyard break; 8118bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 8126acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, 8136acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0)); 8148bfffbccSCorey Minyard break; 8158bfffbccSCorey Minyard default: 8166acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 8178bfffbccSCorey Minyard return; 8188bfffbccSCorey Minyard } 819d13ada5dSCédric Le Goater } 8208bfffbccSCorey Minyard 821b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 822b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 823a580d820SCédric Le Goater RspBuffer *rsp) 824a580d820SCédric Le Goater 825b7088392SCédric Le Goater { 826a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 827a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 828b7088392SCédric Le Goater } 829b7088392SCédric Le Goater 8308bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 8318bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 832a580d820SCédric Le Goater RspBuffer *rsp) 8338bfffbccSCorey Minyard { 834a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 835a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 836a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 837a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 838a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 839a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 84020b23364SCorey Minyard rsp_buffer_push(rsp, ibs->mfg_id & 0xff); 84120b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff); 84220b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff); 84320b23364SCorey Minyard rsp_buffer_push(rsp, ibs->product_id & 0xff); 84420b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff); 8458bfffbccSCorey Minyard } 8468bfffbccSCorey Minyard 8478bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8488bfffbccSCorey Minyard { 8498bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8508bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8518bfffbccSCorey Minyard bool irqs_on; 8528bfffbccSCorey Minyard 8538bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8548bfffbccSCorey Minyard 8558bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8568bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8578bfffbccSCorey Minyard 8588bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8598bfffbccSCorey Minyard } 8608bfffbccSCorey Minyard 8618bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8628bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 863a580d820SCédric Le Goater RspBuffer *rsp) 8648bfffbccSCorey Minyard { 8658bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8668bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8678bfffbccSCorey Minyard 8688bfffbccSCorey Minyard /* Disable all interrupts */ 8698bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8708bfffbccSCorey Minyard 8718bfffbccSCorey Minyard if (k->reset) { 8728bfffbccSCorey Minyard k->reset(s, true); 8738bfffbccSCorey Minyard } 8748bfffbccSCorey Minyard } 8758bfffbccSCorey Minyard 8768bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 878a580d820SCédric Le Goater RspBuffer *rsp) 8798bfffbccSCorey Minyard { 8808bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8818bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8828bfffbccSCorey Minyard 8838bfffbccSCorey Minyard if (k->reset) { 8848bfffbccSCorey Minyard k->reset(s, false); 8858bfffbccSCorey Minyard } 8868bfffbccSCorey Minyard } 88752ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs, 88852ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 889a580d820SCédric Le Goater RspBuffer *rsp) 89052ba4d50SCédric Le Goater { 89152ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 89252ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 89352ba4d50SCédric Le Goater } 89452ba4d50SCédric Le Goater 89552ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 89652ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 897a580d820SCédric Le Goater RspBuffer *rsp) 89852ba4d50SCédric Le Goater { 899a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 900a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 90152ba4d50SCédric Le Goater } 90252ba4d50SCédric Le Goater 90352ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 90452ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 905a580d820SCédric Le Goater RspBuffer *rsp) 90652ba4d50SCédric Le Goater { 90752ba4d50SCédric Le Goater unsigned int i; 90852ba4d50SCédric Le Goater 9097b0cd78bSCorey Minyard /* An uninitialized uuid is all zeros, use that to know if it is set. */ 91052ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 9117b0cd78bSCorey Minyard if (ibs->uuid.data[i]) { 9127b0cd78bSCorey Minyard goto uuid_set; 9137b0cd78bSCorey Minyard } 9147b0cd78bSCorey Minyard } 9157b0cd78bSCorey Minyard /* No uuid is set, return an error. */ 9167b0cd78bSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD); 9177b0cd78bSCorey Minyard return; 9187b0cd78bSCorey Minyard 9197b0cd78bSCorey Minyard uuid_set: 9207b0cd78bSCorey Minyard for (i = 0; i < 16; i++) { 9217b0cd78bSCorey Minyard rsp_buffer_push(rsp, ibs->uuid.data[i]); 92252ba4d50SCédric Le Goater } 92352ba4d50SCédric Le Goater } 9248bfffbccSCorey Minyard 9258bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 9268bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 927a580d820SCédric Le Goater RspBuffer *rsp) 9288bfffbccSCorey Minyard { 9298bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 9308bfffbccSCorey Minyard } 9318bfffbccSCorey Minyard 9328bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 9338bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 934a580d820SCédric Le Goater RspBuffer *rsp) 9358bfffbccSCorey Minyard { 936a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 9378bfffbccSCorey Minyard } 9388bfffbccSCorey Minyard 9398bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 9408bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 941a580d820SCédric Le Goater RspBuffer *rsp) 9428bfffbccSCorey Minyard { 9438bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9448bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9458bfffbccSCorey Minyard 9468bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9478bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9488bfffbccSCorey Minyard } 9498bfffbccSCorey Minyard 9508bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9518bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 952a580d820SCédric Le Goater RspBuffer *rsp) 9538bfffbccSCorey Minyard { 954a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9558bfffbccSCorey Minyard } 9568bfffbccSCorey Minyard 9578bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9588bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 959a580d820SCédric Le Goater RspBuffer *rsp) 9608bfffbccSCorey Minyard { 9618bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9628bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9638bfffbccSCorey Minyard unsigned int i; 9648bfffbccSCorey Minyard 9658bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 9666acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 967d13ada5dSCédric Le Goater return; 9688bfffbccSCorey Minyard } 9698bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 970a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 9718bfffbccSCorey Minyard } 9728bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9738bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9748bfffbccSCorey Minyard } 9758bfffbccSCorey Minyard 9768bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 978a580d820SCédric Le Goater RspBuffer *rsp) 9798bfffbccSCorey Minyard { 9808bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9818bfffbccSCorey Minyard 9828bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9836acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ 9848bfffbccSCorey Minyard goto out; 9858bfffbccSCorey Minyard } 986a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 9878bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 988a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 9898bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9908bfffbccSCorey Minyard g_free(msg); 9918bfffbccSCorey Minyard 9928bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9938bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9948bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9958bfffbccSCorey Minyard 9968bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 9978bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9988bfffbccSCorey Minyard } 9998bfffbccSCorey Minyard 10008bfffbccSCorey Minyard out: 10018bfffbccSCorey Minyard return; 10028bfffbccSCorey Minyard } 10038bfffbccSCorey Minyard 10048bfffbccSCorey Minyard static unsigned char 10058bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 10068bfffbccSCorey Minyard { 10078bfffbccSCorey Minyard for (; size > 0; size--, data++) { 10088bfffbccSCorey Minyard csum += *data; 10098bfffbccSCorey Minyard } 10108bfffbccSCorey Minyard 10118bfffbccSCorey Minyard return -csum; 10128bfffbccSCorey Minyard } 10138bfffbccSCorey Minyard 10148bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 10158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1016a580d820SCédric Le Goater RspBuffer *rsp) 10178bfffbccSCorey Minyard { 10188bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10198bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10208bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 10218bfffbccSCorey Minyard uint8_t *buf; 10228bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 10238bfffbccSCorey Minyard 1024*7f9e7af4SNicholas Piggin if (cmd[2] != IPMI_CHANNEL_IPMB) { 1025*7f9e7af4SNicholas Piggin /* We only handle channel 0h (IPMB) with no options */ 10266acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1027d13ada5dSCédric Le Goater return; 10288bfffbccSCorey Minyard } 10298bfffbccSCorey Minyard 10304f298a4bSCédric Le Goater if (cmd_len < 10) { 10316acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 10324f298a4bSCédric Le Goater return; 10334f298a4bSCédric Le Goater } 10344f298a4bSCédric Le Goater 10358bfffbccSCorey Minyard if (cmd[3] != 0x40) { 10368bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 10376acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */ 1038d13ada5dSCédric Le Goater return; 10398bfffbccSCorey Minyard } 10408bfffbccSCorey Minyard 10418bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10428bfffbccSCorey Minyard cmd_len -= 3; 10438bfffbccSCorey Minyard 10448bfffbccSCorey Minyard /* 10458bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10468bfffbccSCorey Minyard * be returned in the response. 10478bfffbccSCorey Minyard */ 10488bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10498bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1050d13ada5dSCédric Le Goater return; /* No response */ 10518bfffbccSCorey Minyard } 10528bfffbccSCorey Minyard 10538bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10548bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10558bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10568bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10578bfffbccSCorey Minyard 10588bfffbccSCorey Minyard if (rqLun != 2) { 10598bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1060d13ada5dSCédric Le Goater return; 10618bfffbccSCorey Minyard } 10628bfffbccSCorey Minyard 10638bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10648bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10658bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10668bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10678bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10688bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10698bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10708bfffbccSCorey Minyard msg->len = 6; 10718bfffbccSCorey Minyard 10728bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10738bfffbccSCorey Minyard /* Not a command we handle. */ 10748bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10758bfffbccSCorey Minyard goto end_msg; 10768bfffbccSCorey Minyard } 10778bfffbccSCorey Minyard 10788bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10798bfffbccSCorey Minyard buf[0] = 0; 10808bfffbccSCorey Minyard buf[1] = 0; 10818bfffbccSCorey Minyard buf[2] = 0; 10828bfffbccSCorey Minyard buf[3] = 0; 10838bfffbccSCorey Minyard buf[4] = 0x51; 10848bfffbccSCorey Minyard buf[5] = 0; 10858bfffbccSCorey Minyard buf[6] = 0; 10868bfffbccSCorey Minyard buf[7] = 0; 10878bfffbccSCorey Minyard buf[8] = 0; 10888bfffbccSCorey Minyard buf[9] = 0; 10898bfffbccSCorey Minyard buf[10] = 0; 10908bfffbccSCorey Minyard msg->len += 11; 10918bfffbccSCorey Minyard 10928bfffbccSCorey Minyard end_msg: 10938bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 10948bfffbccSCorey Minyard msg->len++; 10958bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 10968bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10978bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 10988bfffbccSCorey Minyard } 10998bfffbccSCorey Minyard 11008bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 11018bfffbccSCorey Minyard { 11028bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 11038bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 11048bfffbccSCorey Minyard ibs->watchdog_running = 0; 11058bfffbccSCorey Minyard return; 11068bfffbccSCorey Minyard } 11078bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 11088bfffbccSCorey Minyard 11098bfffbccSCorey Minyard 11108bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 11118bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 11128bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 11138bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 11148bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 11158bfffbccSCorey Minyard } 11168bfffbccSCorey Minyard ibs->watchdog_running = 1; 11178bfffbccSCorey Minyard } 11188bfffbccSCorey Minyard 11198bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 11208bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1121a580d820SCédric Le Goater RspBuffer *rsp) 11228bfffbccSCorey Minyard { 11238bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 11246acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1125d13ada5dSCédric Le Goater return; 11268bfffbccSCorey Minyard } 11278bfffbccSCorey Minyard do_watchdog_reset(ibs); 11288bfffbccSCorey Minyard } 11298bfffbccSCorey Minyard 11308bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 11318bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1132a580d820SCédric Le Goater RspBuffer *rsp) 11338bfffbccSCorey Minyard { 11348bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 11358bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 11368bfffbccSCorey Minyard unsigned int val; 11378bfffbccSCorey Minyard 11388bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 11398bfffbccSCorey Minyard if (val == 0 || val > 5) { 11406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1141d13ada5dSCédric Le Goater return; 11428bfffbccSCorey Minyard } 11438bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11448bfffbccSCorey Minyard switch (val) { 11458bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11468bfffbccSCorey Minyard break; 11478bfffbccSCorey Minyard 11488bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11496acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1)); 11508bfffbccSCorey Minyard break; 11518bfffbccSCorey Minyard 11528bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11536acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1)); 11548bfffbccSCorey Minyard break; 11558bfffbccSCorey Minyard 11568bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11576acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1)); 11588bfffbccSCorey Minyard break; 11598bfffbccSCorey Minyard 11608bfffbccSCorey Minyard default: 11616acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 11628bfffbccSCorey Minyard } 1163a580d820SCédric Le Goater if (rsp->buffer[2]) { 11646acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1165d13ada5dSCédric Le Goater return; 11668bfffbccSCorey Minyard } 11678bfffbccSCorey Minyard 11688bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11698bfffbccSCorey Minyard switch (val) { 11708bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11718bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11728bfffbccSCorey Minyard break; 11738bfffbccSCorey Minyard 11748bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11756af94767SCorey Minyard if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11768bfffbccSCorey Minyard /* NMI not supported. */ 11776acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1178d13ada5dSCédric Le Goater return; 11798bfffbccSCorey Minyard } 118037eebb86SCorey Minyard break; 118137eebb86SCorey Minyard 11828bfffbccSCorey Minyard default: 11838bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11846acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1185d13ada5dSCédric Le Goater return; 11868bfffbccSCorey Minyard } 11878bfffbccSCorey Minyard 11888bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11898bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11908bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11918bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 11928bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 11938bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 11948bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 11958bfffbccSCorey Minyard do_watchdog_reset(ibs); 11968bfffbccSCorey Minyard } else { 11978bfffbccSCorey Minyard ibs->watchdog_running = 0; 11988bfffbccSCorey Minyard } 11998bfffbccSCorey Minyard } 12008bfffbccSCorey Minyard 12018bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 12028bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1203a580d820SCédric Le Goater RspBuffer *rsp) 12048bfffbccSCorey Minyard { 1205a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1206a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1207a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1208a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 1209fb45770bSCorey Minyard rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff); 1210fb45770bSCorey Minyard rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff); 12118bfffbccSCorey Minyard if (ibs->watchdog_running) { 12128bfffbccSCorey Minyard long timeout; 12138bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 12148bfffbccSCorey Minyard / 100000000); 1215a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff); 1216a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff); 12178bfffbccSCorey Minyard } else { 1218a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 1219a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 12208bfffbccSCorey Minyard } 12218bfffbccSCorey Minyard } 12228bfffbccSCorey Minyard 1223*7f9e7af4SNicholas Piggin static void get_channel_info(IPMIBmcSim *ibs, 1224*7f9e7af4SNicholas Piggin uint8_t *cmd, unsigned int cmd_len, 1225*7f9e7af4SNicholas Piggin RspBuffer *rsp) 1226*7f9e7af4SNicholas Piggin { 1227*7f9e7af4SNicholas Piggin IPMIInterface *s = ibs->parent.intf; 1228*7f9e7af4SNicholas Piggin IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 1229*7f9e7af4SNicholas Piggin IPMIFwInfo info = {}; 1230*7f9e7af4SNicholas Piggin uint8_t ch = cmd[2] & 0x0f; 1231*7f9e7af4SNicholas Piggin 1232*7f9e7af4SNicholas Piggin /* Only define channel 0h (IPMB) and Fh (system interface) */ 1233*7f9e7af4SNicholas Piggin 1234*7f9e7af4SNicholas Piggin if (ch == 0x0e) { /* "This channel" */ 1235*7f9e7af4SNicholas Piggin ch = IPMI_CHANNEL_SYSTEM; 1236*7f9e7af4SNicholas Piggin } 1237*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, ch); 1238*7f9e7af4SNicholas Piggin 1239*7f9e7af4SNicholas Piggin if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) { 1240*7f9e7af4SNicholas Piggin /* Not a supported channel */ 1241*7f9e7af4SNicholas Piggin rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1242*7f9e7af4SNicholas Piggin return; 1243*7f9e7af4SNicholas Piggin } 1244*7f9e7af4SNicholas Piggin 1245*7f9e7af4SNicholas Piggin if (k->get_fwinfo) { 1246*7f9e7af4SNicholas Piggin k->get_fwinfo(s, &info); 1247*7f9e7af4SNicholas Piggin } 1248*7f9e7af4SNicholas Piggin 1249*7f9e7af4SNicholas Piggin if (ch == IPMI_CHANNEL_IPMB) { 1250*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB); 1251*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB); 1252*7f9e7af4SNicholas Piggin } else { /* IPMI_CHANNEL_SYSTEM */ 1253*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM); 1254*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, info.ipmi_channel_protocol); 1255*7f9e7af4SNicholas Piggin } 1256*7f9e7af4SNicholas Piggin 1257*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); /* Session-less */ 1258*7f9e7af4SNicholas Piggin 1259*7f9e7af4SNicholas Piggin /* IPMI Enterprise Number for Vendor ID */ 1260*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0xf2); 1261*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x1b); 1262*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); 1263*7f9e7af4SNicholas Piggin 1264*7f9e7af4SNicholas Piggin if (ch == IPMI_CHANNEL_SYSTEM) { 1265*7f9e7af4SNicholas Piggin uint8_t irq; 1266*7f9e7af4SNicholas Piggin 1267*7f9e7af4SNicholas Piggin if (info.irq_source == IPMI_ISA_IRQ) { 1268*7f9e7af4SNicholas Piggin irq = info.interrupt_number; 1269*7f9e7af4SNicholas Piggin } else if (info.irq_source == IPMI_PCI_IRQ) { 1270*7f9e7af4SNicholas Piggin irq = 0x10 + info.interrupt_number; 1271*7f9e7af4SNicholas Piggin } else { 1272*7f9e7af4SNicholas Piggin irq = 0xff; /* no interrupt / unspecified */ 1273*7f9e7af4SNicholas Piggin } 1274*7f9e7af4SNicholas Piggin 1275*7f9e7af4SNicholas Piggin /* Both interrupts use the same irq number */ 1276*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, irq); 1277*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, irq); 1278*7f9e7af4SNicholas Piggin } else { 1279*7f9e7af4SNicholas Piggin /* Reserved */ 1280*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); 1281*7f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); 1282*7f9e7af4SNicholas Piggin } 1283*7f9e7af4SNicholas Piggin } 1284*7f9e7af4SNicholas Piggin 12858bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 12868bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1287a580d820SCédric Le Goater RspBuffer *rsp) 12888bfffbccSCorey Minyard { 12898bfffbccSCorey Minyard unsigned int i; 12908bfffbccSCorey Minyard 1291a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1292a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1293a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1294a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1295a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 12968bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1297a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 12988bfffbccSCorey Minyard } 12998bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1300a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 13018bfffbccSCorey Minyard } 13028bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1303a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 13048bfffbccSCorey Minyard } 13058bfffbccSCorey Minyard 13068bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 13078bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1308a580d820SCédric Le Goater RspBuffer *rsp) 13098bfffbccSCorey Minyard { 1310a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1311a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 13128bfffbccSCorey Minyard } 13138bfffbccSCorey Minyard 13148bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 13158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1316a580d820SCédric Le Goater RspBuffer *rsp) 13178bfffbccSCorey Minyard { 13188bfffbccSCorey Minyard unsigned int pos; 13198bfffbccSCorey Minyard uint16_t nextrec; 1320a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 13218bfffbccSCorey Minyard 13228bfffbccSCorey Minyard if (cmd[6]) { 13237f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 13246acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13257f996411SCédric Le Goater return; 13268bfffbccSCorey Minyard } 13277f996411SCédric Le Goater } 13287f996411SCédric Le Goater 13298bfffbccSCorey Minyard pos = 0; 13308bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 13318bfffbccSCorey Minyard &pos, &nextrec)) { 13326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1333d13ada5dSCédric Le Goater return; 13348bfffbccSCorey Minyard } 1335a2295f0aSCédric Le Goater 1336a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1337a2295f0aSCédric Le Goater 1338a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 13396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE); 1340d13ada5dSCédric Le Goater return; 13418bfffbccSCorey Minyard } 13428bfffbccSCorey Minyard 1343a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1344a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 13458bfffbccSCorey Minyard 13468bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1347a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 13488bfffbccSCorey Minyard } 13498bfffbccSCorey Minyard 1350a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 13516acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES); 1352d13ada5dSCédric Le Goater return; 13538bfffbccSCorey Minyard } 1354a580d820SCédric Le Goater 1355a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 13568bfffbccSCorey Minyard } 13578bfffbccSCorey Minyard 13588bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 13598bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1360a580d820SCédric Le Goater RspBuffer *rsp) 13618bfffbccSCorey Minyard { 13628bfffbccSCorey Minyard uint16_t recid; 1363a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 13648bfffbccSCorey Minyard 1365a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 13666acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1367d13ada5dSCédric Le Goater return; 13688bfffbccSCorey Minyard } 1369a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1370a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 13718bfffbccSCorey Minyard } 13728bfffbccSCorey Minyard 13738bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 13748bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1375a580d820SCédric Le Goater RspBuffer *rsp) 13768bfffbccSCorey Minyard { 13777f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 13786acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13797f996411SCédric Le Goater return; 13807f996411SCédric Le Goater } 13817f996411SCédric Le Goater 13828bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13836acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1384d13ada5dSCédric Le Goater return; 13858bfffbccSCorey Minyard } 13868bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 13878bfffbccSCorey Minyard ibs->sdr.next_free = 0; 13888bfffbccSCorey Minyard ibs->sdr.overflow = 0; 13898bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1390a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13918bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 13928bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1393a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13948bfffbccSCorey Minyard } else { 13956acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 13968bfffbccSCorey Minyard return; 13978bfffbccSCorey Minyard } 1398d13ada5dSCédric Le Goater } 13998bfffbccSCorey Minyard 14008bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 14018bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1402a580d820SCédric Le Goater RspBuffer *rsp) 14038bfffbccSCorey Minyard { 14048bfffbccSCorey Minyard unsigned int i, val; 14058bfffbccSCorey Minyard 1406a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1407a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1408a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 14098bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1410a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1411a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 14128bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1413a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 14148bfffbccSCorey Minyard } 14158bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1416a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 14178bfffbccSCorey Minyard } 14188bfffbccSCorey Minyard /* Only support Reserve SEL */ 1419a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 14208bfffbccSCorey Minyard } 14218bfffbccSCorey Minyard 1422540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs, 1423540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1424540c07d3SCédric Le Goater RspBuffer *rsp) 1425540c07d3SCédric Le Goater { 1426540c07d3SCédric Le Goater uint8_t fruid; 1427540c07d3SCédric Le Goater uint16_t fru_entry_size; 1428540c07d3SCédric Le Goater 1429540c07d3SCédric Le Goater fruid = cmd[2]; 1430540c07d3SCédric Le Goater 1431540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1432540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1433540c07d3SCédric Le Goater return; 1434540c07d3SCédric Le Goater } 1435540c07d3SCédric Le Goater 1436540c07d3SCédric Le Goater fru_entry_size = ibs->fru.areasize; 1437540c07d3SCédric Le Goater 1438540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size & 0xff); 1439540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff); 1440540c07d3SCédric Le Goater rsp_buffer_push(rsp, 0x0); 1441540c07d3SCédric Le Goater } 1442540c07d3SCédric Le Goater 1443540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs, 1444540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1445540c07d3SCédric Le Goater RspBuffer *rsp) 1446540c07d3SCédric Le Goater { 1447540c07d3SCédric Le Goater uint8_t fruid; 1448540c07d3SCédric Le Goater uint16_t offset; 1449540c07d3SCédric Le Goater int i; 1450540c07d3SCédric Le Goater uint8_t *fru_entry; 1451540c07d3SCédric Le Goater unsigned int count; 1452540c07d3SCédric Le Goater 1453540c07d3SCédric Le Goater fruid = cmd[2]; 1454540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1455540c07d3SCédric Le Goater 1456540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1457540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1458540c07d3SCédric Le Goater return; 1459540c07d3SCédric Le Goater } 1460540c07d3SCédric Le Goater 1461540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1462540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1463540c07d3SCédric Le Goater return; 1464540c07d3SCédric Le Goater } 1465540c07d3SCédric Le Goater 1466540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1467540c07d3SCédric Le Goater 1468540c07d3SCédric Le Goater count = MIN(cmd[5], ibs->fru.areasize - offset); 1469540c07d3SCédric Le Goater 1470540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1471540c07d3SCédric Le Goater for (i = 0; i < count; i++) { 1472540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry[offset + i]); 1473540c07d3SCédric Le Goater } 1474540c07d3SCédric Le Goater } 1475540c07d3SCédric Le Goater 1476540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs, 1477540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1478540c07d3SCédric Le Goater RspBuffer *rsp) 1479540c07d3SCédric Le Goater { 1480540c07d3SCédric Le Goater uint8_t fruid; 1481540c07d3SCédric Le Goater uint16_t offset; 1482540c07d3SCédric Le Goater uint8_t *fru_entry; 1483540c07d3SCédric Le Goater unsigned int count; 1484540c07d3SCédric Le Goater 1485540c07d3SCédric Le Goater fruid = cmd[2]; 1486540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1487540c07d3SCédric Le Goater 1488540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1489540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1490540c07d3SCédric Le Goater return; 1491540c07d3SCédric Le Goater } 1492540c07d3SCédric Le Goater 1493540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1494540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1495540c07d3SCédric Le Goater return; 1496540c07d3SCédric Le Goater } 1497540c07d3SCédric Le Goater 1498540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1499540c07d3SCédric Le Goater 1500540c07d3SCédric Le Goater count = MIN(cmd_len - 5, ibs->fru.areasize - offset); 1501540c07d3SCédric Le Goater 1502540c07d3SCédric Le Goater memcpy(fru_entry + offset, cmd + 5, count); 1503540c07d3SCédric Le Goater 1504540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1505540c07d3SCédric Le Goater } 1506540c07d3SCédric Le Goater 15078bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 15088bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1509a580d820SCédric Le Goater RspBuffer *rsp) 15108bfffbccSCorey Minyard { 1511a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1512a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 15138bfffbccSCorey Minyard } 15148bfffbccSCorey Minyard 15158bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 15168bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1517a580d820SCédric Le Goater RspBuffer *rsp) 15188bfffbccSCorey Minyard { 15198bfffbccSCorey Minyard unsigned int val; 15208bfffbccSCorey Minyard 15218bfffbccSCorey Minyard if (cmd[6]) { 15227f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 15236acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 15247f996411SCédric Le Goater return; 15257f996411SCédric Le Goater } 15268bfffbccSCorey Minyard } 15278bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 15286acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1529d13ada5dSCédric Le Goater return; 15308bfffbccSCorey Minyard } 15318bfffbccSCorey Minyard if (cmd[6] > 15) { 15326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1533d13ada5dSCédric Le Goater return; 15348bfffbccSCorey Minyard } 15358bfffbccSCorey Minyard if (cmd[7] == 0xff) { 15368bfffbccSCorey Minyard cmd[7] = 16; 15378bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 15386acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1539d13ada5dSCédric Le Goater return; 15408bfffbccSCorey Minyard } else { 15418bfffbccSCorey Minyard cmd[7] += cmd[6]; 15428bfffbccSCorey Minyard } 15438bfffbccSCorey Minyard 15448bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 15458bfffbccSCorey Minyard if (val == 0xffff) { 15468bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 15478bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 15486acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1549d13ada5dSCédric Le Goater return; 15508bfffbccSCorey Minyard } 15518bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1552a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1553a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 15548bfffbccSCorey Minyard } else { 1555a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1556a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 15578bfffbccSCorey Minyard } 15588bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1559a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 15608bfffbccSCorey Minyard } 15618bfffbccSCorey Minyard } 15628bfffbccSCorey Minyard 15638bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 15648bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1565a580d820SCédric Le Goater RspBuffer *rsp) 15668bfffbccSCorey Minyard { 15678bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 15686acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 1569d13ada5dSCédric Le Goater return; 15708bfffbccSCorey Minyard } 15718bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1572a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1573a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 15748bfffbccSCorey Minyard } 15758bfffbccSCorey Minyard 15768bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 15778bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1578a580d820SCédric Le Goater RspBuffer *rsp) 15798bfffbccSCorey Minyard { 15807f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 15816acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 15827f996411SCédric Le Goater return; 15837f996411SCédric Le Goater } 15847f996411SCédric Le Goater 15858bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 15866acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1587d13ada5dSCédric Le Goater return; 15888bfffbccSCorey Minyard } 15898bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 15908bfffbccSCorey Minyard ibs->sel.next_free = 0; 15918bfffbccSCorey Minyard ibs->sel.overflow = 0; 15928bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1593a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 15948bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 15958bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1596a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 15978bfffbccSCorey Minyard } else { 15986acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 15998bfffbccSCorey Minyard return; 16008bfffbccSCorey Minyard } 1601d13ada5dSCédric Le Goater } 16028bfffbccSCorey Minyard 16038bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 16048bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1605a580d820SCédric Le Goater RspBuffer *rsp) 16068bfffbccSCorey Minyard { 16078bfffbccSCorey Minyard uint32_t val; 16088bfffbccSCorey Minyard struct ipmi_time now; 16098bfffbccSCorey Minyard 16108bfffbccSCorey Minyard ipmi_gettime(&now); 16118bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1612a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1613a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1614a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1615a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 16168bfffbccSCorey Minyard } 16178bfffbccSCorey Minyard 16188bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 16198bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1620a580d820SCédric Le Goater RspBuffer *rsp) 16218bfffbccSCorey Minyard { 16228bfffbccSCorey Minyard uint32_t val; 16238bfffbccSCorey Minyard struct ipmi_time now; 16248bfffbccSCorey Minyard 16258bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 16268bfffbccSCorey Minyard ipmi_gettime(&now); 16278bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 16288bfffbccSCorey Minyard } 16298bfffbccSCorey Minyard 16309380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs, 16319380d2edSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 16329380d2edSCorey Minyard RspBuffer *rsp) 16339380d2edSCorey Minyard { 16349380d2edSCorey Minyard uint8_t event[16]; 16359380d2edSCorey Minyard 16369380d2edSCorey Minyard event[2] = 2; /* System event record */ 16379380d2edSCorey Minyard event[7] = cmd[2]; /* Generator ID */ 16389380d2edSCorey Minyard event[8] = 0; 16399380d2edSCorey Minyard event[9] = cmd[3]; /* EvMRev */ 16409380d2edSCorey Minyard event[10] = cmd[4]; /* Sensor type */ 16419380d2edSCorey Minyard event[11] = cmd[5]; /* Sensor number */ 16429380d2edSCorey Minyard event[12] = cmd[6]; /* Event dir / Event type */ 16439380d2edSCorey Minyard event[13] = cmd[7]; /* Event data 1 */ 16449380d2edSCorey Minyard event[14] = cmd[8]; /* Event data 2 */ 16459380d2edSCorey Minyard event[15] = cmd[9]; /* Event data 3 */ 16469380d2edSCorey Minyard 16479380d2edSCorey Minyard if (sel_add_event(ibs, event)) { 16489380d2edSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 16499380d2edSCorey Minyard } 16509380d2edSCorey Minyard } 16519380d2edSCorey Minyard 16528bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 16538bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1654a580d820SCédric Le Goater RspBuffer *rsp) 16558bfffbccSCorey Minyard { 16568bfffbccSCorey Minyard IPMISensor *sens; 16578bfffbccSCorey Minyard 165873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16598bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16606acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1661d13ada5dSCédric Le Goater return; 16628bfffbccSCorey Minyard } 16638bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 16648bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 16658bfffbccSCorey Minyard case 0: /* Do not change */ 16668bfffbccSCorey Minyard break; 16678bfffbccSCorey Minyard case 1: /* Enable bits */ 16688bfffbccSCorey Minyard if (cmd_len > 4) { 16698bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 16708bfffbccSCorey Minyard } 16718bfffbccSCorey Minyard if (cmd_len > 5) { 16728bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 16738bfffbccSCorey Minyard } 16748bfffbccSCorey Minyard if (cmd_len > 6) { 16758bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 16768bfffbccSCorey Minyard } 16778bfffbccSCorey Minyard if (cmd_len > 7) { 16788bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 16798bfffbccSCorey Minyard } 16808bfffbccSCorey Minyard break; 16818bfffbccSCorey Minyard case 2: /* Disable bits */ 16828bfffbccSCorey Minyard if (cmd_len > 4) { 16838bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 16848bfffbccSCorey Minyard } 16858bfffbccSCorey Minyard if (cmd_len > 5) { 16868bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 16878bfffbccSCorey Minyard } 16888bfffbccSCorey Minyard if (cmd_len > 6) { 16898bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 16908bfffbccSCorey Minyard } 16918bfffbccSCorey Minyard if (cmd_len > 7) { 16928bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 16938bfffbccSCorey Minyard } 16948bfffbccSCorey Minyard break; 16958bfffbccSCorey Minyard case 3: 16966acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1697d13ada5dSCédric Le Goater return; 16988bfffbccSCorey Minyard } 16998bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 17008bfffbccSCorey Minyard } 17018bfffbccSCorey Minyard 17028bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 17038bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1704a580d820SCédric Le Goater RspBuffer *rsp) 17058bfffbccSCorey Minyard { 17068bfffbccSCorey Minyard IPMISensor *sens; 17078bfffbccSCorey Minyard 170873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17098bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17106acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1711d13ada5dSCédric Le Goater return; 17128bfffbccSCorey Minyard } 17138bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1714a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1715a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1716a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1717a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1718a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 17198bfffbccSCorey Minyard } 17208bfffbccSCorey Minyard 17218bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 17228bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1723a580d820SCédric Le Goater RspBuffer *rsp) 17248bfffbccSCorey Minyard { 17258bfffbccSCorey Minyard IPMISensor *sens; 17268bfffbccSCorey Minyard 172773d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17288bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17296acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1730d13ada5dSCédric Le Goater return; 17318bfffbccSCorey Minyard } 17328bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 17338bfffbccSCorey Minyard 17348bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 17358bfffbccSCorey Minyard /* Just clear everything */ 17368bfffbccSCorey Minyard sens->states = 0; 17378bfffbccSCorey Minyard return; 17388bfffbccSCorey Minyard } 1739d13ada5dSCédric Le Goater } 17408bfffbccSCorey Minyard 17418bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 17428bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1743a580d820SCédric Le Goater RspBuffer *rsp) 17448bfffbccSCorey Minyard { 17458bfffbccSCorey Minyard IPMISensor *sens; 17468bfffbccSCorey Minyard 174773d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17488bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17496acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1750d13ada5dSCédric Le Goater return; 17518bfffbccSCorey Minyard } 17528bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1753a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1754a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1755a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1756a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1757a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1758a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 17598bfffbccSCorey Minyard } 17608bfffbccSCorey Minyard 17618bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 17628bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1763a580d820SCédric Le Goater RspBuffer *rsp) 17648bfffbccSCorey Minyard { 17658bfffbccSCorey Minyard IPMISensor *sens; 17668bfffbccSCorey Minyard 176773d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17688bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17696acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1770d13ada5dSCédric Le Goater return; 17718bfffbccSCorey Minyard } 17728bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1773a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1774a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1775a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 17768bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1777a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 17788bfffbccSCorey Minyard } 17798bfffbccSCorey Minyard } 17808bfffbccSCorey Minyard 1781728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1782728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1783a580d820SCédric Le Goater RspBuffer *rsp) 1784728710e1SCédric Le Goater { 1785728710e1SCédric Le Goater IPMISensor *sens; 1786728710e1SCédric Le Goater 1787728710e1SCédric Le Goater 178873d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1789728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17906acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1791728710e1SCédric Le Goater return; 1792728710e1SCédric Le Goater } 1793728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1794728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1795728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1796728710e1SCédric Le Goater } 1797728710e1SCédric Le Goater 1798728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1799728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1800a580d820SCédric Le Goater RspBuffer *rsp) 1801728710e1SCédric Le Goater { 1802728710e1SCédric Le Goater IPMISensor *sens; 1803728710e1SCédric Le Goater 1804728710e1SCédric Le Goater 180573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1806728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 18076acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1808728710e1SCédric Le Goater return; 1809728710e1SCédric Le Goater } 1810728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1811a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1812a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1813728710e1SCédric Le Goater } 1814728710e1SCédric Le Goater 1815e3f7320cSCédric Le Goater /* 1816e3f7320cSCédric Le Goater * bytes parameter 1817e3f7320cSCédric Le Goater * 1 sensor number 1818e3f7320cSCédric Le Goater * 2 operation (see below for bits meaning) 1819e3f7320cSCédric Le Goater * 3 sensor reading 1820e3f7320cSCédric Le Goater * 4:5 assertion states (optional) 1821e3f7320cSCédric Le Goater * 6:7 deassertion states (optional) 1822e3f7320cSCédric Le Goater * 8:10 event data 1,2,3 (optional) 1823e3f7320cSCédric Le Goater */ 1824e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs, 1825e3f7320cSCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1826e3f7320cSCédric Le Goater RspBuffer *rsp) 1827e3f7320cSCédric Le Goater { 1828e3f7320cSCédric Le Goater IPMISensor *sens; 1829e3f7320cSCédric Le Goater uint8_t evd1 = 0; 1830e3f7320cSCédric Le Goater uint8_t evd2 = 0; 1831e3f7320cSCédric Le Goater uint8_t evd3 = 0; 1832e3f7320cSCédric Le Goater uint8_t new_reading = 0; 1833e3f7320cSCédric Le Goater uint16_t new_assert_states = 0; 1834e3f7320cSCédric Le Goater uint16_t new_deassert_states = 0; 1835e3f7320cSCédric Le Goater bool change_reading = false; 1836e3f7320cSCédric Le Goater bool change_assert = false; 1837e3f7320cSCédric Le Goater bool change_deassert = false; 1838e3f7320cSCédric Le Goater enum { 1839e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_NONE, 1840e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_DATA, 1841e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_BMC, 1842e3f7320cSCédric Le Goater } do_gen_event = SENSOR_GEN_EVENT_NONE; 1843e3f7320cSCédric Le Goater 1844e3f7320cSCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1845e3f7320cSCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1846e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1847e3f7320cSCédric Le Goater return; 1848e3f7320cSCédric Le Goater } 1849e3f7320cSCédric Le Goater 1850e3f7320cSCédric Le Goater sens = ibs->sensors + cmd[2]; 1851e3f7320cSCédric Le Goater 1852e3f7320cSCédric Le Goater /* [1:0] Sensor Reading operation */ 1853e3f7320cSCédric Le Goater switch ((cmd[3]) & 0x3) { 1854e3f7320cSCédric Le Goater case 0: /* Do not change */ 1855e3f7320cSCédric Le Goater break; 1856e3f7320cSCédric Le Goater case 1: /* write given value to sensor reading byte */ 1857e3f7320cSCédric Le Goater new_reading = cmd[4]; 1858e3f7320cSCédric Le Goater if (sens->reading != new_reading) { 1859e3f7320cSCédric Le Goater change_reading = true; 1860e3f7320cSCédric Le Goater } 1861e3f7320cSCédric Le Goater break; 1862e3f7320cSCédric Le Goater case 2: 1863e3f7320cSCédric Le Goater case 3: 1864e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1865e3f7320cSCédric Le Goater return; 1866e3f7320cSCédric Le Goater } 1867e3f7320cSCédric Le Goater 1868e3f7320cSCédric Le Goater /* [3:2] Deassertion bits operation */ 1869e3f7320cSCédric Le Goater switch ((cmd[3] >> 2) & 0x3) { 1870e3f7320cSCédric Le Goater case 0: /* Do not change */ 1871e3f7320cSCédric Le Goater break; 1872e3f7320cSCédric Le Goater case 1: /* write given value */ 1873e3f7320cSCédric Le Goater if (cmd_len > 7) { 1874e3f7320cSCédric Le Goater new_deassert_states = cmd[7]; 1875e3f7320cSCédric Le Goater change_deassert = true; 1876e3f7320cSCédric Le Goater } 1877e3f7320cSCédric Le Goater if (cmd_len > 8) { 1878e3f7320cSCédric Le Goater new_deassert_states |= (cmd[8] << 8); 1879e3f7320cSCédric Le Goater } 1880e3f7320cSCédric Le Goater break; 1881e3f7320cSCédric Le Goater 1882e3f7320cSCédric Le Goater case 2: /* mask on */ 1883e3f7320cSCédric Le Goater if (cmd_len > 7) { 1884e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states | cmd[7]); 1885e3f7320cSCédric Le Goater change_deassert = true; 1886e3f7320cSCédric Le Goater } 1887e3f7320cSCédric Le Goater if (cmd_len > 8) { 1888e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states | (cmd[8] << 8)); 1889e3f7320cSCédric Le Goater } 1890e3f7320cSCédric Le Goater break; 1891e3f7320cSCédric Le Goater 1892e3f7320cSCédric Le Goater case 3: /* mask off */ 1893e3f7320cSCédric Le Goater if (cmd_len > 7) { 1894e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states & cmd[7]); 1895e3f7320cSCédric Le Goater change_deassert = true; 1896e3f7320cSCédric Le Goater } 1897e3f7320cSCédric Le Goater if (cmd_len > 8) { 1898e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states & (cmd[8] << 8)); 1899e3f7320cSCédric Le Goater } 1900e3f7320cSCédric Le Goater break; 1901e3f7320cSCédric Le Goater } 1902e3f7320cSCédric Le Goater 1903e3f7320cSCédric Le Goater if (change_deassert && (new_deassert_states == sens->deassert_states)) { 1904e3f7320cSCédric Le Goater change_deassert = false; 1905e3f7320cSCédric Le Goater } 1906e3f7320cSCédric Le Goater 1907e3f7320cSCédric Le Goater /* [5:4] Assertion bits operation */ 1908e3f7320cSCédric Le Goater switch ((cmd[3] >> 4) & 0x3) { 1909e3f7320cSCédric Le Goater case 0: /* Do not change */ 1910e3f7320cSCédric Le Goater break; 1911e3f7320cSCédric Le Goater case 1: /* write given value */ 1912e3f7320cSCédric Le Goater if (cmd_len > 5) { 1913e3f7320cSCédric Le Goater new_assert_states = cmd[5]; 1914e3f7320cSCédric Le Goater change_assert = true; 1915e3f7320cSCédric Le Goater } 1916e3f7320cSCédric Le Goater if (cmd_len > 6) { 1917e3f7320cSCédric Le Goater new_assert_states |= (cmd[6] << 8); 1918e3f7320cSCédric Le Goater } 1919e3f7320cSCédric Le Goater break; 1920e3f7320cSCédric Le Goater 1921e3f7320cSCédric Le Goater case 2: /* mask on */ 1922e3f7320cSCédric Le Goater if (cmd_len > 5) { 1923e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states | cmd[5]); 1924e3f7320cSCédric Le Goater change_assert = true; 1925e3f7320cSCédric Le Goater } 1926e3f7320cSCédric Le Goater if (cmd_len > 6) { 1927e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states | (cmd[6] << 8)); 1928e3f7320cSCédric Le Goater } 1929e3f7320cSCédric Le Goater break; 1930e3f7320cSCédric Le Goater 1931e3f7320cSCédric Le Goater case 3: /* mask off */ 1932e3f7320cSCédric Le Goater if (cmd_len > 5) { 1933e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states & cmd[5]); 1934e3f7320cSCédric Le Goater change_assert = true; 1935e3f7320cSCédric Le Goater } 1936e3f7320cSCédric Le Goater if (cmd_len > 6) { 1937e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states & (cmd[6] << 8)); 1938e3f7320cSCédric Le Goater } 1939e3f7320cSCédric Le Goater break; 1940e3f7320cSCédric Le Goater } 1941e3f7320cSCédric Le Goater 1942e3f7320cSCédric Le Goater if (change_assert && (new_assert_states == sens->assert_states)) { 1943e3f7320cSCédric Le Goater change_assert = false; 1944e3f7320cSCédric Le Goater } 1945e3f7320cSCédric Le Goater 1946e3f7320cSCédric Le Goater if (cmd_len > 9) { 1947e3f7320cSCédric Le Goater evd1 = cmd[9]; 1948e3f7320cSCédric Le Goater } 1949e3f7320cSCédric Le Goater if (cmd_len > 10) { 1950e3f7320cSCédric Le Goater evd2 = cmd[10]; 1951e3f7320cSCédric Le Goater } 1952e3f7320cSCédric Le Goater if (cmd_len > 11) { 1953e3f7320cSCédric Le Goater evd3 = cmd[11]; 1954e3f7320cSCédric Le Goater } 1955e3f7320cSCédric Le Goater 1956e3f7320cSCédric Le Goater /* [7:6] Event Data Bytes operation */ 1957e3f7320cSCédric Le Goater switch ((cmd[3] >> 6) & 0x3) { 1958e3f7320cSCédric Le Goater case 0: /* 1959e3f7320cSCédric Le Goater * Don’t use Event Data bytes from this command. BMC will 1960e3f7320cSCédric Le Goater * generate it's own Event Data bytes based on its sensor 1961e3f7320cSCédric Le Goater * implementation. 1962e3f7320cSCédric Le Goater */ 1963e3f7320cSCédric Le Goater evd1 = evd2 = evd3 = 0x0; 1964e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_BMC; 1965e3f7320cSCédric Le Goater break; 1966e3f7320cSCédric Le Goater case 1: /* 1967e3f7320cSCédric Le Goater * Write given values to event data bytes including bits 1968e3f7320cSCédric Le Goater * [3:0] Event Data 1. 1969e3f7320cSCédric Le Goater */ 1970e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA; 1971e3f7320cSCédric Le Goater break; 1972e3f7320cSCédric Le Goater case 2: /* 1973e3f7320cSCédric Le Goater * Write given values to event data bytes excluding bits 1974e3f7320cSCédric Le Goater * [3:0] Event Data 1. 1975e3f7320cSCédric Le Goater */ 1976e3f7320cSCédric Le Goater evd1 &= 0xf0; 1977e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA; 1978e3f7320cSCédric Le Goater break; 1979e3f7320cSCédric Le Goater case 3: 1980e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1981e3f7320cSCédric Le Goater return; 1982e3f7320cSCédric Le Goater } 1983e3f7320cSCédric Le Goater 1984e3f7320cSCédric Le Goater /* 1985e3f7320cSCédric Le Goater * Event Data Bytes operation and parameter are inconsistent. The 1986e3f7320cSCédric Le Goater * Specs are not clear on that topic but generating an error seems 1987e3f7320cSCédric Le Goater * correct. 1988e3f7320cSCédric Le Goater */ 1989e3f7320cSCédric Le Goater if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) { 1990e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1991e3f7320cSCédric Le Goater return; 1992e3f7320cSCédric Le Goater } 1993e3f7320cSCédric Le Goater 1994e3f7320cSCédric Le Goater /* commit values */ 1995e3f7320cSCédric Le Goater if (change_reading) { 1996e3f7320cSCédric Le Goater sens->reading = new_reading; 1997e3f7320cSCédric Le Goater } 1998e3f7320cSCédric Le Goater 1999e3f7320cSCédric Le Goater if (change_assert) { 2000e3f7320cSCédric Le Goater sens->assert_states = new_assert_states; 2001e3f7320cSCédric Le Goater } 2002e3f7320cSCédric Le Goater 2003e3f7320cSCédric Le Goater if (change_deassert) { 2004e3f7320cSCédric Le Goater sens->deassert_states = new_deassert_states; 2005e3f7320cSCédric Le Goater } 2006e3f7320cSCédric Le Goater 2007e3f7320cSCédric Le Goater /* TODO: handle threshold sensor */ 2008e3f7320cSCédric Le Goater if (!IPMI_SENSOR_IS_DISCRETE(sens)) { 2009e3f7320cSCédric Le Goater return; 2010e3f7320cSCédric Le Goater } 2011e3f7320cSCédric Le Goater 2012e3f7320cSCédric Le Goater switch (do_gen_event) { 2013e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_DATA: { 2014e3f7320cSCédric Le Goater unsigned int bit = evd1 & 0xf; 2015e3f7320cSCédric Le Goater uint16_t mask = (1 << bit); 2016e3f7320cSCédric Le Goater 2017e3f7320cSCédric Le Goater if (sens->assert_states & mask & sens->assert_enable) { 2018e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 0, evd1, evd2, evd3); 2019e3f7320cSCédric Le Goater } 2020e3f7320cSCédric Le Goater 2021e3f7320cSCédric Le Goater if (sens->deassert_states & mask & sens->deassert_enable) { 2022e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 1, evd1, evd2, evd3); 2023e3f7320cSCédric Le Goater } 2024e3f7320cSCédric Le Goater break; 2025e3f7320cSCédric Le Goater } 2026e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_BMC: 2027e3f7320cSCédric Le Goater /* 2028e3f7320cSCédric Le Goater * TODO: generate event and event data bytes depending on the 2029e3f7320cSCédric Le Goater * sensor 2030e3f7320cSCédric Le Goater */ 2031e3f7320cSCédric Le Goater break; 2032e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_NONE: 2033e3f7320cSCédric Le Goater break; 2034e3f7320cSCédric Le Goater } 2035e3f7320cSCédric Le Goater } 2036728710e1SCédric Le Goater 203762a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 20384f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 20394f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 20404f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 20414f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 20428bfffbccSCorey Minyard }; 20438bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 204462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 20458bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 20468bfffbccSCorey Minyard }; 20478bfffbccSCorey Minyard 204862a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 20499380d2edSCorey Minyard [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 }, 20504f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 20514f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 20524f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 20534f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 20544f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 20554f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 20564f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 2057e3f7320cSCédric Le Goater [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 }, 20588bfffbccSCorey Minyard }; 20598bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 206062a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 20618bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 20628bfffbccSCorey Minyard }; 20638bfffbccSCorey Minyard 206462a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 20654f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 20664f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 20674f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 20684f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 20694f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 20704f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 20714f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 20724f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 20734f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 20744f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 20754f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 20764f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 20774f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 20784f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 20794f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 20804f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 2081*7f9e7af4SNicholas Piggin [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 }, 20828bfffbccSCorey Minyard }; 20838bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 208462a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 20858bfffbccSCorey Minyard .cmd_handlers = app_cmds 20868bfffbccSCorey Minyard }; 20878bfffbccSCorey Minyard 208862a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 2089540c07d3SCédric Le Goater [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 }, 2090540c07d3SCédric Le Goater [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 }, 2091540c07d3SCédric Le Goater [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 }, 20924f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 20934f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 20944f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 20954f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 20964f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 20974f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 20984f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 20994f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 21004f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 21014f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 21027f11cb65SCorey Minyard [IPMI_CMD_GET_SEL_TIME] = { get_sel_time }, 21037f11cb65SCorey Minyard [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 }, 21048bfffbccSCorey Minyard }; 21058bfffbccSCorey Minyard 21068bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 210762a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 21088bfffbccSCorey Minyard .cmd_handlers = storage_cmds 21098bfffbccSCorey Minyard }; 21108bfffbccSCorey Minyard 21118bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 21128bfffbccSCorey Minyard { 2113ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 2114ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 2115ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 2116ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 21178bfffbccSCorey Minyard } 21188bfffbccSCorey Minyard 21195167560bSCédric Le Goater static uint8_t init_sdrs[] = { 21208bfffbccSCorey Minyard /* Watchdog device */ 21218bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 21228bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 21238bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21248bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 21258bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 21268bfffbccSCorey Minyard }; 21278bfffbccSCorey Minyard 21284fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs) 21294fa9f08eSCédric Le Goater { 21304fa9f08eSCédric Le Goater unsigned int i; 21314fa9f08eSCédric Le Goater int len; 21325167560bSCédric Le Goater size_t sdrs_size; 21335167560bSCédric Le Goater uint8_t *sdrs; 213452fc01d9SCédric Le Goater 21355167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs); 21365167560bSCédric Le Goater sdrs = init_sdrs; 21378c6fd7f3SCédric Le Goater if (ibs->sdr_filename && 21388c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size, 21398c6fd7f3SCédric Le Goater NULL)) { 21408c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename); 21418c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs); 21428c6fd7f3SCédric Le Goater sdrs = init_sdrs; 21438c6fd7f3SCédric Le Goater } 21445167560bSCédric Le Goater 21455167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) { 214652fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh; 214752fc01d9SCédric Le Goater 21485167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) { 21494fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 21508c6fd7f3SCédric Le Goater break; 21514fa9f08eSCédric Le Goater } 21525167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i]; 21534fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh); 21545167560bSCédric Le Goater if (i + len > sdrs_size) { 21554fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 21568c6fd7f3SCédric Le Goater break; 21574fa9f08eSCédric Le Goater } 21584fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 21594fa9f08eSCédric Le Goater } 21608c6fd7f3SCédric Le Goater 21618c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) { 21628c6fd7f3SCédric Le Goater g_free(sdrs); 21638c6fd7f3SCédric Le Goater } 21644fa9f08eSCédric Le Goater } 21654fa9f08eSCédric Le Goater 2166bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 2167bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 2168bd66bcfcSCorey Minyard .version_id = 1, 2169bd66bcfcSCorey Minyard .minimum_version_id = 1, 217009c6ac6dSRichard Henderson .fields = (const VMStateField[]) { 2171bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 2172bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 2173bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 2174bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 2175bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 2176bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 21779e744990SJinhua Cao VMSTATE_UINT8(watchdog_expired, IPMIBmcSim), 2178bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 2179bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 2180bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 2181bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 2182bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 2183bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 2184bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 2185bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 2186bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 2187bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 2188bd66bcfcSCorey Minyard IPMIBmcSim), 2189bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 2190bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 2191bd66bcfcSCorey Minyard } 2192bd66bcfcSCorey Minyard }; 2193bd66bcfcSCorey Minyard 2194540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru) 2195540c07d3SCédric Le Goater { 2196540c07d3SCédric Le Goater int fsize; 2197540c07d3SCédric Le Goater int size = 0; 2198540c07d3SCédric Le Goater 2199540c07d3SCédric Le Goater if (!fru->filename) { 2200540c07d3SCédric Le Goater goto out; 2201540c07d3SCédric Le Goater } 2202540c07d3SCédric Le Goater 2203540c07d3SCédric Le Goater fsize = get_image_size(fru->filename); 2204540c07d3SCédric Le Goater if (fsize > 0) { 2205540c07d3SCédric Le Goater size = QEMU_ALIGN_UP(fsize, fru->areasize); 2206540c07d3SCédric Le Goater fru->data = g_malloc0(size); 2207540c07d3SCédric Le Goater if (load_image_size(fru->filename, fru->data, fsize) != fsize) { 2208540c07d3SCédric Le Goater error_report("Could not load file '%s'", fru->filename); 2209540c07d3SCédric Le Goater g_free(fru->data); 2210540c07d3SCédric Le Goater fru->data = NULL; 2211540c07d3SCédric Le Goater } 2212540c07d3SCédric Le Goater } 2213540c07d3SCédric Le Goater 2214540c07d3SCédric Le Goater out: 2215540c07d3SCédric Le Goater if (!fru->data) { 2216540c07d3SCédric Le Goater /* give one default FRU */ 2217540c07d3SCédric Le Goater size = fru->areasize; 2218540c07d3SCédric Le Goater fru->data = g_malloc0(size); 2219540c07d3SCédric Le Goater } 2220540c07d3SCédric Le Goater 2221540c07d3SCédric Le Goater fru->nentries = size / fru->areasize; 2222540c07d3SCédric Le Goater } 2223540c07d3SCédric Le Goater 22240bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp) 22258bfffbccSCorey Minyard { 22260bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev); 22278bfffbccSCorey Minyard unsigned int i; 22288bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 22298bfffbccSCorey Minyard 22308bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 22318bfffbccSCorey Minyard 22328bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 22338bfffbccSCorey Minyard ibs->device_id = 0x20; 22348bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 2235b7088392SCédric Le Goater ibs->restart_cause = 0; 22368bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 22378bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 22388bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 22398bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 22408bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 22418bfffbccSCorey Minyard } 22428bfffbccSCorey Minyard 22434fa9f08eSCédric Le Goater ipmi_sdr_init(ibs); 22448bfffbccSCorey Minyard 2245540c07d3SCédric Le Goater ipmi_fru_init(&ibs->fru); 2246540c07d3SCédric Le Goater 224752ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 224852ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 224952ba4d50SCédric Le Goater 22508bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 22518bfffbccSCorey Minyard register_cmds(ibs); 22528bfffbccSCorey Minyard 22538bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 22548bfffbccSCorey Minyard } 22558bfffbccSCorey Minyard 22562acf1403SRichard Henderson static const Property ipmi_sim_properties[] = { 2257540c07d3SCédric Le Goater DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024), 2258540c07d3SCédric Le Goater DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename), 22598c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename), 226020b23364SCorey Minyard DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20), 226120b23364SCorey Minyard DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02), 226220b23364SCorey Minyard DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0), 226320b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0), 226420b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0), 226520b23364SCorey Minyard DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0), 226620b23364SCorey Minyard DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0), 22677b0cd78bSCorey Minyard DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid), 22688c6fd7f3SCédric Le Goater }; 22698c6fd7f3SCédric Le Goater 22708bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 22718bfffbccSCorey Minyard { 22720bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc); 22738bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 22748bfffbccSCorey Minyard 227566abfddbSCorey Minyard dc->hotpluggable = false; 22760bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize; 2277d11d904cSCorey Minyard dc->vmsd = &vmstate_ipmi_sim; 22784f67d30bSMarc-André Lureau device_class_set_props(dc, ipmi_sim_properties); 22798bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 22808bfffbccSCorey Minyard } 22818bfffbccSCorey Minyard 22828bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 22838bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 22848bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 22858bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 22868bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 22878bfffbccSCorey Minyard }; 22888bfffbccSCorey Minyard 22898bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 22908bfffbccSCorey Minyard { 22918bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 22928bfffbccSCorey Minyard } 22938bfffbccSCorey Minyard 22948bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 2295