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 737f9e7af4SNicholas 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, 517*d9494ef9SNicholas Piggin uint8_t evd1, uint8_t evd2, uint8_t evd3, 518*d9494ef9SNicholas Piggin bool do_log) 5198bfffbccSCorey Minyard { 5208bfffbccSCorey Minyard IPMISensor *sens; 5218bfffbccSCorey Minyard uint16_t mask; 5228bfffbccSCorey Minyard 5238bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 5248bfffbccSCorey Minyard return; 5258bfffbccSCorey Minyard } 5268bfffbccSCorey Minyard if (bit >= 16) { 5278bfffbccSCorey Minyard return; 5288bfffbccSCorey Minyard } 5298bfffbccSCorey Minyard 5308bfffbccSCorey Minyard mask = (1 << bit); 5318bfffbccSCorey Minyard sens = ibs->sensors + sensor; 5328bfffbccSCorey Minyard if (val) { 5338bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 5348bfffbccSCorey Minyard if (sens->assert_states & mask) { 5358bfffbccSCorey Minyard return; /* Already asserted */ 5368bfffbccSCorey Minyard } 5378bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 538*d9494ef9SNicholas Piggin if (do_log && (sens->assert_enable & mask & sens->assert_states)) { 5398bfffbccSCorey Minyard /* Send an event on assert */ 5408bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 5418bfffbccSCorey Minyard } 5428bfffbccSCorey Minyard } else { 5438bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 5448bfffbccSCorey Minyard if (sens->deassert_states & mask) { 5458bfffbccSCorey Minyard return; /* Already deasserted */ 5468bfffbccSCorey Minyard } 5478bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 548*d9494ef9SNicholas Piggin if (do_log && (sens->deassert_enable & mask & sens->deassert_states)) { 5498bfffbccSCorey Minyard /* Send an event on deassert */ 5508bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 5518bfffbccSCorey Minyard } 5528bfffbccSCorey Minyard } 5538bfffbccSCorey Minyard } 5548bfffbccSCorey Minyard 5558bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 5568bfffbccSCorey Minyard { 5578bfffbccSCorey Minyard unsigned int i, pos; 5588bfffbccSCorey Minyard IPMISensor *sens; 5598bfffbccSCorey Minyard 5608bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 5618bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 5628bfffbccSCorey Minyard } 5638bfffbccSCorey Minyard 5648bfffbccSCorey Minyard pos = 0; 5658bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 566a2295f0aSCédric Le Goater struct ipmi_sdr_compact *sdr = 567a2295f0aSCédric Le Goater (struct ipmi_sdr_compact *) &s->sdr.sdr[pos]; 568a2295f0aSCédric Le Goater unsigned int len = sdr->header.rec_length; 5698bfffbccSCorey Minyard 5708bfffbccSCorey Minyard if (len < 20) { 5718bfffbccSCorey Minyard continue; 5728bfffbccSCorey Minyard } 573a2295f0aSCédric Le Goater if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) { 5748bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 5758bfffbccSCorey Minyard } 5768bfffbccSCorey Minyard 57773d60fa5SCédric Le Goater if (sdr->sensor_owner_number >= MAX_SENSORS) { 5788bfffbccSCorey Minyard continue; 5798bfffbccSCorey Minyard } 580a2295f0aSCédric Le Goater sens = s->sensors + sdr->sensor_owner_number; 5818bfffbccSCorey Minyard 5828bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 583a2295f0aSCédric Le Goater IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1); 584a2295f0aSCédric Le Goater IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1); 585a2295f0aSCédric Le Goater sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8); 586a2295f0aSCédric Le Goater sens->deassert_suppt = 587a2295f0aSCédric Le Goater sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8); 588a2295f0aSCédric Le Goater sens->states_suppt = 589a2295f0aSCédric Le Goater sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8); 590a2295f0aSCédric Le Goater sens->sensor_type = sdr->sensor_type; 591a2295f0aSCédric Le Goater sens->evt_reading_type_code = sdr->reading_type & 0x7f; 5928bfffbccSCorey Minyard 5938bfffbccSCorey Minyard /* Enable all the events that are supported. */ 5948bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 5958bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 5968bfffbccSCorey Minyard } 5978bfffbccSCorey Minyard } 5988bfffbccSCorey Minyard 599ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn, 6008bfffbccSCorey Minyard const IPMINetfn *netfnd) 6018bfffbccSCorey Minyard { 60293a53646SCorey Minyard if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) { 6038bfffbccSCorey Minyard return -1; 6048bfffbccSCorey Minyard } 6058bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 6068bfffbccSCorey Minyard return 0; 6078bfffbccSCorey Minyard } 6088bfffbccSCorey Minyard 6094f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs, 6104f298a4bSCédric Le Goater unsigned int netfn, 6114f298a4bSCédric Le Goater unsigned int cmd) 6124f298a4bSCédric Le Goater { 6134f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 6144f298a4bSCédric Le Goater 6154f298a4bSCédric Le Goater if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) { 6164f298a4bSCédric Le Goater return NULL; 6174f298a4bSCédric Le Goater } 6184f298a4bSCédric Le Goater 6194f298a4bSCédric Le Goater if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) { 6204f298a4bSCédric Le Goater return NULL; 6214f298a4bSCédric Le Goater } 6224f298a4bSCédric Le Goater 6234f298a4bSCédric Le Goater hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd]; 6244f298a4bSCédric Le Goater if (!hdl->cmd_handler) { 6254f298a4bSCédric Le Goater return NULL; 6264f298a4bSCédric Le Goater } 6274f298a4bSCédric Le Goater 6284f298a4bSCédric Le Goater return hdl; 6294f298a4bSCédric Le Goater } 6304f298a4bSCédric Le Goater 6318bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 6328bfffbccSCorey Minyard { 6338bfffbccSCorey Minyard int64_t next; 6348bfffbccSCorey Minyard if (ibs->watchdog_running) { 6358bfffbccSCorey Minyard next = ibs->watchdog_expiry; 6368bfffbccSCorey Minyard } else { 6378bfffbccSCorey Minyard /* Wait a minute */ 6388bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 6398bfffbccSCorey Minyard } 6408bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 6418bfffbccSCorey Minyard } 6428bfffbccSCorey Minyard 6438bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 6448bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 6458bfffbccSCorey Minyard unsigned int max_cmd_len, 6468bfffbccSCorey Minyard uint8_t msg_id) 6478bfffbccSCorey Minyard { 6488bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 6498bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 6508bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 6514f298a4bSCédric Le Goater const IPMICmdHandler *hdl; 652a580d820SCédric Le Goater RspBuffer rsp = RSP_BUFFER_INITIALIZER; 6538bfffbccSCorey Minyard 6548bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 6558bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 656a580d820SCédric Le Goater if (sizeof(rsp.buffer) < 3) { 6576acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 658d13ada5dSCédric Le Goater goto out; 659d13ada5dSCédric Le Goater } 660d13ada5dSCédric Le Goater 661a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[0] | 0x04); 662a580d820SCédric Le Goater rsp_buffer_push(&rsp, cmd[1]); 663a580d820SCédric Le Goater rsp_buffer_push(&rsp, 0); /* Assume success */ 6648bfffbccSCorey Minyard 6658bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 6668bfffbccSCorey Minyard if (cmd_len < 2) { 6676acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6688bfffbccSCorey Minyard goto out; 6698bfffbccSCorey Minyard } 6708bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 6716acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED); 6728bfffbccSCorey Minyard goto out; 6738bfffbccSCorey Minyard } 6748bfffbccSCorey Minyard 6758bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 6768bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 6776acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN); 6788bfffbccSCorey Minyard goto out; 6798bfffbccSCorey Minyard } 6808bfffbccSCorey Minyard 6814f298a4bSCédric Le Goater hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]); 6824f298a4bSCédric Le Goater if (!hdl) { 6836acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD); 6848bfffbccSCorey Minyard goto out; 6858bfffbccSCorey Minyard } 6868bfffbccSCorey Minyard 6874f298a4bSCédric Le Goater if (cmd_len < hdl->cmd_len_min) { 6886acb971aSCédric Le Goater rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 6894f298a4bSCédric Le Goater goto out; 6904f298a4bSCédric Le Goater } 6914f298a4bSCédric Le Goater 692a580d820SCédric Le Goater hdl->cmd_handler(ibs, cmd, cmd_len, &rsp); 6938bfffbccSCorey Minyard 6948bfffbccSCorey Minyard out: 695a580d820SCédric Le Goater k->handle_rsp(s, msg_id, rsp.buffer, rsp.len); 6968bfffbccSCorey Minyard 6978bfffbccSCorey Minyard next_timeout(ibs); 6988bfffbccSCorey Minyard } 6998bfffbccSCorey Minyard 7008bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 7018bfffbccSCorey Minyard { 7028bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 7038bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 704*d9494ef9SNicholas Piggin bool do_log = !IPMI_BMC_WATCHDOG_GET_DONT_LOG(ibs); 7058bfffbccSCorey Minyard 7068bfffbccSCorey Minyard if (!ibs->watchdog_running) { 7078bfffbccSCorey Minyard goto out; 7088bfffbccSCorey Minyard } 7098bfffbccSCorey Minyard 7108bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 7118bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 7128bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 7138bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7148bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 7158bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 716*d9494ef9SNicholas Piggin 0xc8, (2 << 4) | 0xf, 0xff, 717*d9494ef9SNicholas Piggin do_log); 7188bfffbccSCorey Minyard break; 7198bfffbccSCorey Minyard 7208bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 7218bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 7228bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 7238bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 724*d9494ef9SNicholas Piggin 0xc8, (3 << 4) | 0xf, 0xff, 725*d9494ef9SNicholas Piggin do_log); 7268bfffbccSCorey Minyard break; 7278bfffbccSCorey Minyard 7288bfffbccSCorey Minyard default: 7298bfffbccSCorey Minyard goto do_full_expiry; 7308bfffbccSCorey Minyard } 7318bfffbccSCorey Minyard 7328bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 7338bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 7348bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 7358bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 7368bfffbccSCorey Minyard goto out; 7378bfffbccSCorey Minyard } 7388bfffbccSCorey Minyard 7398bfffbccSCorey Minyard do_full_expiry: 7408bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 7418bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 7428bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 7438bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 7448bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 745*d9494ef9SNicholas Piggin 0xc0, ibs->watchdog_use & 0xf, 0xff, 746*d9494ef9SNicholas Piggin do_log); 7478bfffbccSCorey Minyard break; 7488bfffbccSCorey Minyard 7498bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 7508bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 751*d9494ef9SNicholas Piggin 0xc1, ibs->watchdog_use & 0xf, 0xff, 752*d9494ef9SNicholas Piggin do_log); 7538bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 7548bfffbccSCorey Minyard break; 7558bfffbccSCorey Minyard 7568bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 7578bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 758*d9494ef9SNicholas Piggin 0xc2, ibs->watchdog_use & 0xf, 0xff, 759*d9494ef9SNicholas Piggin do_log); 7608bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 7618bfffbccSCorey Minyard break; 7628bfffbccSCorey Minyard 7638bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 7648bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 765*d9494ef9SNicholas Piggin 0xc3, ibs->watchdog_use & 0xf, 0xff, 766*d9494ef9SNicholas Piggin do_log); 7678bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 7688bfffbccSCorey Minyard break; 7698bfffbccSCorey Minyard } 7708bfffbccSCorey Minyard 7718bfffbccSCorey Minyard out: 7728bfffbccSCorey Minyard next_timeout(ibs); 7738bfffbccSCorey Minyard } 7748bfffbccSCorey Minyard 7758bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 7768bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 777a580d820SCédric Le Goater RspBuffer *rsp) 7788bfffbccSCorey Minyard { 779a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 780a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 781a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 782a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 783a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->parent.slave_addr); 7848bfffbccSCorey Minyard } 7858bfffbccSCorey Minyard 7868bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 7878bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 788a580d820SCédric Le Goater RspBuffer *rsp) 7898bfffbccSCorey Minyard { 790a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */ 791a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 792a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 793a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 7948bfffbccSCorey Minyard } 7958bfffbccSCorey Minyard 7968bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 7978bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 798a580d820SCédric Le Goater RspBuffer *rsp) 7998bfffbccSCorey Minyard { 8008bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8018bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8028bfffbccSCorey Minyard 8038bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 8048bfffbccSCorey Minyard case 0: /* power down */ 8056acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0)); 8068bfffbccSCorey Minyard break; 8078bfffbccSCorey Minyard case 1: /* power up */ 8086acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0)); 8098bfffbccSCorey Minyard break; 8108bfffbccSCorey Minyard case 2: /* power cycle */ 8116acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0)); 8128bfffbccSCorey Minyard break; 8138bfffbccSCorey Minyard case 3: /* hard reset */ 8146acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0)); 8158bfffbccSCorey Minyard break; 8168bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 8176acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0)); 8188bfffbccSCorey Minyard break; 8198bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 8206acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, 8216acb971aSCédric Le Goater IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0)); 8228bfffbccSCorey Minyard break; 8238bfffbccSCorey Minyard default: 8246acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 8258bfffbccSCorey Minyard return; 8268bfffbccSCorey Minyard } 827d13ada5dSCédric Le Goater } 8288bfffbccSCorey Minyard 829b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs, 830b7088392SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 831a580d820SCédric Le Goater RspBuffer *rsp) 832a580d820SCédric Le Goater 833b7088392SCédric Le Goater { 834a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */ 835a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 836b7088392SCédric Le Goater } 837b7088392SCédric Le Goater 8388bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 8398bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 840a580d820SCédric Le Goater RspBuffer *rsp) 8418bfffbccSCorey Minyard { 842a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_id); 843a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->device_rev & 0xf); 844a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f); 845a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->fwrev2); 846a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->ipmi_version); 847a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ 84820b23364SCorey Minyard rsp_buffer_push(rsp, ibs->mfg_id & 0xff); 84920b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff); 85020b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff); 85120b23364SCorey Minyard rsp_buffer_push(rsp, ibs->product_id & 0xff); 85220b23364SCorey Minyard rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff); 8538bfffbccSCorey Minyard } 8548bfffbccSCorey Minyard 8558bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 8568bfffbccSCorey Minyard { 8578bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8588bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8598bfffbccSCorey Minyard bool irqs_on; 8608bfffbccSCorey Minyard 8618bfffbccSCorey Minyard ibs->bmc_global_enables = val; 8628bfffbccSCorey Minyard 8638bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 8648bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 8658bfffbccSCorey Minyard 8668bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 8678bfffbccSCorey Minyard } 8688bfffbccSCorey Minyard 8698bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 8708bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 871a580d820SCédric Le Goater RspBuffer *rsp) 8728bfffbccSCorey Minyard { 8738bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8748bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8758bfffbccSCorey Minyard 8768bfffbccSCorey Minyard /* Disable all interrupts */ 8778bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 8788bfffbccSCorey Minyard 8798bfffbccSCorey Minyard if (k->reset) { 8808bfffbccSCorey Minyard k->reset(s, true); 8818bfffbccSCorey Minyard } 8828bfffbccSCorey Minyard } 8838bfffbccSCorey Minyard 8848bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 8858bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 886a580d820SCédric Le Goater RspBuffer *rsp) 8878bfffbccSCorey Minyard { 8888bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 8898bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 8908bfffbccSCorey Minyard 8918bfffbccSCorey Minyard if (k->reset) { 8928bfffbccSCorey Minyard k->reset(s, false); 8938bfffbccSCorey Minyard } 8948bfffbccSCorey Minyard } 89552ba4d50SCédric Le Goater static void set_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 { 89952ba4d50SCédric Le Goater ibs->acpi_power_state[0] = cmd[2]; 90052ba4d50SCédric Le Goater ibs->acpi_power_state[1] = cmd[3]; 90152ba4d50SCédric Le Goater } 90252ba4d50SCédric Le Goater 90352ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs, 90452ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 905a580d820SCédric Le Goater RspBuffer *rsp) 90652ba4d50SCédric Le Goater { 907a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[0]); 908a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->acpi_power_state[1]); 90952ba4d50SCédric Le Goater } 91052ba4d50SCédric Le Goater 91152ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs, 91252ba4d50SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 913a580d820SCédric Le Goater RspBuffer *rsp) 91452ba4d50SCédric Le Goater { 91552ba4d50SCédric Le Goater unsigned int i; 91652ba4d50SCédric Le Goater 9177b0cd78bSCorey Minyard /* An uninitialized uuid is all zeros, use that to know if it is set. */ 91852ba4d50SCédric Le Goater for (i = 0; i < 16; i++) { 9197b0cd78bSCorey Minyard if (ibs->uuid.data[i]) { 9207b0cd78bSCorey Minyard goto uuid_set; 9217b0cd78bSCorey Minyard } 9227b0cd78bSCorey Minyard } 9237b0cd78bSCorey Minyard /* No uuid is set, return an error. */ 9247b0cd78bSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD); 9257b0cd78bSCorey Minyard return; 9267b0cd78bSCorey Minyard 9277b0cd78bSCorey Minyard uuid_set: 9287b0cd78bSCorey Minyard for (i = 0; i < 16; i++) { 9297b0cd78bSCorey Minyard rsp_buffer_push(rsp, ibs->uuid.data[i]); 93052ba4d50SCédric Le Goater } 93152ba4d50SCédric Le Goater } 9328bfffbccSCorey Minyard 9338bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 9348bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 935a580d820SCédric Le Goater RspBuffer *rsp) 9368bfffbccSCorey Minyard { 9378bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 9388bfffbccSCorey Minyard } 9398bfffbccSCorey Minyard 9408bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 9418bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 942a580d820SCédric Le Goater RspBuffer *rsp) 9438bfffbccSCorey Minyard { 944a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->bmc_global_enables); 9458bfffbccSCorey Minyard } 9468bfffbccSCorey Minyard 9478bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 9488bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 949a580d820SCédric Le Goater RspBuffer *rsp) 9508bfffbccSCorey Minyard { 9518bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9528bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9538bfffbccSCorey Minyard 9548bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 9558bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9568bfffbccSCorey Minyard } 9578bfffbccSCorey Minyard 9588bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 9598bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 960a580d820SCédric Le Goater RspBuffer *rsp) 9618bfffbccSCorey Minyard { 962a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->msg_flags); 9638bfffbccSCorey Minyard } 9648bfffbccSCorey Minyard 9658bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 9668bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 967a580d820SCédric Le Goater RspBuffer *rsp) 9688bfffbccSCorey Minyard { 9698bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 9708bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 9718bfffbccSCorey Minyard unsigned int i; 9728bfffbccSCorey Minyard 9738bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 9746acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 975d13ada5dSCédric Le Goater return; 9768bfffbccSCorey Minyard } 9778bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 978a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->evtbuf[i]); 9798bfffbccSCorey Minyard } 9808bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 9818bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 9828bfffbccSCorey Minyard } 9838bfffbccSCorey Minyard 9848bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 9858bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 986a580d820SCédric Le Goater RspBuffer *rsp) 9878bfffbccSCorey Minyard { 9888bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 9898bfffbccSCorey Minyard 9908bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 9916acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ 9928bfffbccSCorey Minyard goto out; 9938bfffbccSCorey Minyard } 994a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); /* Channel 0 */ 9958bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 996a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, msg->buf, msg->len); 9978bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 9988bfffbccSCorey Minyard g_free(msg); 9998bfffbccSCorey Minyard 10008bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 10018bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10028bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10038bfffbccSCorey Minyard 10048bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 10058bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 10068bfffbccSCorey Minyard } 10078bfffbccSCorey Minyard 10088bfffbccSCorey Minyard out: 10098bfffbccSCorey Minyard return; 10108bfffbccSCorey Minyard } 10118bfffbccSCorey Minyard 10128bfffbccSCorey Minyard static unsigned char 10138bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 10148bfffbccSCorey Minyard { 10158bfffbccSCorey Minyard for (; size > 0; size--, data++) { 10168bfffbccSCorey Minyard csum += *data; 10178bfffbccSCorey Minyard } 10188bfffbccSCorey Minyard 10198bfffbccSCorey Minyard return -csum; 10208bfffbccSCorey Minyard } 10218bfffbccSCorey Minyard 10228bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 10238bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1024a580d820SCédric Le Goater RspBuffer *rsp) 10258bfffbccSCorey Minyard { 10268bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 10278bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 10288bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 10298bfffbccSCorey Minyard uint8_t *buf; 10308bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 10318bfffbccSCorey Minyard 10327f9e7af4SNicholas Piggin if (cmd[2] != IPMI_CHANNEL_IPMB) { 10337f9e7af4SNicholas Piggin /* We only handle channel 0h (IPMB) with no options */ 10346acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1035d13ada5dSCédric Le Goater return; 10368bfffbccSCorey Minyard } 10378bfffbccSCorey Minyard 10384f298a4bSCédric Le Goater if (cmd_len < 10) { 10396acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID); 10404f298a4bSCédric Le Goater return; 10414f298a4bSCédric Le Goater } 10424f298a4bSCédric Le Goater 10438bfffbccSCorey Minyard if (cmd[3] != 0x40) { 10448bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 10456acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x83); /* NAK on write */ 1046d13ada5dSCédric Le Goater return; 10478bfffbccSCorey Minyard } 10488bfffbccSCorey Minyard 10498bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 10508bfffbccSCorey Minyard cmd_len -= 3; 10518bfffbccSCorey Minyard 10528bfffbccSCorey Minyard /* 10538bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 10548bfffbccSCorey Minyard * be returned in the response. 10558bfffbccSCorey Minyard */ 10568bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 10578bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 1058d13ada5dSCédric Le Goater return; /* No response */ 10598bfffbccSCorey Minyard } 10608bfffbccSCorey Minyard 10618bfffbccSCorey Minyard netfn = cmd[1] >> 2; 10628bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 10638bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 10648bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 10658bfffbccSCorey Minyard 10668bfffbccSCorey Minyard if (rqLun != 2) { 10678bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 1068d13ada5dSCédric Le Goater return; 10698bfffbccSCorey Minyard } 10708bfffbccSCorey Minyard 10718bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 10728bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 10738bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 10748bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 10758bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 10768bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 10778bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 10788bfffbccSCorey Minyard msg->len = 6; 10798bfffbccSCorey Minyard 10808bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 10818bfffbccSCorey Minyard /* Not a command we handle. */ 10828bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 10838bfffbccSCorey Minyard goto end_msg; 10848bfffbccSCorey Minyard } 10858bfffbccSCorey Minyard 10868bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 10878bfffbccSCorey Minyard buf[0] = 0; 10888bfffbccSCorey Minyard buf[1] = 0; 10898bfffbccSCorey Minyard buf[2] = 0; 10908bfffbccSCorey Minyard buf[3] = 0; 10918bfffbccSCorey Minyard buf[4] = 0x51; 10928bfffbccSCorey Minyard buf[5] = 0; 10938bfffbccSCorey Minyard buf[6] = 0; 10948bfffbccSCorey Minyard buf[7] = 0; 10958bfffbccSCorey Minyard buf[8] = 0; 10968bfffbccSCorey Minyard buf[9] = 0; 10978bfffbccSCorey Minyard buf[10] = 0; 10988bfffbccSCorey Minyard msg->len += 11; 10998bfffbccSCorey Minyard 11008bfffbccSCorey Minyard end_msg: 11018bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 11028bfffbccSCorey Minyard msg->len++; 11038bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 11048bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 11058bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 11068bfffbccSCorey Minyard } 11078bfffbccSCorey Minyard 11088bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 11098bfffbccSCorey Minyard { 11108bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 11118bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 11128bfffbccSCorey Minyard ibs->watchdog_running = 0; 11138bfffbccSCorey Minyard return; 11148bfffbccSCorey Minyard } 11158bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 11168bfffbccSCorey Minyard 11178bfffbccSCorey Minyard 11188bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 11198bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 11208bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 11218bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 11228bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 11238bfffbccSCorey Minyard } 11248bfffbccSCorey Minyard ibs->watchdog_running = 1; 11258bfffbccSCorey Minyard } 11268bfffbccSCorey Minyard 11278bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 11288bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1129a580d820SCédric Le Goater RspBuffer *rsp) 11308bfffbccSCorey Minyard { 11318bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 11326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, 0x80); 1133d13ada5dSCédric Le Goater return; 11348bfffbccSCorey Minyard } 11358bfffbccSCorey Minyard do_watchdog_reset(ibs); 11368bfffbccSCorey Minyard } 11378bfffbccSCorey Minyard 11388bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 11398bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1140a580d820SCédric Le Goater RspBuffer *rsp) 11418bfffbccSCorey Minyard { 11428bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 11438bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 11448bfffbccSCorey Minyard unsigned int val; 11458bfffbccSCorey Minyard 11468bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 11478bfffbccSCorey Minyard if (val == 0 || val > 5) { 11486acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1149d13ada5dSCédric Le Goater return; 11508bfffbccSCorey Minyard } 11518bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 11528bfffbccSCorey Minyard switch (val) { 11538bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 11548bfffbccSCorey Minyard break; 11558bfffbccSCorey Minyard 11568bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 11576acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1)); 11588bfffbccSCorey Minyard break; 11598bfffbccSCorey Minyard 11608bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 11616acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1)); 11628bfffbccSCorey Minyard break; 11638bfffbccSCorey Minyard 11648bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 11656acb971aSCédric Le Goater rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1)); 11668bfffbccSCorey Minyard break; 11678bfffbccSCorey Minyard 11688bfffbccSCorey Minyard default: 11696acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 11708bfffbccSCorey Minyard } 1171a580d820SCédric Le Goater if (rsp->buffer[2]) { 11726acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1173d13ada5dSCédric Le Goater return; 11748bfffbccSCorey Minyard } 11758bfffbccSCorey Minyard 11768bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 11778bfffbccSCorey Minyard switch (val) { 11788bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 11798bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 11808bfffbccSCorey Minyard break; 11818bfffbccSCorey Minyard 11828bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 11836af94767SCorey Minyard if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 11848bfffbccSCorey Minyard /* NMI not supported. */ 11856acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1186d13ada5dSCédric Le Goater return; 11878bfffbccSCorey Minyard } 118837eebb86SCorey Minyard break; 118937eebb86SCorey Minyard 11908bfffbccSCorey Minyard default: 11918bfffbccSCorey Minyard /* We don't support PRE_SMI */ 11926acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1193d13ada5dSCédric Le Goater return; 11948bfffbccSCorey Minyard } 11958bfffbccSCorey Minyard 11968bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 11978bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 11988bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 11998bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 12008bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 12018bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 12028bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 12038bfffbccSCorey Minyard do_watchdog_reset(ibs); 12048bfffbccSCorey Minyard } else { 12058bfffbccSCorey Minyard ibs->watchdog_running = 0; 12068bfffbccSCorey Minyard } 12078bfffbccSCorey Minyard } 12088bfffbccSCorey Minyard 12098bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 12108bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1211a580d820SCédric Le Goater RspBuffer *rsp) 12128bfffbccSCorey Minyard { 1213a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_use); 1214a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_action); 1215a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_pretimeout); 1216a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->watchdog_expired); 1217fb45770bSCorey Minyard rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff); 1218fb45770bSCorey Minyard rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff); 12198bfffbccSCorey Minyard if (ibs->watchdog_running) { 12208bfffbccSCorey Minyard long timeout; 12218bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 12228bfffbccSCorey Minyard / 100000000); 1223a580d820SCédric Le Goater rsp_buffer_push(rsp, timeout & 0xff); 1224a580d820SCédric Le Goater rsp_buffer_push(rsp, (timeout >> 8) & 0xff); 12258bfffbccSCorey Minyard } else { 1226a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 1227a580d820SCédric Le Goater rsp_buffer_push(rsp, 0); 12288bfffbccSCorey Minyard } 12298bfffbccSCorey Minyard } 12308bfffbccSCorey Minyard 12317f9e7af4SNicholas Piggin static void get_channel_info(IPMIBmcSim *ibs, 12327f9e7af4SNicholas Piggin uint8_t *cmd, unsigned int cmd_len, 12337f9e7af4SNicholas Piggin RspBuffer *rsp) 12347f9e7af4SNicholas Piggin { 12357f9e7af4SNicholas Piggin IPMIInterface *s = ibs->parent.intf; 12367f9e7af4SNicholas Piggin IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 12377f9e7af4SNicholas Piggin IPMIFwInfo info = {}; 12387f9e7af4SNicholas Piggin uint8_t ch = cmd[2] & 0x0f; 12397f9e7af4SNicholas Piggin 12407f9e7af4SNicholas Piggin /* Only define channel 0h (IPMB) and Fh (system interface) */ 12417f9e7af4SNicholas Piggin 12427f9e7af4SNicholas Piggin if (ch == 0x0e) { /* "This channel" */ 12437f9e7af4SNicholas Piggin ch = IPMI_CHANNEL_SYSTEM; 12447f9e7af4SNicholas Piggin } 12457f9e7af4SNicholas Piggin rsp_buffer_push(rsp, ch); 12467f9e7af4SNicholas Piggin 12477f9e7af4SNicholas Piggin if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) { 12487f9e7af4SNicholas Piggin /* Not a supported channel */ 12497f9e7af4SNicholas Piggin rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 12507f9e7af4SNicholas Piggin return; 12517f9e7af4SNicholas Piggin } 12527f9e7af4SNicholas Piggin 12537f9e7af4SNicholas Piggin if (k->get_fwinfo) { 12547f9e7af4SNicholas Piggin k->get_fwinfo(s, &info); 12557f9e7af4SNicholas Piggin } 12567f9e7af4SNicholas Piggin 12577f9e7af4SNicholas Piggin if (ch == IPMI_CHANNEL_IPMB) { 12587f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB); 12597f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB); 12607f9e7af4SNicholas Piggin } else { /* IPMI_CHANNEL_SYSTEM */ 12617f9e7af4SNicholas Piggin rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM); 12627f9e7af4SNicholas Piggin rsp_buffer_push(rsp, info.ipmi_channel_protocol); 12637f9e7af4SNicholas Piggin } 12647f9e7af4SNicholas Piggin 12657f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); /* Session-less */ 12667f9e7af4SNicholas Piggin 12677f9e7af4SNicholas Piggin /* IPMI Enterprise Number for Vendor ID */ 12687f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0xf2); 12697f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x1b); 12707f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); 12717f9e7af4SNicholas Piggin 12727f9e7af4SNicholas Piggin if (ch == IPMI_CHANNEL_SYSTEM) { 12737f9e7af4SNicholas Piggin uint8_t irq; 12747f9e7af4SNicholas Piggin 12757f9e7af4SNicholas Piggin if (info.irq_source == IPMI_ISA_IRQ) { 12767f9e7af4SNicholas Piggin irq = info.interrupt_number; 12777f9e7af4SNicholas Piggin } else if (info.irq_source == IPMI_PCI_IRQ) { 12787f9e7af4SNicholas Piggin irq = 0x10 + info.interrupt_number; 12797f9e7af4SNicholas Piggin } else { 12807f9e7af4SNicholas Piggin irq = 0xff; /* no interrupt / unspecified */ 12817f9e7af4SNicholas Piggin } 12827f9e7af4SNicholas Piggin 12837f9e7af4SNicholas Piggin /* Both interrupts use the same irq number */ 12847f9e7af4SNicholas Piggin rsp_buffer_push(rsp, irq); 12857f9e7af4SNicholas Piggin rsp_buffer_push(rsp, irq); 12867f9e7af4SNicholas Piggin } else { 12877f9e7af4SNicholas Piggin /* Reserved */ 12887f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); 12897f9e7af4SNicholas Piggin rsp_buffer_push(rsp, 0x00); 12907f9e7af4SNicholas Piggin } 12917f9e7af4SNicholas Piggin } 12927f9e7af4SNicholas Piggin 12938bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 12948bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1295a580d820SCédric Le Goater RspBuffer *rsp) 12968bfffbccSCorey Minyard { 12978bfffbccSCorey Minyard unsigned int i; 12988bfffbccSCorey Minyard 1299a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */ 1300a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff); 1301a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff); 1302a580d820SCédric Le Goater rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1303a580d820SCédric Le Goater rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 13048bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1305a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_addition[i]); 13068bfffbccSCorey Minyard } 13078bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1308a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.last_clear[i]); 13098bfffbccSCorey Minyard } 13108bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1311a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22); 13128bfffbccSCorey Minyard } 13138bfffbccSCorey Minyard 13148bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 13158bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1316a580d820SCédric Le Goater RspBuffer *rsp) 13178bfffbccSCorey Minyard { 1318a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff); 1319a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff); 13208bfffbccSCorey Minyard } 13218bfffbccSCorey Minyard 13228bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 13238bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1324a580d820SCédric Le Goater RspBuffer *rsp) 13258bfffbccSCorey Minyard { 13268bfffbccSCorey Minyard unsigned int pos; 13278bfffbccSCorey Minyard uint16_t nextrec; 1328a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh; 13298bfffbccSCorey Minyard 13308bfffbccSCorey Minyard if (cmd[6]) { 13317f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 13326acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13337f996411SCédric Le Goater return; 13348bfffbccSCorey Minyard } 13357f996411SCédric Le Goater } 13367f996411SCédric Le Goater 13378bfffbccSCorey Minyard pos = 0; 13388bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 13398bfffbccSCorey Minyard &pos, &nextrec)) { 13406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1341d13ada5dSCédric Le Goater return; 13428bfffbccSCorey Minyard } 1343a2295f0aSCédric Le Goater 1344a2295f0aSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos]; 1345a2295f0aSCédric Le Goater 1346a2295f0aSCédric Le Goater if (cmd[6] > ipmi_sdr_length(sdrh)) { 13476acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE); 1348d13ada5dSCédric Le Goater return; 13498bfffbccSCorey Minyard } 13508bfffbccSCorey Minyard 1351a580d820SCédric Le Goater rsp_buffer_push(rsp, nextrec & 0xff); 1352a580d820SCédric Le Goater rsp_buffer_push(rsp, (nextrec >> 8) & 0xff); 13538bfffbccSCorey Minyard 13548bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1355a2295f0aSCédric Le Goater cmd[7] = ipmi_sdr_length(sdrh) - cmd[6]; 13568bfffbccSCorey Minyard } 13578bfffbccSCorey Minyard 1358a580d820SCédric Le Goater if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) { 13596acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES); 1360d13ada5dSCédric Le Goater return; 13618bfffbccSCorey Minyard } 1362a580d820SCédric Le Goater 1363a580d820SCédric Le Goater rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 13648bfffbccSCorey Minyard } 13658bfffbccSCorey Minyard 13668bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 13678bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1368a580d820SCédric Le Goater RspBuffer *rsp) 13698bfffbccSCorey Minyard { 13708bfffbccSCorey Minyard uint16_t recid; 1371a2295f0aSCédric Le Goater struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2; 13728bfffbccSCorey Minyard 1373a2295f0aSCédric Le Goater if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) { 13746acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1375d13ada5dSCédric Le Goater return; 13768bfffbccSCorey Minyard } 1377a580d820SCédric Le Goater rsp_buffer_push(rsp, recid & 0xff); 1378a580d820SCédric Le Goater rsp_buffer_push(rsp, (recid >> 8) & 0xff); 13798bfffbccSCorey Minyard } 13808bfffbccSCorey Minyard 13818bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 13828bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1383a580d820SCédric Le Goater RspBuffer *rsp) 13848bfffbccSCorey Minyard { 13857f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) { 13866acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 13877f996411SCédric Le Goater return; 13887f996411SCédric Le Goater } 13897f996411SCédric Le Goater 13908bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 13916acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1392d13ada5dSCédric Le Goater return; 13938bfffbccSCorey Minyard } 13948bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 13958bfffbccSCorey Minyard ibs->sdr.next_free = 0; 13968bfffbccSCorey Minyard ibs->sdr.overflow = 0; 13978bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1398a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 13998bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 14008bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1401a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 14028bfffbccSCorey Minyard } else { 14036acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 14048bfffbccSCorey Minyard return; 14058bfffbccSCorey Minyard } 1406d13ada5dSCédric Le Goater } 14078bfffbccSCorey Minyard 14088bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 14098bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1410a580d820SCédric Le Goater RspBuffer *rsp) 14118bfffbccSCorey Minyard { 14128bfffbccSCorey Minyard unsigned int i, val; 14138bfffbccSCorey Minyard 1414a580d820SCédric Le Goater rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */ 1415a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.next_free & 0xff); 1416a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff); 14178bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1418a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1419a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 14208bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1421a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_addition[i]); 14228bfffbccSCorey Minyard } 14238bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1424a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.last_clear[i]); 14258bfffbccSCorey Minyard } 14268bfffbccSCorey Minyard /* Only support Reserve SEL */ 1427a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02); 14288bfffbccSCorey Minyard } 14298bfffbccSCorey Minyard 1430540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs, 1431540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1432540c07d3SCédric Le Goater RspBuffer *rsp) 1433540c07d3SCédric Le Goater { 1434540c07d3SCédric Le Goater uint8_t fruid; 1435540c07d3SCédric Le Goater uint16_t fru_entry_size; 1436540c07d3SCédric Le Goater 1437540c07d3SCédric Le Goater fruid = cmd[2]; 1438540c07d3SCédric Le Goater 1439540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1440540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1441540c07d3SCédric Le Goater return; 1442540c07d3SCédric Le Goater } 1443540c07d3SCédric Le Goater 1444540c07d3SCédric Le Goater fru_entry_size = ibs->fru.areasize; 1445540c07d3SCédric Le Goater 1446540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size & 0xff); 1447540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff); 1448540c07d3SCédric Le Goater rsp_buffer_push(rsp, 0x0); 1449540c07d3SCédric Le Goater } 1450540c07d3SCédric Le Goater 1451540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs, 1452540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1453540c07d3SCédric Le Goater RspBuffer *rsp) 1454540c07d3SCédric Le Goater { 1455540c07d3SCédric Le Goater uint8_t fruid; 1456540c07d3SCédric Le Goater uint16_t offset; 1457540c07d3SCédric Le Goater int i; 1458540c07d3SCédric Le Goater uint8_t *fru_entry; 1459540c07d3SCédric Le Goater unsigned int count; 1460540c07d3SCédric Le Goater 1461540c07d3SCédric Le Goater fruid = cmd[2]; 1462540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1463540c07d3SCédric Le Goater 1464540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1465540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1466540c07d3SCédric Le Goater return; 1467540c07d3SCédric Le Goater } 1468540c07d3SCédric Le Goater 1469540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1470540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1471540c07d3SCédric Le Goater return; 1472540c07d3SCédric Le Goater } 1473540c07d3SCédric Le Goater 1474540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1475540c07d3SCédric Le Goater 1476540c07d3SCédric Le Goater count = MIN(cmd[5], ibs->fru.areasize - offset); 1477540c07d3SCédric Le Goater 1478540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1479540c07d3SCédric Le Goater for (i = 0; i < count; i++) { 1480540c07d3SCédric Le Goater rsp_buffer_push(rsp, fru_entry[offset + i]); 1481540c07d3SCédric Le Goater } 1482540c07d3SCédric Le Goater } 1483540c07d3SCédric Le Goater 1484540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs, 1485540c07d3SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1486540c07d3SCédric Le Goater RspBuffer *rsp) 1487540c07d3SCédric Le Goater { 1488540c07d3SCédric Le Goater uint8_t fruid; 1489540c07d3SCédric Le Goater uint16_t offset; 1490540c07d3SCédric Le Goater uint8_t *fru_entry; 1491540c07d3SCédric Le Goater unsigned int count; 1492540c07d3SCédric Le Goater 1493540c07d3SCédric Le Goater fruid = cmd[2]; 1494540c07d3SCédric Le Goater offset = (cmd[3] | cmd[4] << 8); 1495540c07d3SCédric Le Goater 1496540c07d3SCédric Le Goater if (fruid >= ibs->fru.nentries) { 1497540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1498540c07d3SCédric Le Goater return; 1499540c07d3SCédric Le Goater } 1500540c07d3SCédric Le Goater 1501540c07d3SCédric Le Goater if (offset >= ibs->fru.areasize - 1) { 1502540c07d3SCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1503540c07d3SCédric Le Goater return; 1504540c07d3SCédric Le Goater } 1505540c07d3SCédric Le Goater 1506540c07d3SCédric Le Goater fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize]; 1507540c07d3SCédric Le Goater 1508540c07d3SCédric Le Goater count = MIN(cmd_len - 5, ibs->fru.areasize - offset); 1509540c07d3SCédric Le Goater 1510540c07d3SCédric Le Goater memcpy(fru_entry + offset, cmd + 5, count); 1511540c07d3SCédric Le Goater 1512540c07d3SCédric Le Goater rsp_buffer_push(rsp, count & 0xff); 1513540c07d3SCédric Le Goater } 1514540c07d3SCédric Le Goater 15158bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 15168bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1517a580d820SCédric Le Goater RspBuffer *rsp) 15188bfffbccSCorey Minyard { 1519a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.reservation & 0xff); 1520a580d820SCédric Le Goater rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff); 15218bfffbccSCorey Minyard } 15228bfffbccSCorey Minyard 15238bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 15248bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1525a580d820SCédric Le Goater RspBuffer *rsp) 15268bfffbccSCorey Minyard { 15278bfffbccSCorey Minyard unsigned int val; 15288bfffbccSCorey Minyard 15298bfffbccSCorey Minyard if (cmd[6]) { 15307f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 15316acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 15327f996411SCédric Le Goater return; 15337f996411SCédric Le Goater } 15348bfffbccSCorey Minyard } 15358bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 15366acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1537d13ada5dSCédric Le Goater return; 15388bfffbccSCorey Minyard } 15398bfffbccSCorey Minyard if (cmd[6] > 15) { 15406acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1541d13ada5dSCédric Le Goater return; 15428bfffbccSCorey Minyard } 15438bfffbccSCorey Minyard if (cmd[7] == 0xff) { 15448bfffbccSCorey Minyard cmd[7] = 16; 15458bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 15466acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1547d13ada5dSCédric Le Goater return; 15488bfffbccSCorey Minyard } else { 15498bfffbccSCorey Minyard cmd[7] += cmd[6]; 15508bfffbccSCorey Minyard } 15518bfffbccSCorey Minyard 15528bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 15538bfffbccSCorey Minyard if (val == 0xffff) { 15548bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 15558bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 15566acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1557d13ada5dSCédric Le Goater return; 15588bfffbccSCorey Minyard } 15598bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1560a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 1561a580d820SCédric Le Goater rsp_buffer_push(rsp, 0xff); 15628bfffbccSCorey Minyard } else { 1563a580d820SCédric Le Goater rsp_buffer_push(rsp, (val + 1) & 0xff); 1564a580d820SCédric Le Goater rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff); 15658bfffbccSCorey Minyard } 15668bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1567a580d820SCédric Le Goater rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]); 15688bfffbccSCorey Minyard } 15698bfffbccSCorey Minyard } 15708bfffbccSCorey Minyard 15718bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 15728bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1573a580d820SCédric Le Goater RspBuffer *rsp) 15748bfffbccSCorey Minyard { 15758bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 15766acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 1577d13ada5dSCédric Le Goater return; 15788bfffbccSCorey Minyard } 15798bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1580a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[2]); 1581a580d820SCédric Le Goater rsp_buffer_push(rsp, cmd[3]); 15828bfffbccSCorey Minyard } 15838bfffbccSCorey Minyard 15848bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 15858bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1586a580d820SCédric Le Goater RspBuffer *rsp) 15878bfffbccSCorey Minyard { 15887f996411SCédric Le Goater if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) { 15896acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION); 15907f996411SCédric Le Goater return; 15917f996411SCédric Le Goater } 15927f996411SCédric Le Goater 15938bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 15946acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1595d13ada5dSCédric Le Goater return; 15968bfffbccSCorey Minyard } 15978bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 15988bfffbccSCorey Minyard ibs->sel.next_free = 0; 15998bfffbccSCorey Minyard ibs->sel.overflow = 0; 16008bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1601a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 16028bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 16038bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1604a580d820SCédric Le Goater rsp_buffer_push(rsp, 1); /* Erasure complete */ 16058bfffbccSCorey Minyard } else { 16066acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 16078bfffbccSCorey Minyard return; 16088bfffbccSCorey Minyard } 1609d13ada5dSCédric Le Goater } 16108bfffbccSCorey Minyard 16118bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 16128bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1613a580d820SCédric Le Goater RspBuffer *rsp) 16148bfffbccSCorey Minyard { 16158bfffbccSCorey Minyard uint32_t val; 16168bfffbccSCorey Minyard struct ipmi_time now; 16178bfffbccSCorey Minyard 16188bfffbccSCorey Minyard ipmi_gettime(&now); 16198bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1620a580d820SCédric Le Goater rsp_buffer_push(rsp, val & 0xff); 1621a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 8) & 0xff); 1622a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 16) & 0xff); 1623a580d820SCédric Le Goater rsp_buffer_push(rsp, (val >> 24) & 0xff); 16248bfffbccSCorey Minyard } 16258bfffbccSCorey Minyard 16268bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 16278bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1628a580d820SCédric Le Goater RspBuffer *rsp) 16298bfffbccSCorey Minyard { 16308bfffbccSCorey Minyard uint32_t val; 16318bfffbccSCorey Minyard struct ipmi_time now; 16328bfffbccSCorey Minyard 16338bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 16348bfffbccSCorey Minyard ipmi_gettime(&now); 16358bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 16368bfffbccSCorey Minyard } 16378bfffbccSCorey Minyard 16389380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs, 16399380d2edSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 16409380d2edSCorey Minyard RspBuffer *rsp) 16419380d2edSCorey Minyard { 16429380d2edSCorey Minyard uint8_t event[16]; 16439380d2edSCorey Minyard 16449380d2edSCorey Minyard event[2] = 2; /* System event record */ 16459380d2edSCorey Minyard event[7] = cmd[2]; /* Generator ID */ 16469380d2edSCorey Minyard event[8] = 0; 16479380d2edSCorey Minyard event[9] = cmd[3]; /* EvMRev */ 16489380d2edSCorey Minyard event[10] = cmd[4]; /* Sensor type */ 16499380d2edSCorey Minyard event[11] = cmd[5]; /* Sensor number */ 16509380d2edSCorey Minyard event[12] = cmd[6]; /* Event dir / Event type */ 16519380d2edSCorey Minyard event[13] = cmd[7]; /* Event data 1 */ 16529380d2edSCorey Minyard event[14] = cmd[8]; /* Event data 2 */ 16539380d2edSCorey Minyard event[15] = cmd[9]; /* Event data 3 */ 16549380d2edSCorey Minyard 16559380d2edSCorey Minyard if (sel_add_event(ibs, event)) { 16569380d2edSCorey Minyard rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); 16579380d2edSCorey Minyard } 16589380d2edSCorey Minyard } 16599380d2edSCorey Minyard 16608bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 16618bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1662a580d820SCédric Le Goater RspBuffer *rsp) 16638bfffbccSCorey Minyard { 16648bfffbccSCorey Minyard IPMISensor *sens; 16658bfffbccSCorey Minyard 166673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 16678bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 16686acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1669d13ada5dSCédric Le Goater return; 16708bfffbccSCorey Minyard } 16718bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 16728bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 16738bfffbccSCorey Minyard case 0: /* Do not change */ 16748bfffbccSCorey Minyard break; 16758bfffbccSCorey Minyard case 1: /* Enable bits */ 16768bfffbccSCorey Minyard if (cmd_len > 4) { 16778bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 16788bfffbccSCorey Minyard } 16798bfffbccSCorey Minyard if (cmd_len > 5) { 16808bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 16818bfffbccSCorey Minyard } 16828bfffbccSCorey Minyard if (cmd_len > 6) { 16838bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 16848bfffbccSCorey Minyard } 16858bfffbccSCorey Minyard if (cmd_len > 7) { 16868bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 16878bfffbccSCorey Minyard } 16888bfffbccSCorey Minyard break; 16898bfffbccSCorey Minyard case 2: /* Disable bits */ 16908bfffbccSCorey Minyard if (cmd_len > 4) { 16918bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 16928bfffbccSCorey Minyard } 16938bfffbccSCorey Minyard if (cmd_len > 5) { 16948bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 16958bfffbccSCorey Minyard } 16968bfffbccSCorey Minyard if (cmd_len > 6) { 16978bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 16988bfffbccSCorey Minyard } 16998bfffbccSCorey Minyard if (cmd_len > 7) { 17008bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 17018bfffbccSCorey Minyard } 17028bfffbccSCorey Minyard break; 17038bfffbccSCorey Minyard case 3: 17046acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1705d13ada5dSCédric Le Goater return; 17068bfffbccSCorey Minyard } 17078bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 17088bfffbccSCorey Minyard } 17098bfffbccSCorey Minyard 17108bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 17118bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1712a580d820SCédric Le Goater RspBuffer *rsp) 17138bfffbccSCorey Minyard { 17148bfffbccSCorey Minyard IPMISensor *sens; 17158bfffbccSCorey Minyard 171673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17178bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17186acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1719d13ada5dSCédric Le Goater return; 17208bfffbccSCorey Minyard } 17218bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1722a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1723a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_enable & 0xff); 1724a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff); 1725a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_enable & 0xff); 1726a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff); 17278bfffbccSCorey Minyard } 17288bfffbccSCorey Minyard 17298bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 17308bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1731a580d820SCédric Le Goater RspBuffer *rsp) 17328bfffbccSCorey Minyard { 17338bfffbccSCorey Minyard IPMISensor *sens; 17348bfffbccSCorey Minyard 173573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17368bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17376acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1738d13ada5dSCédric Le Goater return; 17398bfffbccSCorey Minyard } 17408bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 17418bfffbccSCorey Minyard 17428bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 17438bfffbccSCorey Minyard /* Just clear everything */ 17448bfffbccSCorey Minyard sens->states = 0; 17458bfffbccSCorey Minyard return; 17468bfffbccSCorey Minyard } 1747d13ada5dSCédric Le Goater } 17488bfffbccSCorey Minyard 17498bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 17508bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1751a580d820SCédric Le Goater RspBuffer *rsp) 17528bfffbccSCorey Minyard { 17538bfffbccSCorey Minyard IPMISensor *sens; 17548bfffbccSCorey Minyard 175573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17568bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17576acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1758d13ada5dSCédric Le Goater return; 17598bfffbccSCorey Minyard } 17608bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1761a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1762a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1763a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->assert_states & 0xff); 1764a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff); 1765a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->deassert_states & 0xff); 1766a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff); 17678bfffbccSCorey Minyard } 17688bfffbccSCorey Minyard 17698bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 17708bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1771a580d820SCédric Le Goater RspBuffer *rsp) 17728bfffbccSCorey Minyard { 17738bfffbccSCorey Minyard IPMISensor *sens; 17748bfffbccSCorey Minyard 177573d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 17768bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17776acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1778d13ada5dSCédric Le Goater return; 17798bfffbccSCorey Minyard } 17808bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1781a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->reading); 1782a580d820SCédric Le Goater rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens)); 1783a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->states & 0xff); 17848bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1785a580d820SCédric Le Goater rsp_buffer_push(rsp, (sens->states >> 8) & 0xff); 17868bfffbccSCorey Minyard } 17878bfffbccSCorey Minyard } 17888bfffbccSCorey Minyard 1789728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs, 1790728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1791a580d820SCédric Le Goater RspBuffer *rsp) 1792728710e1SCédric Le Goater { 1793728710e1SCédric Le Goater IPMISensor *sens; 1794728710e1SCédric Le Goater 1795728710e1SCédric Le Goater 179673d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1797728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 17986acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1799728710e1SCédric Le Goater return; 1800728710e1SCédric Le Goater } 1801728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1802728710e1SCédric Le Goater sens->sensor_type = cmd[3]; 1803728710e1SCédric Le Goater sens->evt_reading_type_code = cmd[4] & 0x7f; 1804728710e1SCédric Le Goater } 1805728710e1SCédric Le Goater 1806728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs, 1807728710e1SCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1808a580d820SCédric Le Goater RspBuffer *rsp) 1809728710e1SCédric Le Goater { 1810728710e1SCédric Le Goater IPMISensor *sens; 1811728710e1SCédric Le Goater 1812728710e1SCédric Le Goater 181373d60fa5SCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1814728710e1SCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 18156acb971aSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1816728710e1SCédric Le Goater return; 1817728710e1SCédric Le Goater } 1818728710e1SCédric Le Goater sens = ibs->sensors + cmd[2]; 1819a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->sensor_type); 1820a580d820SCédric Le Goater rsp_buffer_push(rsp, sens->evt_reading_type_code); 1821728710e1SCédric Le Goater } 1822728710e1SCédric Le Goater 1823e3f7320cSCédric Le Goater /* 1824e3f7320cSCédric Le Goater * bytes parameter 1825e3f7320cSCédric Le Goater * 1 sensor number 1826e3f7320cSCédric Le Goater * 2 operation (see below for bits meaning) 1827e3f7320cSCédric Le Goater * 3 sensor reading 1828e3f7320cSCédric Le Goater * 4:5 assertion states (optional) 1829e3f7320cSCédric Le Goater * 6:7 deassertion states (optional) 1830e3f7320cSCédric Le Goater * 8:10 event data 1,2,3 (optional) 1831e3f7320cSCédric Le Goater */ 1832e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs, 1833e3f7320cSCédric Le Goater uint8_t *cmd, unsigned int cmd_len, 1834e3f7320cSCédric Le Goater RspBuffer *rsp) 1835e3f7320cSCédric Le Goater { 1836e3f7320cSCédric Le Goater IPMISensor *sens; 1837e3f7320cSCédric Le Goater uint8_t evd1 = 0; 1838e3f7320cSCédric Le Goater uint8_t evd2 = 0; 1839e3f7320cSCédric Le Goater uint8_t evd3 = 0; 1840e3f7320cSCédric Le Goater uint8_t new_reading = 0; 1841e3f7320cSCédric Le Goater uint16_t new_assert_states = 0; 1842e3f7320cSCédric Le Goater uint16_t new_deassert_states = 0; 1843e3f7320cSCédric Le Goater bool change_reading = false; 1844e3f7320cSCédric Le Goater bool change_assert = false; 1845e3f7320cSCédric Le Goater bool change_deassert = false; 1846e3f7320cSCédric Le Goater enum { 1847e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_NONE, 1848e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_DATA, 1849e3f7320cSCédric Le Goater SENSOR_GEN_EVENT_BMC, 1850e3f7320cSCédric Le Goater } do_gen_event = SENSOR_GEN_EVENT_NONE; 1851e3f7320cSCédric Le Goater 1852e3f7320cSCédric Le Goater if ((cmd[2] >= MAX_SENSORS) || 1853e3f7320cSCédric Le Goater !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1854e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT); 1855e3f7320cSCédric Le Goater return; 1856e3f7320cSCédric Le Goater } 1857e3f7320cSCédric Le Goater 1858e3f7320cSCédric Le Goater sens = ibs->sensors + cmd[2]; 1859e3f7320cSCédric Le Goater 1860e3f7320cSCédric Le Goater /* [1:0] Sensor Reading operation */ 1861e3f7320cSCédric Le Goater switch ((cmd[3]) & 0x3) { 1862e3f7320cSCédric Le Goater case 0: /* Do not change */ 1863e3f7320cSCédric Le Goater break; 1864e3f7320cSCédric Le Goater case 1: /* write given value to sensor reading byte */ 1865e3f7320cSCédric Le Goater new_reading = cmd[4]; 1866e3f7320cSCédric Le Goater if (sens->reading != new_reading) { 1867e3f7320cSCédric Le Goater change_reading = true; 1868e3f7320cSCédric Le Goater } 1869e3f7320cSCédric Le Goater break; 1870e3f7320cSCédric Le Goater case 2: 1871e3f7320cSCédric Le Goater case 3: 1872e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1873e3f7320cSCédric Le Goater return; 1874e3f7320cSCédric Le Goater } 1875e3f7320cSCédric Le Goater 1876e3f7320cSCédric Le Goater /* [3:2] Deassertion bits operation */ 1877e3f7320cSCédric Le Goater switch ((cmd[3] >> 2) & 0x3) { 1878e3f7320cSCédric Le Goater case 0: /* Do not change */ 1879e3f7320cSCédric Le Goater break; 1880e3f7320cSCédric Le Goater case 1: /* write given value */ 1881e3f7320cSCédric Le Goater if (cmd_len > 7) { 1882e3f7320cSCédric Le Goater new_deassert_states = cmd[7]; 1883e3f7320cSCédric Le Goater change_deassert = true; 1884e3f7320cSCédric Le Goater } 1885e3f7320cSCédric Le Goater if (cmd_len > 8) { 1886e3f7320cSCédric Le Goater new_deassert_states |= (cmd[8] << 8); 1887e3f7320cSCédric Le Goater } 1888e3f7320cSCédric Le Goater break; 1889e3f7320cSCédric Le Goater 1890e3f7320cSCédric Le Goater case 2: /* mask on */ 1891e3f7320cSCédric Le Goater if (cmd_len > 7) { 1892e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states | cmd[7]); 1893e3f7320cSCédric Le Goater change_deassert = true; 1894e3f7320cSCédric Le Goater } 1895e3f7320cSCédric Le Goater if (cmd_len > 8) { 1896e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states | (cmd[8] << 8)); 1897e3f7320cSCédric Le Goater } 1898e3f7320cSCédric Le Goater break; 1899e3f7320cSCédric Le Goater 1900e3f7320cSCédric Le Goater case 3: /* mask off */ 1901e3f7320cSCédric Le Goater if (cmd_len > 7) { 1902e3f7320cSCédric Le Goater new_deassert_states = (sens->deassert_states & cmd[7]); 1903e3f7320cSCédric Le Goater change_deassert = true; 1904e3f7320cSCédric Le Goater } 1905e3f7320cSCédric Le Goater if (cmd_len > 8) { 1906e3f7320cSCédric Le Goater new_deassert_states |= (sens->deassert_states & (cmd[8] << 8)); 1907e3f7320cSCédric Le Goater } 1908e3f7320cSCédric Le Goater break; 1909e3f7320cSCédric Le Goater } 1910e3f7320cSCédric Le Goater 1911e3f7320cSCédric Le Goater if (change_deassert && (new_deassert_states == sens->deassert_states)) { 1912e3f7320cSCédric Le Goater change_deassert = false; 1913e3f7320cSCédric Le Goater } 1914e3f7320cSCédric Le Goater 1915e3f7320cSCédric Le Goater /* [5:4] Assertion bits operation */ 1916e3f7320cSCédric Le Goater switch ((cmd[3] >> 4) & 0x3) { 1917e3f7320cSCédric Le Goater case 0: /* Do not change */ 1918e3f7320cSCédric Le Goater break; 1919e3f7320cSCédric Le Goater case 1: /* write given value */ 1920e3f7320cSCédric Le Goater if (cmd_len > 5) { 1921e3f7320cSCédric Le Goater new_assert_states = cmd[5]; 1922e3f7320cSCédric Le Goater change_assert = true; 1923e3f7320cSCédric Le Goater } 1924e3f7320cSCédric Le Goater if (cmd_len > 6) { 1925e3f7320cSCédric Le Goater new_assert_states |= (cmd[6] << 8); 1926e3f7320cSCédric Le Goater } 1927e3f7320cSCédric Le Goater break; 1928e3f7320cSCédric Le Goater 1929e3f7320cSCédric Le Goater case 2: /* mask on */ 1930e3f7320cSCédric Le Goater if (cmd_len > 5) { 1931e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states | cmd[5]); 1932e3f7320cSCédric Le Goater change_assert = true; 1933e3f7320cSCédric Le Goater } 1934e3f7320cSCédric Le Goater if (cmd_len > 6) { 1935e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states | (cmd[6] << 8)); 1936e3f7320cSCédric Le Goater } 1937e3f7320cSCédric Le Goater break; 1938e3f7320cSCédric Le Goater 1939e3f7320cSCédric Le Goater case 3: /* mask off */ 1940e3f7320cSCédric Le Goater if (cmd_len > 5) { 1941e3f7320cSCédric Le Goater new_assert_states = (sens->assert_states & cmd[5]); 1942e3f7320cSCédric Le Goater change_assert = true; 1943e3f7320cSCédric Le Goater } 1944e3f7320cSCédric Le Goater if (cmd_len > 6) { 1945e3f7320cSCédric Le Goater new_assert_states |= (sens->assert_states & (cmd[6] << 8)); 1946e3f7320cSCédric Le Goater } 1947e3f7320cSCédric Le Goater break; 1948e3f7320cSCédric Le Goater } 1949e3f7320cSCédric Le Goater 1950e3f7320cSCédric Le Goater if (change_assert && (new_assert_states == sens->assert_states)) { 1951e3f7320cSCédric Le Goater change_assert = false; 1952e3f7320cSCédric Le Goater } 1953e3f7320cSCédric Le Goater 1954e3f7320cSCédric Le Goater if (cmd_len > 9) { 1955e3f7320cSCédric Le Goater evd1 = cmd[9]; 1956e3f7320cSCédric Le Goater } 1957e3f7320cSCédric Le Goater if (cmd_len > 10) { 1958e3f7320cSCédric Le Goater evd2 = cmd[10]; 1959e3f7320cSCédric Le Goater } 1960e3f7320cSCédric Le Goater if (cmd_len > 11) { 1961e3f7320cSCédric Le Goater evd3 = cmd[11]; 1962e3f7320cSCédric Le Goater } 1963e3f7320cSCédric Le Goater 1964e3f7320cSCédric Le Goater /* [7:6] Event Data Bytes operation */ 1965e3f7320cSCédric Le Goater switch ((cmd[3] >> 6) & 0x3) { 1966e3f7320cSCédric Le Goater case 0: /* 1967e3f7320cSCédric Le Goater * Don’t use Event Data bytes from this command. BMC will 1968e3f7320cSCédric Le Goater * generate it's own Event Data bytes based on its sensor 1969e3f7320cSCédric Le Goater * implementation. 1970e3f7320cSCédric Le Goater */ 1971e3f7320cSCédric Le Goater evd1 = evd2 = evd3 = 0x0; 1972e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_BMC; 1973e3f7320cSCédric Le Goater break; 1974e3f7320cSCédric Le Goater case 1: /* 1975e3f7320cSCédric Le Goater * Write given values to event data bytes including bits 1976e3f7320cSCédric Le Goater * [3:0] Event Data 1. 1977e3f7320cSCédric Le Goater */ 1978e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA; 1979e3f7320cSCédric Le Goater break; 1980e3f7320cSCédric Le Goater case 2: /* 1981e3f7320cSCédric Le Goater * Write given values to event data bytes excluding bits 1982e3f7320cSCédric Le Goater * [3:0] Event Data 1. 1983e3f7320cSCédric Le Goater */ 1984e3f7320cSCédric Le Goater evd1 &= 0xf0; 1985e3f7320cSCédric Le Goater do_gen_event = SENSOR_GEN_EVENT_DATA; 1986e3f7320cSCédric Le Goater break; 1987e3f7320cSCédric Le Goater case 3: 1988e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1989e3f7320cSCédric Le Goater return; 1990e3f7320cSCédric Le Goater } 1991e3f7320cSCédric Le Goater 1992e3f7320cSCédric Le Goater /* 1993e3f7320cSCédric Le Goater * Event Data Bytes operation and parameter are inconsistent. The 1994e3f7320cSCédric Le Goater * Specs are not clear on that topic but generating an error seems 1995e3f7320cSCédric Le Goater * correct. 1996e3f7320cSCédric Le Goater */ 1997e3f7320cSCédric Le Goater if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) { 1998e3f7320cSCédric Le Goater rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); 1999e3f7320cSCédric Le Goater return; 2000e3f7320cSCédric Le Goater } 2001e3f7320cSCédric Le Goater 2002e3f7320cSCédric Le Goater /* commit values */ 2003e3f7320cSCédric Le Goater if (change_reading) { 2004e3f7320cSCédric Le Goater sens->reading = new_reading; 2005e3f7320cSCédric Le Goater } 2006e3f7320cSCédric Le Goater 2007e3f7320cSCédric Le Goater if (change_assert) { 2008e3f7320cSCédric Le Goater sens->assert_states = new_assert_states; 2009e3f7320cSCédric Le Goater } 2010e3f7320cSCédric Le Goater 2011e3f7320cSCédric Le Goater if (change_deassert) { 2012e3f7320cSCédric Le Goater sens->deassert_states = new_deassert_states; 2013e3f7320cSCédric Le Goater } 2014e3f7320cSCédric Le Goater 2015e3f7320cSCédric Le Goater /* TODO: handle threshold sensor */ 2016e3f7320cSCédric Le Goater if (!IPMI_SENSOR_IS_DISCRETE(sens)) { 2017e3f7320cSCédric Le Goater return; 2018e3f7320cSCédric Le Goater } 2019e3f7320cSCédric Le Goater 2020e3f7320cSCédric Le Goater switch (do_gen_event) { 2021e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_DATA: { 2022e3f7320cSCédric Le Goater unsigned int bit = evd1 & 0xf; 2023e3f7320cSCédric Le Goater uint16_t mask = (1 << bit); 2024e3f7320cSCédric Le Goater 2025e3f7320cSCédric Le Goater if (sens->assert_states & mask & sens->assert_enable) { 2026e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 0, evd1, evd2, evd3); 2027e3f7320cSCédric Le Goater } 2028e3f7320cSCédric Le Goater 2029e3f7320cSCédric Le Goater if (sens->deassert_states & mask & sens->deassert_enable) { 2030e3f7320cSCédric Le Goater gen_event(ibs, cmd[2], 1, evd1, evd2, evd3); 2031e3f7320cSCédric Le Goater } 2032e3f7320cSCédric Le Goater break; 2033e3f7320cSCédric Le Goater } 2034e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_BMC: 2035e3f7320cSCédric Le Goater /* 2036e3f7320cSCédric Le Goater * TODO: generate event and event data bytes depending on the 2037e3f7320cSCédric Le Goater * sensor 2038e3f7320cSCédric Le Goater */ 2039e3f7320cSCédric Le Goater break; 2040e3f7320cSCédric Le Goater case SENSOR_GEN_EVENT_NONE: 2041e3f7320cSCédric Le Goater break; 2042e3f7320cSCédric Le Goater } 2043e3f7320cSCédric Le Goater } 2044728710e1SCédric Le Goater 204562a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = { 20464f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities }, 20474f298a4bSCédric Le Goater [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status }, 20484f298a4bSCédric Le Goater [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 }, 20494f298a4bSCédric Le Goater [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause } 20508bfffbccSCorey Minyard }; 20518bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 205262a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(chassis_cmds), 20538bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 20548bfffbccSCorey Minyard }; 20558bfffbccSCorey Minyard 205662a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = { 20579380d2edSCorey Minyard [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 }, 20584f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, 20594f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, 20604f298a4bSCédric Le Goater [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, 20614f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 }, 20624f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 }, 20634f298a4bSCédric Le Goater [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 }, 20644f298a4bSCédric Le Goater [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 }, 2065e3f7320cSCédric Le Goater [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 }, 20668bfffbccSCorey Minyard }; 20678bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 206862a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(sensor_event_cmds), 20698bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 20708bfffbccSCorey Minyard }; 20718bfffbccSCorey Minyard 207262a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = { 20734f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_ID] = { get_device_id }, 20744f298a4bSCédric Le Goater [IPMI_CMD_COLD_RESET] = { cold_reset }, 20754f298a4bSCédric Le Goater [IPMI_CMD_WARM_RESET] = { warm_reset }, 20764f298a4bSCédric Le Goater [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 }, 20774f298a4bSCédric Le Goater [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state }, 20784f298a4bSCédric Le Goater [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid }, 20794f298a4bSCédric Le Goater [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 }, 20804f298a4bSCédric Le Goater [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables }, 20814f298a4bSCédric Le Goater [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 }, 20824f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags }, 20834f298a4bSCédric Le Goater [IPMI_CMD_GET_MSG] = { get_msg }, 20844f298a4bSCédric Le Goater [IPMI_CMD_SEND_MSG] = { send_msg, 3 }, 20854f298a4bSCédric Le Goater [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf }, 20864f298a4bSCédric Le Goater [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, 20874f298a4bSCédric Le Goater [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, 20884f298a4bSCédric Le Goater [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, 20897f9e7af4SNicholas Piggin [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 }, 20908bfffbccSCorey Minyard }; 20918bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 209262a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(app_cmds), 20938bfffbccSCorey Minyard .cmd_handlers = app_cmds 20948bfffbccSCorey Minyard }; 20958bfffbccSCorey Minyard 209662a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = { 2097540c07d3SCédric Le Goater [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 }, 2098540c07d3SCédric Le Goater [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 }, 2099540c07d3SCédric Le Goater [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 }, 21004f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info }, 21014f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep }, 21024f298a4bSCédric Le Goater [IPMI_CMD_GET_SDR] = { get_sdr, 8 }, 21034f298a4bSCédric Le Goater [IPMI_CMD_ADD_SDR] = { add_sdr }, 21044f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 }, 21054f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_INFO] = { get_sel_info }, 21064f298a4bSCédric Le Goater [IPMI_CMD_RESERVE_SEL] = { reserve_sel }, 21074f298a4bSCédric Le Goater [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, 21084f298a4bSCédric Le Goater [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, 21094f298a4bSCédric Le Goater [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, 21107f11cb65SCorey Minyard [IPMI_CMD_GET_SEL_TIME] = { get_sel_time }, 21117f11cb65SCorey Minyard [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 }, 21128bfffbccSCorey Minyard }; 21138bfffbccSCorey Minyard 21148bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 211562a4931dSCédric Le Goater .cmd_nums = ARRAY_SIZE(storage_cmds), 21168bfffbccSCorey Minyard .cmd_handlers = storage_cmds 21178bfffbccSCorey Minyard }; 21188bfffbccSCorey Minyard 21198bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 21208bfffbccSCorey Minyard { 2121ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 2122ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 2123ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 2124ed8da05cSCédric Le Goater ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 21258bfffbccSCorey Minyard } 21268bfffbccSCorey Minyard 21275167560bSCédric Le Goater static uint8_t init_sdrs[] = { 21288bfffbccSCorey Minyard /* Watchdog device */ 21298bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 21308bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 21318bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21328bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 21338bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 21348bfffbccSCorey Minyard }; 21358bfffbccSCorey Minyard 21364fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs) 21374fa9f08eSCédric Le Goater { 21384fa9f08eSCédric Le Goater unsigned int i; 21394fa9f08eSCédric Le Goater int len; 21405167560bSCédric Le Goater size_t sdrs_size; 21415167560bSCédric Le Goater uint8_t *sdrs; 214252fc01d9SCédric Le Goater 21435167560bSCédric Le Goater sdrs_size = sizeof(init_sdrs); 21445167560bSCédric Le Goater sdrs = init_sdrs; 21458c6fd7f3SCédric Le Goater if (ibs->sdr_filename && 21468c6fd7f3SCédric Le Goater !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size, 21478c6fd7f3SCédric Le Goater NULL)) { 21488c6fd7f3SCédric Le Goater error_report("failed to load sdr file '%s'", ibs->sdr_filename); 21498c6fd7f3SCédric Le Goater sdrs_size = sizeof(init_sdrs); 21508c6fd7f3SCédric Le Goater sdrs = init_sdrs; 21518c6fd7f3SCédric Le Goater } 21525167560bSCédric Le Goater 21535167560bSCédric Le Goater for (i = 0; i < sdrs_size; i += len) { 215452fc01d9SCédric Le Goater struct ipmi_sdr_header *sdrh; 215552fc01d9SCédric Le Goater 21565167560bSCédric Le Goater if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) { 21574fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 21588c6fd7f3SCédric Le Goater break; 21594fa9f08eSCédric Le Goater } 21605167560bSCédric Le Goater sdrh = (struct ipmi_sdr_header *) &sdrs[i]; 21614fa9f08eSCédric Le Goater len = ipmi_sdr_length(sdrh); 21625167560bSCédric Le Goater if (i + len > sdrs_size) { 21634fa9f08eSCédric Le Goater error_report("Problem with recid 0x%4.4x", i); 21648c6fd7f3SCédric Le Goater break; 21654fa9f08eSCédric Le Goater } 21664fa9f08eSCédric Le Goater sdr_add_entry(ibs, sdrh, len, NULL); 21674fa9f08eSCédric Le Goater } 21688c6fd7f3SCédric Le Goater 21698c6fd7f3SCédric Le Goater if (sdrs != init_sdrs) { 21708c6fd7f3SCédric Le Goater g_free(sdrs); 21718c6fd7f3SCédric Le Goater } 21724fa9f08eSCédric Le Goater } 21734fa9f08eSCédric Le Goater 2174bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = { 2175bd66bcfcSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 2176bd66bcfcSCorey Minyard .version_id = 1, 2177bd66bcfcSCorey Minyard .minimum_version_id = 1, 217809c6ac6dSRichard Henderson .fields = (const VMStateField[]) { 2179bd66bcfcSCorey Minyard VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim), 2180bd66bcfcSCorey Minyard VMSTATE_UINT8(msg_flags, IPMIBmcSim), 2181bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim), 2182bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_use, IPMIBmcSim), 2183bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_action, IPMIBmcSim), 2184bd66bcfcSCorey Minyard VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim), 21859e744990SJinhua Cao VMSTATE_UINT8(watchdog_expired, IPMIBmcSim), 2186bd66bcfcSCorey Minyard VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim), 2187bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_running, IPMIBmcSim), 2188bd66bcfcSCorey Minyard VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim), 2189bd66bcfcSCorey Minyard VMSTATE_INT64(watchdog_expiry, IPMIBmcSim), 2190bd66bcfcSCorey Minyard VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16), 2191bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim), 2192bd66bcfcSCorey Minyard VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim), 2193bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim), 2194bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim), 2195bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states, 2196bd66bcfcSCorey Minyard IPMIBmcSim), 2197bd66bcfcSCorey Minyard VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim), 2198bd66bcfcSCorey Minyard VMSTATE_END_OF_LIST() 2199bd66bcfcSCorey Minyard } 2200bd66bcfcSCorey Minyard }; 2201bd66bcfcSCorey Minyard 2202540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru) 2203540c07d3SCédric Le Goater { 2204540c07d3SCédric Le Goater int fsize; 2205540c07d3SCédric Le Goater int size = 0; 2206540c07d3SCédric Le Goater 2207540c07d3SCédric Le Goater if (!fru->filename) { 2208540c07d3SCédric Le Goater goto out; 2209540c07d3SCédric Le Goater } 2210540c07d3SCédric Le Goater 2211540c07d3SCédric Le Goater fsize = get_image_size(fru->filename); 2212540c07d3SCédric Le Goater if (fsize > 0) { 2213540c07d3SCédric Le Goater size = QEMU_ALIGN_UP(fsize, fru->areasize); 2214540c07d3SCédric Le Goater fru->data = g_malloc0(size); 2215540c07d3SCédric Le Goater if (load_image_size(fru->filename, fru->data, fsize) != fsize) { 2216540c07d3SCédric Le Goater error_report("Could not load file '%s'", fru->filename); 2217540c07d3SCédric Le Goater g_free(fru->data); 2218540c07d3SCédric Le Goater fru->data = NULL; 2219540c07d3SCédric Le Goater } 2220540c07d3SCédric Le Goater } 2221540c07d3SCédric Le Goater 2222540c07d3SCédric Le Goater out: 2223540c07d3SCédric Le Goater if (!fru->data) { 2224540c07d3SCédric Le Goater /* give one default FRU */ 2225540c07d3SCédric Le Goater size = fru->areasize; 2226540c07d3SCédric Le Goater fru->data = g_malloc0(size); 2227540c07d3SCédric Le Goater } 2228540c07d3SCédric Le Goater 2229540c07d3SCédric Le Goater fru->nentries = size / fru->areasize; 2230540c07d3SCédric Le Goater } 2231540c07d3SCédric Le Goater 22320bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp) 22338bfffbccSCorey Minyard { 22340bc6001fSCédric Le Goater IPMIBmc *b = IPMI_BMC(dev); 22358bfffbccSCorey Minyard unsigned int i; 22368bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 22378bfffbccSCorey Minyard 22388bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 22398bfffbccSCorey Minyard 22408bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 22418bfffbccSCorey Minyard ibs->device_id = 0x20; 22428bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 2243b7088392SCédric Le Goater ibs->restart_cause = 0; 22448bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 22458bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 22468bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 22478bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 22488bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 22498bfffbccSCorey Minyard } 22508bfffbccSCorey Minyard 22514fa9f08eSCédric Le Goater ipmi_sdr_init(ibs); 22528bfffbccSCorey Minyard 2253540c07d3SCédric Le Goater ipmi_fru_init(&ibs->fru); 2254540c07d3SCédric Le Goater 225552ba4d50SCédric Le Goater ibs->acpi_power_state[0] = 0; 225652ba4d50SCédric Le Goater ibs->acpi_power_state[1] = 0; 225752ba4d50SCédric Le Goater 22588bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 22598bfffbccSCorey Minyard register_cmds(ibs); 22608bfffbccSCorey Minyard 22618bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 22628bfffbccSCorey Minyard } 22638bfffbccSCorey Minyard 22642acf1403SRichard Henderson static const Property ipmi_sim_properties[] = { 2265540c07d3SCédric Le Goater DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024), 2266540c07d3SCédric Le Goater DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename), 22678c6fd7f3SCédric Le Goater DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename), 226820b23364SCorey Minyard DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20), 226920b23364SCorey Minyard DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02), 227020b23364SCorey Minyard DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0), 227120b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0), 227220b23364SCorey Minyard DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0), 227320b23364SCorey Minyard DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0), 227420b23364SCorey Minyard DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0), 22757b0cd78bSCorey Minyard DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid), 22768c6fd7f3SCédric Le Goater }; 22778c6fd7f3SCédric Le Goater 22788bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 22798bfffbccSCorey Minyard { 22800bc6001fSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(oc); 22818bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 22828bfffbccSCorey Minyard 228366abfddbSCorey Minyard dc->hotpluggable = false; 22840bc6001fSCédric Le Goater dc->realize = ipmi_sim_realize; 2285d11d904cSCorey Minyard dc->vmsd = &vmstate_ipmi_sim; 22864f67d30bSMarc-André Lureau device_class_set_props(dc, ipmi_sim_properties); 22878bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 22888bfffbccSCorey Minyard } 22898bfffbccSCorey Minyard 22908bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 22918bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 22928bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 22938bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 22948bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 22958bfffbccSCorey Minyard }; 22968bfffbccSCorey Minyard 22978bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 22988bfffbccSCorey Minyard { 22998bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 23008bfffbccSCorey Minyard } 23018bfffbccSCorey Minyard 23028bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 2303