xref: /qemu/hw/ipmi/ipmi_bmc_sim.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 
238dacb3e70SNicholas Piggin #define IPMI_BMC_GLOBAL_ENABLES_SUPPORTED 0x0f
2398bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT    0
2408bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT       1
2418bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT        2
2428bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT            3
2438bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \
2448bfffbccSCorey Minyard                                  (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT))
2458bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \
2468bfffbccSCorey Minyard                                         (1 << IPMI_BMC_EVBUF_FULL_INT_BIT))
2478bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \
2488bfffbccSCorey Minyard                                        (1 << IPMI_BMC_EVENT_LOG_BIT))
2498bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \
2508bfffbccSCorey Minyard                                            (1 << IPMI_BMC_EVENT_MSG_BUF_BIT))
2518bfffbccSCorey Minyard 
2528bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7
2538bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77
2548bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7)
2558bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1)
2568bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1)
2578bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7)
2588bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE               0
2598bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI                1
2608bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI                2
2618bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT            3
2628bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7)
2638bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE            0
2648bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET           1
2658bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN      2
2668bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE     3
2678bfffbccSCorey Minyard 
268a580d820SCédric Le Goater #define RSP_BUFFER_INITIALIZER { }
2698bfffbccSCorey Minyard 
rsp_buffer_pushmore(RspBuffer * rsp,uint8_t * bytes,unsigned int n)270a580d820SCédric Le Goater static inline void rsp_buffer_pushmore(RspBuffer *rsp, uint8_t *bytes,
271a580d820SCédric Le Goater                                        unsigned int n)
272a580d820SCédric Le Goater {
273a580d820SCédric Le Goater     if (rsp->len + n >= sizeof(rsp->buffer)) {
2746acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
275a580d820SCédric Le Goater         return;
276a580d820SCédric Le Goater     }
277a580d820SCédric Le Goater 
278a580d820SCédric Le Goater     memcpy(&rsp->buffer[rsp->len], bytes, n);
279a580d820SCédric Le Goater     rsp->len += n;
280a580d820SCédric Le Goater }
2818bfffbccSCorey Minyard 
2828bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs);
2838bfffbccSCorey Minyard 
ipmi_gettime(struct ipmi_time * time)2848bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time)
2858bfffbccSCorey Minyard {
2868bfffbccSCorey Minyard     int64_t stime;
2878bfffbccSCorey Minyard 
2888bfffbccSCorey Minyard     stime = qemu_clock_get_ns(QEMU_CLOCK_HOST);
2898bfffbccSCorey Minyard     time->tv_sec = stime / 1000000000LL;
2908bfffbccSCorey Minyard     time->tv_nsec = stime % 1000000000LL;
2918bfffbccSCorey Minyard }
2928bfffbccSCorey Minyard 
ipmi_getmonotime(void)2938bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void)
2948bfffbccSCorey Minyard {
2958bfffbccSCorey Minyard     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2968bfffbccSCorey Minyard }
2978bfffbccSCorey Minyard 
ipmi_timeout(void * opaque)2988bfffbccSCorey Minyard static void ipmi_timeout(void *opaque)
2998bfffbccSCorey Minyard {
3008bfffbccSCorey Minyard     IPMIBmcSim *ibs = opaque;
3018bfffbccSCorey Minyard 
3028bfffbccSCorey Minyard     ipmi_sim_handle_timeout(ibs);
3038bfffbccSCorey Minyard }
3048bfffbccSCorey Minyard 
set_timestamp(IPMIBmcSim * ibs,uint8_t * ts)3058bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts)
3068bfffbccSCorey Minyard {
3078bfffbccSCorey Minyard     unsigned int val;
3088bfffbccSCorey Minyard     struct ipmi_time now;
3098bfffbccSCorey Minyard 
3108bfffbccSCorey Minyard     ipmi_gettime(&now);
3118bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
3128bfffbccSCorey Minyard     ts[0] = val & 0xff;
3138bfffbccSCorey Minyard     ts[1] = (val >> 8) & 0xff;
3148bfffbccSCorey Minyard     ts[2] = (val >> 16) & 0xff;
3158bfffbccSCorey Minyard     ts[3] = (val >> 24) & 0xff;
3168bfffbccSCorey Minyard }
3178bfffbccSCorey Minyard 
sdr_inc_reservation(IPMISdr * sdr)3188bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr)
3198bfffbccSCorey Minyard {
3208bfffbccSCorey Minyard     sdr->reservation++;
3218bfffbccSCorey Minyard     if (sdr->reservation == 0) {
3228bfffbccSCorey Minyard         sdr->reservation = 1;
3238bfffbccSCorey Minyard     }
3248bfffbccSCorey Minyard }
3258bfffbccSCorey Minyard 
sdr_add_entry(IPMIBmcSim * ibs,const struct ipmi_sdr_header * sdrh_entry,unsigned int len,uint16_t * recid)326a2295f0aSCédric Le Goater static int sdr_add_entry(IPMIBmcSim *ibs,
327a2295f0aSCédric Le Goater                          const struct ipmi_sdr_header *sdrh_entry,
3288bfffbccSCorey Minyard                          unsigned int len, uint16_t *recid)
3298bfffbccSCorey Minyard {
330a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh =
331a2295f0aSCédric Le Goater         (struct ipmi_sdr_header *) &ibs->sdr.sdr[ibs->sdr.next_free];
332a2295f0aSCédric Le Goater 
333a2295f0aSCédric Le Goater     if ((len < IPMI_SDR_HEADER_SIZE) || (len > 255)) {
3348bfffbccSCorey Minyard         return 1;
3358bfffbccSCorey Minyard     }
3368bfffbccSCorey Minyard 
337a2295f0aSCédric Le Goater     if (ipmi_sdr_length(sdrh_entry) != len) {
3388bfffbccSCorey Minyard         return 1;
3398bfffbccSCorey Minyard     }
3408bfffbccSCorey Minyard 
3418bfffbccSCorey Minyard     if (ibs->sdr.next_free + len > MAX_SDR_SIZE) {
3428bfffbccSCorey Minyard         ibs->sdr.overflow = 1;
3438bfffbccSCorey Minyard         return 1;
3448bfffbccSCorey Minyard     }
3458bfffbccSCorey Minyard 
346a2295f0aSCédric Le Goater     memcpy(sdrh, sdrh_entry, len);
347a2295f0aSCédric Le Goater     sdrh->rec_id[0] = ibs->sdr.next_rec_id & 0xff;
348a2295f0aSCédric Le Goater     sdrh->rec_id[1] = (ibs->sdr.next_rec_id >> 8) & 0xff;
349a2295f0aSCédric Le Goater     sdrh->sdr_version = 0x51; /* Conform to IPMI 1.5 spec */
3508bfffbccSCorey Minyard 
3518bfffbccSCorey Minyard     if (recid) {
3528bfffbccSCorey Minyard         *recid = ibs->sdr.next_rec_id;
3538bfffbccSCorey Minyard     }
3548bfffbccSCorey Minyard     ibs->sdr.next_rec_id++;
3558bfffbccSCorey Minyard     set_timestamp(ibs, ibs->sdr.last_addition);
3568bfffbccSCorey Minyard     ibs->sdr.next_free += len;
3578bfffbccSCorey Minyard     sdr_inc_reservation(&ibs->sdr);
3588bfffbccSCorey Minyard     return 0;
3598bfffbccSCorey Minyard }
3608bfffbccSCorey Minyard 
sdr_find_entry(IPMISdr * sdr,uint16_t recid,unsigned int * retpos,uint16_t * nextrec)3618bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid,
3628bfffbccSCorey Minyard                           unsigned int *retpos, uint16_t *nextrec)
3638bfffbccSCorey Minyard {
3648bfffbccSCorey Minyard     unsigned int pos = *retpos;
3658bfffbccSCorey Minyard 
3668bfffbccSCorey Minyard     while (pos < sdr->next_free) {
367a2295f0aSCédric Le Goater         struct ipmi_sdr_header *sdrh =
368a2295f0aSCédric Le Goater             (struct ipmi_sdr_header *) &sdr->sdr[pos];
369a2295f0aSCédric Le Goater         uint16_t trec = ipmi_sdr_recid(sdrh);
370a2295f0aSCédric Le Goater         unsigned int nextpos = pos + ipmi_sdr_length(sdrh);
3718bfffbccSCorey Minyard 
3728bfffbccSCorey Minyard         if (trec == recid) {
3738bfffbccSCorey Minyard             if (nextrec) {
3748bfffbccSCorey Minyard                 if (nextpos >= sdr->next_free) {
3758bfffbccSCorey Minyard                     *nextrec = 0xffff;
3768bfffbccSCorey Minyard                 } else {
3778bfffbccSCorey Minyard                     *nextrec = (sdr->sdr[nextpos] |
3788bfffbccSCorey Minyard                                 (sdr->sdr[nextpos + 1] << 8));
3798bfffbccSCorey Minyard                 }
3808bfffbccSCorey Minyard             }
3818bfffbccSCorey Minyard             *retpos = pos;
3828bfffbccSCorey Minyard             return 0;
3838bfffbccSCorey Minyard         }
3848bfffbccSCorey Minyard         pos = nextpos;
3858bfffbccSCorey Minyard     }
3868bfffbccSCorey Minyard     return 1;
3878bfffbccSCorey Minyard }
3888bfffbccSCorey Minyard 
ipmi_bmc_sdr_find(IPMIBmc * b,uint16_t recid,const struct ipmi_sdr_compact ** sdr,uint16_t * nextrec)3897fabcdb9SCédric Le Goater int ipmi_bmc_sdr_find(IPMIBmc *b, uint16_t recid,
3907fabcdb9SCédric Le Goater                       const struct ipmi_sdr_compact **sdr, uint16_t *nextrec)
3917fabcdb9SCédric Le Goater 
3927fabcdb9SCédric Le Goater {
3937fabcdb9SCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
3947fabcdb9SCédric Le Goater     unsigned int pos;
3957fabcdb9SCédric Le Goater 
3967fabcdb9SCédric Le Goater     pos = 0;
3977fabcdb9SCédric Le Goater     if (sdr_find_entry(&ibs->sdr, recid, &pos, nextrec)) {
3987fabcdb9SCédric Le Goater         return -1;
3997fabcdb9SCédric Le Goater     }
4007fabcdb9SCédric Le Goater 
4017fabcdb9SCédric Le Goater     *sdr = (const struct ipmi_sdr_compact *) &ibs->sdr.sdr[pos];
4027fabcdb9SCédric Le Goater     return 0;
4037fabcdb9SCédric Le Goater }
4047fabcdb9SCédric Le Goater 
sel_inc_reservation(IPMISel * sel)4058bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel)
4068bfffbccSCorey Minyard {
4078bfffbccSCorey Minyard     sel->reservation++;
4088bfffbccSCorey Minyard     if (sel->reservation == 0) {
4098bfffbccSCorey Minyard         sel->reservation = 1;
4108bfffbccSCorey Minyard     }
4118bfffbccSCorey Minyard }
4128bfffbccSCorey Minyard 
4138bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */
sel_add_event(IPMIBmcSim * ibs,uint8_t * event)4148bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event)
4158bfffbccSCorey Minyard {
4169f7d1d92SCorey Minyard     uint8_t ts[4];
4179f7d1d92SCorey Minyard 
4188bfffbccSCorey Minyard     event[0] = 0xff;
4198bfffbccSCorey Minyard     event[1] = 0xff;
4209f7d1d92SCorey Minyard     set_timestamp(ibs, ts);
4219f7d1d92SCorey Minyard     if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */
4229f7d1d92SCorey Minyard         memcpy(event + 3, ts, 4);
4239f7d1d92SCorey Minyard     }
4248bfffbccSCorey Minyard     if (ibs->sel.next_free == MAX_SEL_SIZE) {
4258bfffbccSCorey Minyard         ibs->sel.overflow = 1;
4268bfffbccSCorey Minyard         return 1;
4278bfffbccSCorey Minyard     }
4288bfffbccSCorey Minyard     event[0] = ibs->sel.next_free & 0xff;
4298bfffbccSCorey Minyard     event[1] = (ibs->sel.next_free >> 8) & 0xff;
4309f7d1d92SCorey Minyard     memcpy(ibs->sel.last_addition, ts, 4);
4318bfffbccSCorey Minyard     memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16);
4328bfffbccSCorey Minyard     ibs->sel.next_free++;
4338bfffbccSCorey Minyard     sel_inc_reservation(&ibs->sel);
4348bfffbccSCorey Minyard     return 0;
4358bfffbccSCorey Minyard }
4368bfffbccSCorey Minyard 
attn_set(IPMIBmcSim * ibs)4378bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs)
4388bfffbccSCorey Minyard {
4398bfffbccSCorey Minyard     return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)
4408bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)
4418bfffbccSCorey Minyard         || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs);
4428bfffbccSCorey Minyard }
4438bfffbccSCorey Minyard 
attn_irq_enabled(IPMIBmcSim * ibs)4448bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs)
4458bfffbccSCorey Minyard {
4468bc8af69SCorey Minyard     return (IPMI_BMC_MSG_INTS_ON(ibs) &&
4478bc8af69SCorey Minyard             (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) ||
4488bc8af69SCorey Minyard              IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs)))
4498bfffbccSCorey Minyard         || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) &&
4508bfffbccSCorey Minyard             IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs));
4518bfffbccSCorey Minyard }
4528bfffbccSCorey Minyard 
ipmi_bmc_gen_event(IPMIBmc * b,uint8_t * evt,bool log)453cd60d85eSCédric Le Goater void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log)
454cd60d85eSCédric Le Goater {
455cd60d85eSCédric Le Goater     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
456cd60d85eSCédric Le Goater     IPMIInterface *s = ibs->parent.intf;
457cd60d85eSCédric Le Goater     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
458cd60d85eSCédric Le Goater 
459cd60d85eSCédric Le Goater     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
460cd60d85eSCédric Le Goater         return;
461cd60d85eSCédric Le Goater     }
462cd60d85eSCédric Le Goater 
463cd60d85eSCédric Le Goater     if (log && IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
464cd60d85eSCédric Le Goater         sel_add_event(ibs, evt);
465cd60d85eSCédric Le Goater     }
466cd60d85eSCédric Le Goater 
467cd60d85eSCédric Le Goater     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
468abb55b1aSMarkus Armbruster         return;
469cd60d85eSCédric Le Goater     }
470cd60d85eSCédric Le Goater 
471cd60d85eSCédric Le Goater     memcpy(ibs->evtbuf, evt, 16);
472cd60d85eSCédric Le Goater     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
473cd60d85eSCédric Le Goater     k->set_atn(s, 1, attn_irq_enabled(ibs));
474cd60d85eSCédric Le Goater }
gen_event(IPMIBmcSim * ibs,unsigned int sens_num,uint8_t deassert,uint8_t evd1,uint8_t evd2,uint8_t evd3)4758bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert,
4768bfffbccSCorey Minyard                       uint8_t evd1, uint8_t evd2, uint8_t evd3)
4778bfffbccSCorey Minyard {
4788bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
4798bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
4808bfffbccSCorey Minyard     uint8_t evt[16];
4818bfffbccSCorey Minyard     IPMISensor *sens = ibs->sensors + sens_num;
4828bfffbccSCorey Minyard 
4838bfffbccSCorey Minyard     if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) {
4848bfffbccSCorey Minyard         return;
4858bfffbccSCorey Minyard     }
4868bfffbccSCorey Minyard     if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) {
4878bfffbccSCorey Minyard         return;
4888bfffbccSCorey Minyard     }
4898bfffbccSCorey Minyard 
4908bfffbccSCorey Minyard     evt[2] = 0x2; /* System event record */
4918bfffbccSCorey Minyard     evt[7] = ibs->parent.slave_addr;
4928bfffbccSCorey Minyard     evt[8] = 0;
4938bfffbccSCorey Minyard     evt[9] = 0x04; /* Format version */
4948bfffbccSCorey Minyard     evt[10] = sens->sensor_type;
4958bfffbccSCorey Minyard     evt[11] = sens_num;
4968bfffbccSCorey Minyard     evt[12] = sens->evt_reading_type_code | (!!deassert << 7);
4978bfffbccSCorey Minyard     evt[13] = evd1;
4988bfffbccSCorey Minyard     evt[14] = evd2;
4998bfffbccSCorey Minyard     evt[15] = evd3;
5008bfffbccSCorey Minyard 
5018bfffbccSCorey Minyard     if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) {
5028bfffbccSCorey Minyard         sel_add_event(ibs, evt);
5038bfffbccSCorey Minyard     }
5048bfffbccSCorey Minyard 
5058bfffbccSCorey Minyard     if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) {
506d13ada5dSCédric Le Goater         return;
5078bfffbccSCorey Minyard     }
5088bfffbccSCorey Minyard 
5098bfffbccSCorey Minyard     memcpy(ibs->evtbuf, evt, 16);
5108bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
5118bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
5128bfffbccSCorey Minyard }
5138bfffbccSCorey Minyard 
sensor_set_discrete_bit(IPMIBmcSim * ibs,unsigned int sensor,unsigned int bit,unsigned int val,uint8_t evd1,uint8_t evd2,uint8_t evd3,bool do_log)5148bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor,
5158bfffbccSCorey Minyard                                     unsigned int bit, unsigned int val,
516d9494ef9SNicholas Piggin                                     uint8_t evd1, uint8_t evd2, uint8_t evd3,
517d9494ef9SNicholas Piggin                                     bool do_log)
5188bfffbccSCorey Minyard {
5198bfffbccSCorey Minyard     IPMISensor *sens;
5208bfffbccSCorey Minyard     uint16_t mask;
5218bfffbccSCorey Minyard 
5228bfffbccSCorey Minyard     if (sensor >= MAX_SENSORS) {
5238bfffbccSCorey Minyard         return;
5248bfffbccSCorey Minyard     }
5258bfffbccSCorey Minyard     if (bit >= 16) {
5268bfffbccSCorey Minyard         return;
5278bfffbccSCorey Minyard     }
5288bfffbccSCorey Minyard 
5298bfffbccSCorey Minyard     mask = (1 << bit);
5308bfffbccSCorey Minyard     sens = ibs->sensors + sensor;
5318bfffbccSCorey Minyard     if (val) {
5328bfffbccSCorey Minyard         sens->states |= mask & sens->states_suppt;
5338bfffbccSCorey Minyard         if (sens->assert_states & mask) {
5348bfffbccSCorey Minyard             return; /* Already asserted */
5358bfffbccSCorey Minyard         }
5368bfffbccSCorey Minyard         sens->assert_states |= mask & sens->assert_suppt;
537d9494ef9SNicholas Piggin         if (do_log && (sens->assert_enable & mask & sens->assert_states)) {
5388bfffbccSCorey Minyard             /* Send an event on assert */
5398bfffbccSCorey Minyard             gen_event(ibs, sensor, 0, evd1, evd2, evd3);
5408bfffbccSCorey Minyard         }
5418bfffbccSCorey Minyard     } else {
5428bfffbccSCorey Minyard         sens->states &= ~(mask & sens->states_suppt);
5438bfffbccSCorey Minyard         if (sens->deassert_states & mask) {
5448bfffbccSCorey Minyard             return; /* Already deasserted */
5458bfffbccSCorey Minyard         }
5468bfffbccSCorey Minyard         sens->deassert_states |= mask & sens->deassert_suppt;
547d9494ef9SNicholas Piggin         if (do_log && (sens->deassert_enable & mask & sens->deassert_states)) {
5488bfffbccSCorey Minyard             /* Send an event on deassert */
5498bfffbccSCorey Minyard             gen_event(ibs, sensor, 1, evd1, evd2, evd3);
5508bfffbccSCorey Minyard         }
5518bfffbccSCorey Minyard     }
5528bfffbccSCorey Minyard }
5538bfffbccSCorey Minyard 
ipmi_init_sensors_from_sdrs(IPMIBmcSim * s)5548bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s)
5558bfffbccSCorey Minyard {
5568bfffbccSCorey Minyard     unsigned int i, pos;
5578bfffbccSCorey Minyard     IPMISensor *sens;
5588bfffbccSCorey Minyard 
5598bfffbccSCorey Minyard     for (i = 0; i < MAX_SENSORS; i++) {
5608bfffbccSCorey Minyard         memset(s->sensors + i, 0, sizeof(*sens));
5618bfffbccSCorey Minyard     }
5628bfffbccSCorey Minyard 
5638bfffbccSCorey Minyard     pos = 0;
5648bfffbccSCorey Minyard     for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) {
565a2295f0aSCédric Le Goater         struct ipmi_sdr_compact *sdr =
566a2295f0aSCédric Le Goater             (struct ipmi_sdr_compact *) &s->sdr.sdr[pos];
567a2295f0aSCédric Le Goater         unsigned int len = sdr->header.rec_length;
5688bfffbccSCorey Minyard 
5698bfffbccSCorey Minyard         if (len < 20) {
5708bfffbccSCorey Minyard             continue;
5718bfffbccSCorey Minyard         }
572a2295f0aSCédric Le Goater         if (sdr->header.rec_type != IPMI_SDR_COMPACT_TYPE) {
5738bfffbccSCorey Minyard             continue; /* Not a sensor SDR we set from */
5748bfffbccSCorey Minyard         }
5758bfffbccSCorey Minyard 
57673d60fa5SCédric Le Goater         if (sdr->sensor_owner_number >= MAX_SENSORS) {
5778bfffbccSCorey Minyard             continue;
5788bfffbccSCorey Minyard         }
579a2295f0aSCédric Le Goater         sens = s->sensors + sdr->sensor_owner_number;
5808bfffbccSCorey Minyard 
5818bfffbccSCorey Minyard         IPMI_SENSOR_SET_PRESENT(sens, 1);
582a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_SCAN_ON(sens, (sdr->sensor_init >> 6) & 1);
583a2295f0aSCédric Le Goater         IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr->sensor_init >> 5) & 1);
584a2295f0aSCédric Le Goater         sens->assert_suppt = sdr->assert_mask[0] | (sdr->assert_mask[1] << 8);
585a2295f0aSCédric Le Goater         sens->deassert_suppt =
586a2295f0aSCédric Le Goater             sdr->deassert_mask[0] | (sdr->deassert_mask[1] << 8);
587a2295f0aSCédric Le Goater         sens->states_suppt =
588a2295f0aSCédric Le Goater             sdr->discrete_mask[0] | (sdr->discrete_mask[1] << 8);
589a2295f0aSCédric Le Goater         sens->sensor_type = sdr->sensor_type;
590a2295f0aSCédric Le Goater         sens->evt_reading_type_code = sdr->reading_type & 0x7f;
5918bfffbccSCorey Minyard 
5928bfffbccSCorey Minyard         /* Enable all the events that are supported. */
5938bfffbccSCorey Minyard         sens->assert_enable = sens->assert_suppt;
5948bfffbccSCorey Minyard         sens->deassert_enable = sens->deassert_suppt;
5958bfffbccSCorey Minyard     }
5968bfffbccSCorey Minyard }
5978bfffbccSCorey Minyard 
ipmi_sim_register_netfn(IPMIBmcSim * s,unsigned int netfn,const IPMINetfn * netfnd)598ed8da05cSCédric Le Goater int ipmi_sim_register_netfn(IPMIBmcSim *s, unsigned int netfn,
5998bfffbccSCorey Minyard                         const IPMINetfn *netfnd)
6008bfffbccSCorey Minyard {
60193a53646SCorey Minyard     if ((netfn & 1) || (netfn >= MAX_NETFNS) || (s->netfns[netfn / 2])) {
6028bfffbccSCorey Minyard         return -1;
6038bfffbccSCorey Minyard     }
6048bfffbccSCorey Minyard     s->netfns[netfn / 2] = netfnd;
6058bfffbccSCorey Minyard     return 0;
6068bfffbccSCorey Minyard }
6078bfffbccSCorey Minyard 
ipmi_get_handler(IPMIBmcSim * ibs,unsigned int netfn,unsigned int cmd)6084f298a4bSCédric Le Goater static const IPMICmdHandler *ipmi_get_handler(IPMIBmcSim *ibs,
6094f298a4bSCédric Le Goater                                               unsigned int netfn,
6104f298a4bSCédric Le Goater                                               unsigned int cmd)
6114f298a4bSCédric Le Goater {
6124f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
6134f298a4bSCédric Le Goater 
6144f298a4bSCédric Le Goater     if (netfn & 1 || netfn >= MAX_NETFNS || !ibs->netfns[netfn / 2]) {
6154f298a4bSCédric Le Goater         return NULL;
6164f298a4bSCédric Le Goater     }
6174f298a4bSCédric Le Goater 
6184f298a4bSCédric Le Goater     if (cmd >= ibs->netfns[netfn / 2]->cmd_nums) {
6194f298a4bSCédric Le Goater         return NULL;
6204f298a4bSCédric Le Goater     }
6214f298a4bSCédric Le Goater 
6224f298a4bSCédric Le Goater     hdl = &ibs->netfns[netfn / 2]->cmd_handlers[cmd];
6234f298a4bSCédric Le Goater     if (!hdl->cmd_handler) {
6244f298a4bSCédric Le Goater         return NULL;
6254f298a4bSCédric Le Goater     }
6264f298a4bSCédric Le Goater 
6274f298a4bSCédric Le Goater     return hdl;
6284f298a4bSCédric Le Goater }
6294f298a4bSCédric Le Goater 
next_timeout(IPMIBmcSim * ibs)6308bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs)
6318bfffbccSCorey Minyard {
6328bfffbccSCorey Minyard     int64_t next;
6338bfffbccSCorey Minyard     if (ibs->watchdog_running) {
6348bfffbccSCorey Minyard         next = ibs->watchdog_expiry;
6358bfffbccSCorey Minyard     } else {
6368bfffbccSCorey Minyard         /* Wait a minute */
6378bfffbccSCorey Minyard         next = ipmi_getmonotime() + 60 * 1000000000LL;
6388bfffbccSCorey Minyard     }
6398bfffbccSCorey Minyard     timer_mod_ns(ibs->timer, next);
6408bfffbccSCorey Minyard }
6418bfffbccSCorey Minyard 
ipmi_sim_handle_command(IPMIBmc * b,uint8_t * cmd,unsigned int cmd_len,unsigned int max_cmd_len,uint8_t msg_id)6428bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b,
6438bfffbccSCorey Minyard                                     uint8_t *cmd, unsigned int cmd_len,
6448bfffbccSCorey Minyard                                     unsigned int max_cmd_len,
6458bfffbccSCorey Minyard                                     uint8_t msg_id)
6468bfffbccSCorey Minyard {
6478bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
6488bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
6498bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
6504f298a4bSCédric Le Goater     const IPMICmdHandler *hdl;
651a580d820SCédric Le Goater     RspBuffer rsp = RSP_BUFFER_INITIALIZER;
6528bfffbccSCorey Minyard 
6538bfffbccSCorey Minyard     /* Set up the response, set the low bit of NETFN. */
6548bfffbccSCorey Minyard     /* Note that max_rsp_len must be at least 3 */
655a580d820SCédric Le Goater     if (sizeof(rsp.buffer) < 3) {
6566acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
657d13ada5dSCédric Le Goater         goto out;
658d13ada5dSCédric Le Goater     }
659d13ada5dSCédric Le Goater 
660a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[0] | 0x04);
661a580d820SCédric Le Goater     rsp_buffer_push(&rsp, cmd[1]);
662a580d820SCédric Le Goater     rsp_buffer_push(&rsp, 0); /* Assume success */
6638bfffbccSCorey Minyard 
6648bfffbccSCorey Minyard     /* If it's too short or it was truncated, return an error. */
6658bfffbccSCorey Minyard     if (cmd_len < 2) {
6666acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6678bfffbccSCorey Minyard         goto out;
6688bfffbccSCorey Minyard     }
6698bfffbccSCorey Minyard     if (cmd_len > max_cmd_len) {
6706acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_TRUNCATED);
6718bfffbccSCorey Minyard         goto out;
6728bfffbccSCorey Minyard     }
6738bfffbccSCorey Minyard 
6748bfffbccSCorey Minyard     if ((cmd[0] & 0x03) != 0) {
6758bfffbccSCorey Minyard         /* Only have stuff on LUN 0 */
6766acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_COMMAND_INVALID_FOR_LUN);
6778bfffbccSCorey Minyard         goto out;
6788bfffbccSCorey Minyard     }
6798bfffbccSCorey Minyard 
6804f298a4bSCédric Le Goater     hdl = ipmi_get_handler(ibs, cmd[0] >> 2, cmd[1]);
6814f298a4bSCédric Le Goater     if (!hdl) {
6826acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_INVALID_CMD);
6838bfffbccSCorey Minyard         goto out;
6848bfffbccSCorey Minyard     }
6858bfffbccSCorey Minyard 
6864f298a4bSCédric Le Goater     if (cmd_len < hdl->cmd_len_min) {
6876acb971aSCédric Le Goater         rsp_buffer_set_error(&rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
6884f298a4bSCédric Le Goater         goto out;
6894f298a4bSCédric Le Goater     }
6904f298a4bSCédric Le Goater 
691a580d820SCédric Le Goater     hdl->cmd_handler(ibs, cmd, cmd_len, &rsp);
6928bfffbccSCorey Minyard 
6938bfffbccSCorey Minyard  out:
694a580d820SCédric Le Goater     k->handle_rsp(s, msg_id, rsp.buffer, rsp.len);
6958bfffbccSCorey Minyard 
6968bfffbccSCorey Minyard     next_timeout(ibs);
6978bfffbccSCorey Minyard }
6988bfffbccSCorey Minyard 
ipmi_sim_handle_timeout(IPMIBmcSim * ibs)6998bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs)
7008bfffbccSCorey Minyard {
7018bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
7028bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
703d9494ef9SNicholas Piggin     bool do_log = !IPMI_BMC_WATCHDOG_GET_DONT_LOG(ibs);
7048bfffbccSCorey Minyard 
7058bfffbccSCorey Minyard     if (!ibs->watchdog_running) {
7068bfffbccSCorey Minyard         goto out;
7078bfffbccSCorey Minyard     }
7088bfffbccSCorey Minyard 
7098bfffbccSCorey Minyard     if (!ibs->watchdog_preaction_ran) {
7108bfffbccSCorey Minyard         switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) {
7118bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_NMI:
7128bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7138bfffbccSCorey Minyard             k->do_hw_op(s, IPMI_SEND_NMI, 0);
7148bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
715d9494ef9SNicholas Piggin                                     0xc8, (2 << 4) | 0xf, 0xff,
716d9494ef9SNicholas Piggin                                     do_log);
7178bfffbccSCorey Minyard             break;
7188bfffbccSCorey Minyard 
7198bfffbccSCorey Minyard         case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
7208bfffbccSCorey Minyard             ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK;
7218bfffbccSCorey Minyard             k->set_atn(s, 1, attn_irq_enabled(ibs));
7228bfffbccSCorey Minyard             sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1,
723d9494ef9SNicholas Piggin                                     0xc8, (3 << 4) | 0xf, 0xff,
724d9494ef9SNicholas Piggin                                     do_log);
7258bfffbccSCorey Minyard             break;
7268bfffbccSCorey Minyard 
7278bfffbccSCorey Minyard         default:
7288bfffbccSCorey Minyard             goto do_full_expiry;
7298bfffbccSCorey Minyard         }
7308bfffbccSCorey Minyard 
7318bfffbccSCorey Minyard         ibs->watchdog_preaction_ran = 1;
7328bfffbccSCorey Minyard         /* Issued the pretimeout, do the rest of the timeout now. */
7338bfffbccSCorey Minyard         ibs->watchdog_expiry = ipmi_getmonotime();
7348bfffbccSCorey Minyard         ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL;
7358bfffbccSCorey Minyard         goto out;
7368bfffbccSCorey Minyard     }
7378bfffbccSCorey Minyard 
7388bfffbccSCorey Minyard  do_full_expiry:
7398bfffbccSCorey Minyard     ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */
7408bfffbccSCorey Minyard     ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs));
7418bfffbccSCorey Minyard     switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) {
7428bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
7438bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1,
744d9494ef9SNicholas Piggin                                 0xc0, ibs->watchdog_use & 0xf, 0xff,
745d9494ef9SNicholas Piggin                                 do_log);
7468bfffbccSCorey Minyard         break;
7478bfffbccSCorey Minyard 
7488bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
7498bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1,
750d9494ef9SNicholas Piggin                                 0xc1, ibs->watchdog_use & 0xf, 0xff,
751d9494ef9SNicholas Piggin                                 do_log);
7528bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_RESET_CHASSIS, 0);
7538bfffbccSCorey Minyard         break;
7548bfffbccSCorey Minyard 
7558bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
7568bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
757d9494ef9SNicholas Piggin                                 0xc2, ibs->watchdog_use & 0xf, 0xff,
758d9494ef9SNicholas Piggin                                 do_log);
7598bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0);
7608bfffbccSCorey Minyard         break;
7618bfffbccSCorey Minyard 
7628bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
7638bfffbccSCorey Minyard         sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1,
764d9494ef9SNicholas Piggin                                 0xc3, ibs->watchdog_use & 0xf, 0xff,
765d9494ef9SNicholas Piggin                                 do_log);
7668bfffbccSCorey Minyard         k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0);
7678bfffbccSCorey Minyard         break;
7688bfffbccSCorey Minyard     }
7698bfffbccSCorey Minyard 
7708bfffbccSCorey Minyard  out:
7718bfffbccSCorey Minyard     next_timeout(ibs);
7728bfffbccSCorey Minyard }
7738bfffbccSCorey Minyard 
chassis_capabilities(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7748bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs,
7758bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
776a580d820SCédric Le Goater                                  RspBuffer *rsp)
7778bfffbccSCorey Minyard {
778a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
779a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->parent.slave_addr);
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);
7838bfffbccSCorey Minyard }
7848bfffbccSCorey Minyard 
chassis_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7858bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs,
7868bfffbccSCorey Minyard                            uint8_t *cmd, unsigned int cmd_len,
787a580d820SCédric Le Goater                            RspBuffer *rsp)
7888bfffbccSCorey Minyard {
789a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x61); /* Unknown power restore, power is on */
790a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
791a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
792a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);
7938bfffbccSCorey Minyard }
7948bfffbccSCorey Minyard 
chassis_control(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)7958bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs,
7968bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
797a580d820SCédric Le Goater                             RspBuffer *rsp)
7988bfffbccSCorey Minyard {
7998bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8008bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8018bfffbccSCorey Minyard 
8028bfffbccSCorey Minyard     switch (cmd[2] & 0xf) {
8038bfffbccSCorey Minyard     case 0: /* power down */
8046acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0));
8058bfffbccSCorey Minyard         break;
8068bfffbccSCorey Minyard     case 1: /* power up */
8076acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0));
8088bfffbccSCorey Minyard         break;
8098bfffbccSCorey Minyard     case 2: /* power cycle */
8106acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0));
8118bfffbccSCorey Minyard         break;
8128bfffbccSCorey Minyard     case 3: /* hard reset */
8136acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 0));
8148bfffbccSCorey Minyard         break;
8158bfffbccSCorey Minyard     case 4: /* pulse diagnostic interrupt */
8166acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0));
8178bfffbccSCorey Minyard         break;
8188bfffbccSCorey Minyard     case 5: /* soft shutdown via ACPI by overtemp emulation */
8196acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s,
8206acb971aSCédric Le Goater                                           IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0));
8218bfffbccSCorey Minyard         break;
8228bfffbccSCorey Minyard     default:
8236acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
8248bfffbccSCorey Minyard         return;
8258bfffbccSCorey Minyard     }
826d13ada5dSCédric Le Goater }
8278bfffbccSCorey Minyard 
chassis_get_sys_restart_cause(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)828b7088392SCédric Le Goater static void chassis_get_sys_restart_cause(IPMIBmcSim *ibs,
829b7088392SCédric Le Goater                            uint8_t *cmd, unsigned int cmd_len,
830a580d820SCédric Le Goater                            RspBuffer *rsp)
831a580d820SCédric Le Goater 
832b7088392SCédric Le Goater {
833a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->restart_cause & 0xf); /* Restart Cause */
834a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0);  /* Channel 0 */
835b7088392SCédric Le Goater }
836b7088392SCédric Le Goater 
get_device_id(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8378bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs,
8388bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
839a580d820SCédric Le Goater                           RspBuffer *rsp)
8408bfffbccSCorey Minyard {
841a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_id);
842a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->device_rev & 0xf);
843a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev1 & 0x7f);
844a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->fwrev2);
845a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->ipmi_version);
846a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */
84720b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->mfg_id & 0xff);
84820b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff);
84920b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff);
85020b23364SCorey Minyard     rsp_buffer_push(rsp, ibs->product_id & 0xff);
85120b23364SCorey Minyard     rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff);
8528bfffbccSCorey Minyard }
8538bfffbccSCorey Minyard 
set_global_enables(IPMIBmcSim * ibs,uint8_t val)8548bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val)
8558bfffbccSCorey Minyard {
8568bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8578bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8588bfffbccSCorey Minyard     bool irqs_on;
8598bfffbccSCorey Minyard 
8608bfffbccSCorey Minyard     ibs->bmc_global_enables = val;
8618bfffbccSCorey Minyard 
8628bfffbccSCorey Minyard     irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT |
8638bfffbccSCorey Minyard                      IPMI_BMC_RCV_MSG_QUEUE_INT_BIT);
8648bfffbccSCorey Minyard 
8658bfffbccSCorey Minyard     k->set_irq_enable(s, irqs_on);
8668bfffbccSCorey Minyard }
8678bfffbccSCorey Minyard 
cold_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8688bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs,
8698bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
870a580d820SCédric Le Goater                        RspBuffer *rsp)
8718bfffbccSCorey Minyard {
8728bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8738bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8748bfffbccSCorey Minyard 
8758bfffbccSCorey Minyard     /* Disable all interrupts */
8768bfffbccSCorey Minyard     set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT);
8778bfffbccSCorey Minyard 
8788bfffbccSCorey Minyard     if (k->reset) {
8798bfffbccSCorey Minyard         k->reset(s, true);
8808bfffbccSCorey Minyard     }
8818bfffbccSCorey Minyard }
8828bfffbccSCorey Minyard 
warm_reset(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)8838bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs,
8848bfffbccSCorey Minyard                        uint8_t *cmd, unsigned int cmd_len,
885a580d820SCédric Le Goater                        RspBuffer *rsp)
8868bfffbccSCorey Minyard {
8878bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
8888bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
8898bfffbccSCorey Minyard 
8908bfffbccSCorey Minyard     if (k->reset) {
8918bfffbccSCorey Minyard         k->reset(s, false);
8928bfffbccSCorey Minyard     }
8938bfffbccSCorey Minyard }
set_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)89452ba4d50SCédric Le Goater static void set_acpi_power_state(IPMIBmcSim *ibs,
89552ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
896a580d820SCédric Le Goater                                  RspBuffer *rsp)
89752ba4d50SCédric Le Goater {
89852ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = cmd[2];
89952ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = cmd[3];
90052ba4d50SCédric Le Goater }
90152ba4d50SCédric Le Goater 
get_acpi_power_state(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)90252ba4d50SCédric Le Goater static void get_acpi_power_state(IPMIBmcSim *ibs,
90352ba4d50SCédric Le Goater                                  uint8_t *cmd, unsigned int cmd_len,
904a580d820SCédric Le Goater                                  RspBuffer *rsp)
90552ba4d50SCédric Le Goater {
906a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[0]);
907a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->acpi_power_state[1]);
90852ba4d50SCédric Le Goater }
90952ba4d50SCédric Le Goater 
get_device_guid(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)91052ba4d50SCédric Le Goater static void get_device_guid(IPMIBmcSim *ibs,
91152ba4d50SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
912a580d820SCédric Le Goater                             RspBuffer *rsp)
91352ba4d50SCédric Le Goater {
91452ba4d50SCédric Le Goater     unsigned int i;
91552ba4d50SCédric Le Goater 
9167b0cd78bSCorey Minyard     /* An uninitialized uuid is all zeros, use that to know if it is set. */
91752ba4d50SCédric Le Goater     for (i = 0; i < 16; i++) {
9187b0cd78bSCorey Minyard         if (ibs->uuid.data[i]) {
9197b0cd78bSCorey Minyard             goto uuid_set;
9207b0cd78bSCorey Minyard         }
9217b0cd78bSCorey Minyard     }
9227b0cd78bSCorey Minyard     /* No uuid is set, return an error. */
9237b0cd78bSCorey Minyard     rsp_buffer_set_error(rsp, IPMI_CC_INVALID_CMD);
9247b0cd78bSCorey Minyard     return;
9257b0cd78bSCorey Minyard 
9267b0cd78bSCorey Minyard  uuid_set:
9277b0cd78bSCorey Minyard     for (i = 0; i < 16; i++) {
9287b0cd78bSCorey Minyard         rsp_buffer_push(rsp, ibs->uuid.data[i]);
92952ba4d50SCédric Le Goater     }
93052ba4d50SCédric Le Goater }
9318bfffbccSCorey Minyard 
set_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9328bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs,
9338bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
934a580d820SCédric Le Goater                                    RspBuffer *rsp)
9358bfffbccSCorey Minyard {
936dacb3e70SNicholas Piggin     uint8_t val = cmd[2];
937dacb3e70SNicholas Piggin 
938dacb3e70SNicholas Piggin     if (val & ~IPMI_BMC_GLOBAL_ENABLES_SUPPORTED) {
939dacb3e70SNicholas Piggin         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
940dacb3e70SNicholas Piggin         return;
941dacb3e70SNicholas Piggin     }
942dacb3e70SNicholas Piggin 
943dacb3e70SNicholas Piggin     set_global_enables(ibs, val);
9448bfffbccSCorey Minyard }
9458bfffbccSCorey Minyard 
get_bmc_global_enables(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9468bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs,
9478bfffbccSCorey Minyard                                    uint8_t *cmd, unsigned int cmd_len,
948a580d820SCédric Le Goater                                    RspBuffer *rsp)
9498bfffbccSCorey Minyard {
950a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->bmc_global_enables);
9518bfffbccSCorey Minyard }
9528bfffbccSCorey Minyard 
clr_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9538bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs,
9548bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
955a580d820SCédric Le Goater                           RspBuffer *rsp)
9568bfffbccSCorey Minyard {
9578bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9588bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9598bfffbccSCorey Minyard 
9608bfffbccSCorey Minyard     ibs->msg_flags &= ~cmd[2];
9618bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9628bfffbccSCorey Minyard }
9638bfffbccSCorey Minyard 
get_msg_flags(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9648bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs,
9658bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
966a580d820SCédric Le Goater                           RspBuffer *rsp)
9678bfffbccSCorey Minyard {
968a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->msg_flags);
9698bfffbccSCorey Minyard }
9708bfffbccSCorey Minyard 
read_evt_msg_buf(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9718bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs,
9728bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
973a580d820SCédric Le Goater                              RspBuffer *rsp)
9748bfffbccSCorey Minyard {
9758bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
9768bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
9778bfffbccSCorey Minyard     unsigned int i;
9788bfffbccSCorey Minyard 
9798bfffbccSCorey Minyard     if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) {
9806acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
981d13ada5dSCédric Le Goater         return;
9828bfffbccSCorey Minyard     }
9838bfffbccSCorey Minyard     for (i = 0; i < 16; i++) {
984a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->evtbuf[i]);
9858bfffbccSCorey Minyard     }
9868bfffbccSCorey Minyard     ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL;
9878bfffbccSCorey Minyard     k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
9888bfffbccSCorey Minyard }
9898bfffbccSCorey Minyard 
get_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)9908bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs,
9918bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
992a580d820SCédric Le Goater                     RspBuffer *rsp)
9938bfffbccSCorey Minyard {
9948bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
9958bfffbccSCorey Minyard 
9968bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
9976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80); /* Queue empty */
998abb55b1aSMarkus Armbruster         return;
9998bfffbccSCorey Minyard     }
1000a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0); /* Channel 0 */
10018bfffbccSCorey Minyard     msg = QTAILQ_FIRST(&ibs->rcvbufs);
1002a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, msg->buf, msg->len);
10038bfffbccSCorey Minyard     QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry);
10048bfffbccSCorey Minyard     g_free(msg);
10058bfffbccSCorey Minyard 
10068bfffbccSCorey Minyard     if (QTAILQ_EMPTY(&ibs->rcvbufs)) {
10078bfffbccSCorey Minyard         IPMIInterface *s = ibs->parent.intf;
10088bfffbccSCorey Minyard         IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10098bfffbccSCorey Minyard 
10108bfffbccSCorey Minyard         ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
10118bfffbccSCorey Minyard         k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs));
10128bfffbccSCorey Minyard     }
10138bfffbccSCorey Minyard }
10148bfffbccSCorey Minyard 
10158bfffbccSCorey Minyard static unsigned char
ipmb_checksum(unsigned char * data,int size,unsigned char csum)10168bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum)
10178bfffbccSCorey Minyard {
10188bfffbccSCorey Minyard     for (; size > 0; size--, data++) {
10198bfffbccSCorey Minyard             csum += *data;
10208bfffbccSCorey Minyard     }
10218bfffbccSCorey Minyard 
10228bfffbccSCorey Minyard     return -csum;
10238bfffbccSCorey Minyard }
10248bfffbccSCorey Minyard 
send_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)10258bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs,
10268bfffbccSCorey Minyard                      uint8_t *cmd, unsigned int cmd_len,
1027a580d820SCédric Le Goater                      RspBuffer *rsp)
10288bfffbccSCorey Minyard {
10298bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
10308bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
10318bfffbccSCorey Minyard     IPMIRcvBufEntry *msg;
10328bfffbccSCorey Minyard     uint8_t *buf;
10338bfffbccSCorey Minyard     uint8_t netfn, rqLun, rsLun, rqSeq;
10348bfffbccSCorey Minyard 
10357f9e7af4SNicholas Piggin     if (cmd[2] != IPMI_CHANNEL_IPMB) {
10367f9e7af4SNicholas Piggin         /* We only handle channel 0h (IPMB) with no options */
10376acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1038d13ada5dSCédric Le Goater         return;
10398bfffbccSCorey Minyard     }
10408bfffbccSCorey Minyard 
10414f298a4bSCédric Le Goater     if (cmd_len < 10) {
10426acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQUEST_DATA_LENGTH_INVALID);
10434f298a4bSCédric Le Goater         return;
10444f298a4bSCédric Le Goater     }
10454f298a4bSCédric Le Goater 
10468bfffbccSCorey Minyard     if (cmd[3] != 0x40) {
10478bfffbccSCorey Minyard         /* We only emulate a MC at address 0x40. */
10486acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x83); /* NAK on write */
1049d13ada5dSCédric Le Goater         return;
10508bfffbccSCorey Minyard     }
10518bfffbccSCorey Minyard 
10528bfffbccSCorey Minyard     cmd += 3; /* Skip the header. */
10538bfffbccSCorey Minyard     cmd_len -= 3;
10548bfffbccSCorey Minyard 
10558bfffbccSCorey Minyard     /*
10568bfffbccSCorey Minyard      * At this point we "send" the message successfully.  Any error will
10578bfffbccSCorey Minyard      * be returned in the response.
10588bfffbccSCorey Minyard      */
10598bfffbccSCorey Minyard     if (ipmb_checksum(cmd, cmd_len, 0) != 0 ||
10608bfffbccSCorey Minyard         cmd[3] != 0x20) { /* Improper response address */
1061d13ada5dSCédric Le Goater         return; /* No response */
10628bfffbccSCorey Minyard     }
10638bfffbccSCorey Minyard 
10648bfffbccSCorey Minyard     netfn = cmd[1] >> 2;
10658bfffbccSCorey Minyard     rqLun = cmd[4] & 0x3;
10668bfffbccSCorey Minyard     rsLun = cmd[1] & 0x3;
10678bfffbccSCorey Minyard     rqSeq = cmd[4] >> 2;
10688bfffbccSCorey Minyard 
10698bfffbccSCorey Minyard     if (rqLun != 2) {
10708bfffbccSCorey Minyard         /* We only support LUN 2 coming back to us. */
1071d13ada5dSCédric Le Goater         return;
10728bfffbccSCorey Minyard     }
10738bfffbccSCorey Minyard 
10748bfffbccSCorey Minyard     msg = g_malloc(sizeof(*msg));
10758bfffbccSCorey Minyard     msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */
10768bfffbccSCorey Minyard     msg->buf[1] = ipmb_checksum(msg->buf, 1, 0);
10778bfffbccSCorey Minyard     msg->buf[2] = cmd[0]; /* rsSA */
10788bfffbccSCorey Minyard     msg->buf[3] = (rqSeq << 2) | rsLun;
10798bfffbccSCorey Minyard     msg->buf[4] = cmd[5]; /* Cmd */
10808bfffbccSCorey Minyard     msg->buf[5] = 0; /* Completion Code */
10818bfffbccSCorey Minyard     msg->len = 6;
10828bfffbccSCorey Minyard 
10838bfffbccSCorey Minyard     if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) {
10848bfffbccSCorey Minyard         /* Not a command we handle. */
10858bfffbccSCorey Minyard         msg->buf[5] = IPMI_CC_INVALID_CMD;
10868bfffbccSCorey Minyard         goto end_msg;
10878bfffbccSCorey Minyard     }
10888bfffbccSCorey Minyard 
10898bfffbccSCorey Minyard     buf = msg->buf + msg->len; /* After the CC */
10908bfffbccSCorey Minyard     buf[0] = 0;
10918bfffbccSCorey Minyard     buf[1] = 0;
10928bfffbccSCorey Minyard     buf[2] = 0;
10938bfffbccSCorey Minyard     buf[3] = 0;
10948bfffbccSCorey Minyard     buf[4] = 0x51;
10958bfffbccSCorey Minyard     buf[5] = 0;
10968bfffbccSCorey Minyard     buf[6] = 0;
10978bfffbccSCorey Minyard     buf[7] = 0;
10988bfffbccSCorey Minyard     buf[8] = 0;
10998bfffbccSCorey Minyard     buf[9] = 0;
11008bfffbccSCorey Minyard     buf[10] = 0;
11018bfffbccSCorey Minyard     msg->len += 11;
11028bfffbccSCorey Minyard 
11038bfffbccSCorey Minyard  end_msg:
11048bfffbccSCorey Minyard     msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0);
11058bfffbccSCorey Minyard     msg->len++;
11068bfffbccSCorey Minyard     QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry);
11078bfffbccSCorey Minyard     ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE;
11088bfffbccSCorey Minyard     k->set_atn(s, 1, attn_irq_enabled(ibs));
11098bfffbccSCorey Minyard }
11108bfffbccSCorey Minyard 
do_watchdog_reset(IPMIBmcSim * ibs)11118bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs)
11128bfffbccSCorey Minyard {
11138bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) ==
11148bfffbccSCorey Minyard         IPMI_BMC_WATCHDOG_ACTION_NONE) {
11158bfffbccSCorey Minyard         ibs->watchdog_running = 0;
11168bfffbccSCorey Minyard         return;
11178bfffbccSCorey Minyard     }
11188bfffbccSCorey Minyard     ibs->watchdog_preaction_ran = 0;
11198bfffbccSCorey Minyard 
11208bfffbccSCorey Minyard 
11218bfffbccSCorey Minyard     /* Timeout is in tenths of a second, offset is in seconds */
11228bfffbccSCorey Minyard     ibs->watchdog_expiry = ipmi_getmonotime();
11238bfffbccSCorey Minyard     ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL;
11248bfffbccSCorey Minyard     if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) {
11258bfffbccSCorey Minyard         ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL;
11268bfffbccSCorey Minyard     }
11278bfffbccSCorey Minyard     ibs->watchdog_running = 1;
11288bfffbccSCorey Minyard }
11298bfffbccSCorey Minyard 
reset_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11308bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs,
11318bfffbccSCorey Minyard                                  uint8_t *cmd, unsigned int cmd_len,
1132a580d820SCédric Le Goater                                  RspBuffer *rsp)
11338bfffbccSCorey Minyard {
11348bfffbccSCorey Minyard     if (!ibs->watchdog_initialized) {
11356acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, 0x80);
1136d13ada5dSCédric Le Goater         return;
11378bfffbccSCorey Minyard     }
11388bfffbccSCorey Minyard     do_watchdog_reset(ibs);
11398bfffbccSCorey Minyard }
11408bfffbccSCorey Minyard 
set_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)11418bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs,
11428bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1143a580d820SCédric Le Goater                                RspBuffer *rsp)
11448bfffbccSCorey Minyard {
11458bfffbccSCorey Minyard     IPMIInterface *s = ibs->parent.intf;
11468bfffbccSCorey Minyard     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
11478bfffbccSCorey Minyard     unsigned int val;
11488bfffbccSCorey Minyard 
11498bfffbccSCorey Minyard     val = cmd[2] & 0x7; /* Validate use */
11508bfffbccSCorey Minyard     if (val == 0 || val > 5) {
11516acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1152d13ada5dSCédric Le Goater         return;
11538bfffbccSCorey Minyard     }
11548bfffbccSCorey Minyard     val = cmd[3] & 0x7; /* Validate action */
11558bfffbccSCorey Minyard     switch (val) {
11568bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_NONE:
11578bfffbccSCorey Minyard         break;
11588bfffbccSCorey Minyard 
11598bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_RESET:
11606acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_RESET_CHASSIS, 1));
11618bfffbccSCorey Minyard         break;
11628bfffbccSCorey Minyard 
11638bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN:
11646acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1));
11658bfffbccSCorey Minyard         break;
11668bfffbccSCorey Minyard 
11678bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE:
11686acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1));
11698bfffbccSCorey Minyard         break;
11708bfffbccSCorey Minyard 
11718bfffbccSCorey Minyard     default:
11726acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
11738bfffbccSCorey Minyard     }
1174a580d820SCédric Le Goater     if (rsp->buffer[2]) {
11756acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1176d13ada5dSCédric Le Goater         return;
11778bfffbccSCorey Minyard     }
11788bfffbccSCorey Minyard 
11798bfffbccSCorey Minyard     val = (cmd[3] >> 4) & 0x7; /* Validate preaction */
11808bfffbccSCorey Minyard     switch (val) {
11818bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_MSG_INT:
11828bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NONE:
11838bfffbccSCorey Minyard         break;
11848bfffbccSCorey Minyard 
11858bfffbccSCorey Minyard     case IPMI_BMC_WATCHDOG_PRE_NMI:
11866af94767SCorey Minyard         if (k->do_hw_op(s, IPMI_SEND_NMI, 1)) {
11878bfffbccSCorey Minyard             /* NMI not supported. */
11886acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1189d13ada5dSCédric Le Goater             return;
11908bfffbccSCorey Minyard         }
119137eebb86SCorey Minyard         break;
119237eebb86SCorey Minyard 
11938bfffbccSCorey Minyard     default:
11948bfffbccSCorey Minyard         /* We don't support PRE_SMI */
11956acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1196d13ada5dSCédric Le Goater         return;
11978bfffbccSCorey Minyard     }
11988bfffbccSCorey Minyard 
11998bfffbccSCorey Minyard     ibs->watchdog_initialized = 1;
12008bfffbccSCorey Minyard     ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK;
12018bfffbccSCorey Minyard     ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK;
12028bfffbccSCorey Minyard     ibs->watchdog_pretimeout = cmd[4];
12038bfffbccSCorey Minyard     ibs->watchdog_expired &= ~cmd[5];
12048bfffbccSCorey Minyard     ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8);
12058bfffbccSCorey Minyard     if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) {
12068bfffbccSCorey Minyard         do_watchdog_reset(ibs);
12078bfffbccSCorey Minyard     } else {
12088bfffbccSCorey Minyard         ibs->watchdog_running = 0;
12098bfffbccSCorey Minyard     }
12108bfffbccSCorey Minyard }
12118bfffbccSCorey Minyard 
get_watchdog_timer(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12128bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs,
12138bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1214a580d820SCédric Le Goater                                RspBuffer *rsp)
12158bfffbccSCorey Minyard {
1216a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_use);
1217a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_action);
1218a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_pretimeout);
1219a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->watchdog_expired);
1220fb45770bSCorey Minyard     rsp_buffer_push(rsp, ibs->watchdog_timeout & 0xff);
1221fb45770bSCorey Minyard     rsp_buffer_push(rsp, (ibs->watchdog_timeout >> 8) & 0xff);
12228bfffbccSCorey Minyard     if (ibs->watchdog_running) {
12238bfffbccSCorey Minyard         long timeout;
12248bfffbccSCorey Minyard         timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000)
12258bfffbccSCorey Minyard                    / 100000000);
1226a580d820SCédric Le Goater         rsp_buffer_push(rsp, timeout & 0xff);
1227a580d820SCédric Le Goater         rsp_buffer_push(rsp, (timeout >> 8) & 0xff);
12288bfffbccSCorey Minyard     } else {
1229a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
1230a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0);
12318bfffbccSCorey Minyard     }
12328bfffbccSCorey Minyard }
12338bfffbccSCorey Minyard 
get_channel_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12347f9e7af4SNicholas Piggin static void get_channel_info(IPMIBmcSim *ibs,
12357f9e7af4SNicholas Piggin                              uint8_t *cmd, unsigned int cmd_len,
12367f9e7af4SNicholas Piggin                              RspBuffer *rsp)
12377f9e7af4SNicholas Piggin {
12387f9e7af4SNicholas Piggin     IPMIInterface *s = ibs->parent.intf;
12397f9e7af4SNicholas Piggin     IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s);
12407f9e7af4SNicholas Piggin     IPMIFwInfo info = {};
12417f9e7af4SNicholas Piggin     uint8_t ch = cmd[2] & 0x0f;
12427f9e7af4SNicholas Piggin 
12437f9e7af4SNicholas Piggin     /* Only define channel 0h (IPMB) and Fh (system interface) */
12447f9e7af4SNicholas Piggin 
12457f9e7af4SNicholas Piggin     if (ch == 0x0e) { /* "This channel" */
12467f9e7af4SNicholas Piggin         ch = IPMI_CHANNEL_SYSTEM;
12477f9e7af4SNicholas Piggin     }
12487f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, ch);
12497f9e7af4SNicholas Piggin 
12507f9e7af4SNicholas Piggin     if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) {
12517f9e7af4SNicholas Piggin         /* Not a supported channel */
12527f9e7af4SNicholas Piggin         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
12537f9e7af4SNicholas Piggin         return;
12547f9e7af4SNicholas Piggin     }
12557f9e7af4SNicholas Piggin 
12567f9e7af4SNicholas Piggin     if (k->get_fwinfo) {
12577f9e7af4SNicholas Piggin         k->get_fwinfo(s, &info);
12587f9e7af4SNicholas Piggin     }
12597f9e7af4SNicholas Piggin 
12607f9e7af4SNicholas Piggin     if (ch == IPMI_CHANNEL_IPMB) {
12617f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB);
12627f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB);
12637f9e7af4SNicholas Piggin     } else { /* IPMI_CHANNEL_SYSTEM */
12647f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM);
12657f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, info.ipmi_channel_protocol);
12667f9e7af4SNicholas Piggin     }
12677f9e7af4SNicholas Piggin 
12687f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x00); /* Session-less */
12697f9e7af4SNicholas Piggin 
12707f9e7af4SNicholas Piggin     /* IPMI Enterprise Number for Vendor ID */
12717f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0xf2);
12727f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x1b);
12737f9e7af4SNicholas Piggin     rsp_buffer_push(rsp, 0x00);
12747f9e7af4SNicholas Piggin 
12757f9e7af4SNicholas Piggin     if (ch == IPMI_CHANNEL_SYSTEM) {
12767f9e7af4SNicholas Piggin         uint8_t irq;
12777f9e7af4SNicholas Piggin 
12787f9e7af4SNicholas Piggin         if (info.irq_source == IPMI_ISA_IRQ) {
12797f9e7af4SNicholas Piggin             irq = info.interrupt_number;
12807f9e7af4SNicholas Piggin         } else if (info.irq_source == IPMI_PCI_IRQ) {
12817f9e7af4SNicholas Piggin             irq = 0x10 + info.interrupt_number;
12827f9e7af4SNicholas Piggin         } else {
12837f9e7af4SNicholas Piggin             irq = 0xff; /* no interrupt / unspecified */
12847f9e7af4SNicholas Piggin         }
12857f9e7af4SNicholas Piggin 
12867f9e7af4SNicholas Piggin         /* Both interrupts use the same irq number */
12877f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, irq);
12887f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, irq);
12897f9e7af4SNicholas Piggin     } else {
12907f9e7af4SNicholas Piggin         /* Reserved */
12917f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, 0x00);
12927f9e7af4SNicholas Piggin         rsp_buffer_push(rsp, 0x00);
12937f9e7af4SNicholas Piggin     }
12947f9e7af4SNicholas Piggin }
12957f9e7af4SNicholas Piggin 
get_sdr_rep_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)12968bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs,
12978bfffbccSCorey Minyard                              uint8_t *cmd, unsigned int cmd_len,
1298a580d820SCédric Le Goater                              RspBuffer *rsp)
12998bfffbccSCorey Minyard {
13008bfffbccSCorey Minyard     unsigned int i;
13018bfffbccSCorey Minyard 
1302a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 spec */
1303a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.next_rec_id & 0xff);
1304a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.next_rec_id >> 8) & 0xff);
1305a580d820SCédric Le Goater     rsp_buffer_push(rsp, (MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff);
1306a580d820SCédric Le Goater     rsp_buffer_push(rsp, ((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff);
13078bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1308a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_addition[i]);
13098bfffbccSCorey Minyard     }
13108bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1311a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sdr.last_clear[i]);
13128bfffbccSCorey Minyard     }
13138bfffbccSCorey Minyard     /* Only modal support, reserve supported */
1314a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.overflow << 7) | 0x22);
13158bfffbccSCorey Minyard }
13168bfffbccSCorey Minyard 
reserve_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13178bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs,
13188bfffbccSCorey Minyard                             uint8_t *cmd, unsigned int cmd_len,
1319a580d820SCédric Le Goater                             RspBuffer *rsp)
13208bfffbccSCorey Minyard {
1321a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sdr.reservation & 0xff);
1322a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sdr.reservation >> 8) & 0xff);
13238bfffbccSCorey Minyard }
13248bfffbccSCorey Minyard 
get_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13258bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs,
13268bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1327a580d820SCédric Le Goater                     RspBuffer *rsp)
13288bfffbccSCorey Minyard {
13298bfffbccSCorey Minyard     unsigned int pos;
13308bfffbccSCorey Minyard     uint16_t nextrec;
1331a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh;
13328bfffbccSCorey Minyard 
13338bfffbccSCorey Minyard     if (cmd[6]) {
13347f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13356acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13367f996411SCédric Le Goater             return;
13378bfffbccSCorey Minyard         }
13387f996411SCédric Le Goater     }
13397f996411SCédric Le Goater 
13408bfffbccSCorey Minyard     pos = 0;
13418bfffbccSCorey Minyard     if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8),
13428bfffbccSCorey Minyard                        &pos, &nextrec)) {
13436acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1344d13ada5dSCédric Le Goater         return;
13458bfffbccSCorey Minyard     }
1346a2295f0aSCédric Le Goater 
1347a2295f0aSCédric Le Goater     sdrh = (struct ipmi_sdr_header *) &ibs->sdr.sdr[pos];
1348a2295f0aSCédric Le Goater 
1349a2295f0aSCédric Le Goater     if (cmd[6] > ipmi_sdr_length(sdrh)) {
13506acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_PARM_OUT_OF_RANGE);
1351d13ada5dSCédric Le Goater         return;
13528bfffbccSCorey Minyard     }
13538bfffbccSCorey Minyard 
1354a580d820SCédric Le Goater     rsp_buffer_push(rsp, nextrec & 0xff);
1355a580d820SCédric Le Goater     rsp_buffer_push(rsp, (nextrec >> 8) & 0xff);
13568bfffbccSCorey Minyard 
13578bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
1358a2295f0aSCédric Le Goater         cmd[7] = ipmi_sdr_length(sdrh) - cmd[6];
13598bfffbccSCorey Minyard     }
13608bfffbccSCorey Minyard 
1361a580d820SCédric Le Goater     if ((cmd[7] + rsp->len) > sizeof(rsp->buffer)) {
13626acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES);
1363d13ada5dSCédric Le Goater         return;
13648bfffbccSCorey Minyard     }
1365a580d820SCédric Le Goater 
1366a580d820SCédric Le Goater     rsp_buffer_pushmore(rsp, ibs->sdr.sdr + pos + cmd[6], cmd[7]);
13678bfffbccSCorey Minyard }
13688bfffbccSCorey Minyard 
add_sdr(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13698bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs,
13708bfffbccSCorey Minyard                     uint8_t *cmd, unsigned int cmd_len,
1371a580d820SCédric Le Goater                     RspBuffer *rsp)
13728bfffbccSCorey Minyard {
13738bfffbccSCorey Minyard     uint16_t recid;
1374a2295f0aSCédric Le Goater     struct ipmi_sdr_header *sdrh = (struct ipmi_sdr_header *) cmd + 2;
13758bfffbccSCorey Minyard 
1376a2295f0aSCédric Le Goater     if (sdr_add_entry(ibs, sdrh, cmd_len - 2, &recid)) {
13776acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1378d13ada5dSCédric Le Goater         return;
13798bfffbccSCorey Minyard     }
1380a580d820SCédric Le Goater     rsp_buffer_push(rsp, recid & 0xff);
1381a580d820SCédric Le Goater     rsp_buffer_push(rsp, (recid >> 8) & 0xff);
13828bfffbccSCorey Minyard }
13838bfffbccSCorey Minyard 
clear_sdr_rep(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)13848bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs,
13858bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1386a580d820SCédric Le Goater                           RspBuffer *rsp)
13878bfffbccSCorey Minyard {
13887f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sdr.reservation) {
13896acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
13907f996411SCédric Le Goater         return;
13917f996411SCédric Le Goater     }
13927f996411SCédric Le Goater 
13938bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
13946acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1395d13ada5dSCédric Le Goater         return;
13968bfffbccSCorey Minyard     }
13978bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
13988bfffbccSCorey Minyard         ibs->sdr.next_free = 0;
13998bfffbccSCorey Minyard         ibs->sdr.overflow = 0;
14008bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1401a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14028bfffbccSCorey Minyard         sdr_inc_reservation(&ibs->sdr);
14038bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1404a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
14058bfffbccSCorey Minyard     } else {
14066acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
14078bfffbccSCorey Minyard         return;
14088bfffbccSCorey Minyard     }
1409d13ada5dSCédric Le Goater }
14108bfffbccSCorey Minyard 
get_sel_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)14118bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs,
14128bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1413a580d820SCédric Le Goater                          RspBuffer *rsp)
14148bfffbccSCorey Minyard {
14158bfffbccSCorey Minyard     unsigned int i, val;
14168bfffbccSCorey Minyard 
1417a580d820SCédric Le Goater     rsp_buffer_push(rsp, 0x51); /* Conform to IPMI 1.5 */
1418a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.next_free & 0xff);
1419a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.next_free >> 8) & 0xff);
14208bfffbccSCorey Minyard     val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16;
1421a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1422a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
14238bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1424a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_addition[i]);
14258bfffbccSCorey Minyard     }
14268bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
1427a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.last_clear[i]);
14288bfffbccSCorey Minyard     }
14298bfffbccSCorey Minyard     /* Only support Reserve SEL */
1430a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.overflow << 7) | 0x02);
14318bfffbccSCorey Minyard }
14328bfffbccSCorey Minyard 
get_fru_area_info(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1433540c07d3SCédric Le Goater static void get_fru_area_info(IPMIBmcSim *ibs,
1434540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1435540c07d3SCédric Le Goater                          RspBuffer *rsp)
1436540c07d3SCédric Le Goater {
1437540c07d3SCédric Le Goater     uint8_t fruid;
1438540c07d3SCédric Le Goater     uint16_t fru_entry_size;
1439540c07d3SCédric Le Goater 
1440540c07d3SCédric Le Goater     fruid = cmd[2];
1441540c07d3SCédric Le Goater 
1442540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1443540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1444540c07d3SCédric Le Goater         return;
1445540c07d3SCédric Le Goater     }
1446540c07d3SCédric Le Goater 
1447540c07d3SCédric Le Goater     fru_entry_size = ibs->fru.areasize;
1448540c07d3SCédric Le Goater 
1449540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size & 0xff);
1450540c07d3SCédric Le Goater     rsp_buffer_push(rsp, fru_entry_size >> 8 & 0xff);
1451540c07d3SCédric Le Goater     rsp_buffer_push(rsp, 0x0);
1452540c07d3SCédric Le Goater }
1453540c07d3SCédric Le Goater 
read_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1454540c07d3SCédric Le Goater static void read_fru_data(IPMIBmcSim *ibs,
1455540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1456540c07d3SCédric Le Goater                          RspBuffer *rsp)
1457540c07d3SCédric Le Goater {
1458540c07d3SCédric Le Goater     uint8_t fruid;
1459540c07d3SCédric Le Goater     uint16_t offset;
1460540c07d3SCédric Le Goater     int i;
1461540c07d3SCédric Le Goater     uint8_t *fru_entry;
1462540c07d3SCédric Le Goater     unsigned int count;
1463540c07d3SCédric Le Goater 
1464540c07d3SCédric Le Goater     fruid = cmd[2];
1465540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1466540c07d3SCédric Le Goater 
1467540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1468540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1469540c07d3SCédric Le Goater         return;
1470540c07d3SCédric Le Goater     }
1471540c07d3SCédric Le Goater 
1472540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1473540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1474540c07d3SCédric Le Goater         return;
1475540c07d3SCédric Le Goater     }
1476540c07d3SCédric Le Goater 
1477540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1478540c07d3SCédric Le Goater 
1479540c07d3SCédric Le Goater     count = MIN(cmd[5], ibs->fru.areasize - offset);
1480540c07d3SCédric Le Goater 
1481540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1482540c07d3SCédric Le Goater     for (i = 0; i < count; i++) {
1483540c07d3SCédric Le Goater         rsp_buffer_push(rsp, fru_entry[offset + i]);
1484540c07d3SCédric Le Goater     }
1485540c07d3SCédric Le Goater }
1486540c07d3SCédric Le Goater 
write_fru_data(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1487540c07d3SCédric Le Goater static void write_fru_data(IPMIBmcSim *ibs,
1488540c07d3SCédric Le Goater                          uint8_t *cmd, unsigned int cmd_len,
1489540c07d3SCédric Le Goater                          RspBuffer *rsp)
1490540c07d3SCédric Le Goater {
1491540c07d3SCédric Le Goater     uint8_t fruid;
1492540c07d3SCédric Le Goater     uint16_t offset;
1493540c07d3SCédric Le Goater     uint8_t *fru_entry;
1494540c07d3SCédric Le Goater     unsigned int count;
1495540c07d3SCédric Le Goater 
1496540c07d3SCédric Le Goater     fruid = cmd[2];
1497540c07d3SCédric Le Goater     offset = (cmd[3] | cmd[4] << 8);
1498540c07d3SCédric Le Goater 
1499540c07d3SCédric Le Goater     if (fruid >= ibs->fru.nentries) {
1500540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1501540c07d3SCédric Le Goater         return;
1502540c07d3SCédric Le Goater     }
1503540c07d3SCédric Le Goater 
1504540c07d3SCédric Le Goater     if (offset >= ibs->fru.areasize - 1) {
1505540c07d3SCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1506540c07d3SCédric Le Goater         return;
1507540c07d3SCédric Le Goater     }
1508540c07d3SCédric Le Goater 
1509540c07d3SCédric Le Goater     fru_entry = &ibs->fru.data[fruid * ibs->fru.areasize];
1510540c07d3SCédric Le Goater 
1511540c07d3SCédric Le Goater     count = MIN(cmd_len - 5, ibs->fru.areasize - offset);
1512540c07d3SCédric Le Goater 
1513540c07d3SCédric Le Goater     memcpy(fru_entry + offset, cmd + 5, count);
1514540c07d3SCédric Le Goater 
1515540c07d3SCédric Le Goater     rsp_buffer_push(rsp, count & 0xff);
1516540c07d3SCédric Le Goater }
1517540c07d3SCédric Le Goater 
reserve_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15188bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs,
15198bfffbccSCorey Minyard                         uint8_t *cmd, unsigned int cmd_len,
1520a580d820SCédric Le Goater                         RspBuffer *rsp)
15218bfffbccSCorey Minyard {
1522a580d820SCédric Le Goater     rsp_buffer_push(rsp, ibs->sel.reservation & 0xff);
1523a580d820SCédric Le Goater     rsp_buffer_push(rsp, (ibs->sel.reservation >> 8) & 0xff);
15248bfffbccSCorey Minyard }
15258bfffbccSCorey Minyard 
get_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15268bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs,
15278bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1528a580d820SCédric Le Goater                           RspBuffer *rsp)
15298bfffbccSCorey Minyard {
15308bfffbccSCorey Minyard     unsigned int val;
15318bfffbccSCorey Minyard 
15328bfffbccSCorey Minyard     if (cmd[6]) {
15337f996411SCédric Le Goater         if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15346acb971aSCédric Le Goater             rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15357f996411SCédric Le Goater             return;
15367f996411SCédric Le Goater         }
15378bfffbccSCorey Minyard     }
15388bfffbccSCorey Minyard     if (ibs->sel.next_free == 0) {
15396acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1540d13ada5dSCédric Le Goater         return;
15418bfffbccSCorey Minyard     }
15428bfffbccSCorey Minyard     if (cmd[6] > 15) {
15436acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1544d13ada5dSCédric Le Goater         return;
15458bfffbccSCorey Minyard     }
15468bfffbccSCorey Minyard     if (cmd[7] == 0xff) {
15478bfffbccSCorey Minyard         cmd[7] = 16;
15488bfffbccSCorey Minyard     } else if ((cmd[7] + cmd[6]) > 16) {
15496acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1550d13ada5dSCédric Le Goater         return;
15518bfffbccSCorey Minyard     } else {
15528bfffbccSCorey Minyard         cmd[7] += cmd[6];
15538bfffbccSCorey Minyard     }
15548bfffbccSCorey Minyard 
15558bfffbccSCorey Minyard     val = cmd[4] | (cmd[5] << 8);
15568bfffbccSCorey Minyard     if (val == 0xffff) {
15578bfffbccSCorey Minyard         val = ibs->sel.next_free - 1;
15588bfffbccSCorey Minyard     } else if (val >= ibs->sel.next_free) {
15596acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1560d13ada5dSCédric Le Goater         return;
15618bfffbccSCorey Minyard     }
15628bfffbccSCorey Minyard     if ((val + 1) == ibs->sel.next_free) {
1563a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
1564a580d820SCédric Le Goater         rsp_buffer_push(rsp, 0xff);
15658bfffbccSCorey Minyard     } else {
1566a580d820SCédric Le Goater         rsp_buffer_push(rsp, (val + 1) & 0xff);
1567a580d820SCédric Le Goater         rsp_buffer_push(rsp, ((val + 1) >> 8) & 0xff);
15688bfffbccSCorey Minyard     }
15698bfffbccSCorey Minyard     for (; cmd[6] < cmd[7]; cmd[6]++) {
1570a580d820SCédric Le Goater         rsp_buffer_push(rsp, ibs->sel.sel[val][cmd[6]]);
15718bfffbccSCorey Minyard     }
15728bfffbccSCorey Minyard }
15738bfffbccSCorey Minyard 
add_sel_entry(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15748bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs,
15758bfffbccSCorey Minyard                           uint8_t *cmd, unsigned int cmd_len,
1576a580d820SCédric Le Goater                           RspBuffer *rsp)
15778bfffbccSCorey Minyard {
15788bfffbccSCorey Minyard     if (sel_add_event(ibs, cmd + 2)) {
15796acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
1580d13ada5dSCédric Le Goater         return;
15818bfffbccSCorey Minyard     }
15828bfffbccSCorey Minyard     /* sel_add_event fills in the record number. */
1583a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[2]);
1584a580d820SCédric Le Goater     rsp_buffer_push(rsp, cmd[3]);
15858bfffbccSCorey Minyard }
15868bfffbccSCorey Minyard 
clear_sel(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)15878bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs,
15888bfffbccSCorey Minyard                       uint8_t *cmd, unsigned int cmd_len,
1589a580d820SCédric Le Goater                       RspBuffer *rsp)
15908bfffbccSCorey Minyard {
15917f996411SCédric Le Goater     if ((cmd[2] | (cmd[3] << 8)) != ibs->sel.reservation) {
15926acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_RESERVATION);
15937f996411SCédric Le Goater         return;
15947f996411SCédric Le Goater     }
15957f996411SCédric Le Goater 
15968bfffbccSCorey Minyard     if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') {
15976acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1598d13ada5dSCédric Le Goater         return;
15998bfffbccSCorey Minyard     }
16008bfffbccSCorey Minyard     if (cmd[7] == 0xaa) {
16018bfffbccSCorey Minyard         ibs->sel.next_free = 0;
16028bfffbccSCorey Minyard         ibs->sel.overflow = 0;
16038bfffbccSCorey Minyard         set_timestamp(ibs, ibs->sdr.last_clear);
1604a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
16058bfffbccSCorey Minyard         sel_inc_reservation(&ibs->sel);
16068bfffbccSCorey Minyard     } else if (cmd[7] == 0) {
1607a580d820SCédric Le Goater         rsp_buffer_push(rsp, 1); /* Erasure complete */
16088bfffbccSCorey Minyard     } else {
16096acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
16108bfffbccSCorey Minyard         return;
16118bfffbccSCorey Minyard     }
1612d13ada5dSCédric Le Goater }
16138bfffbccSCorey Minyard 
get_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16148bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs,
16158bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1616a580d820SCédric Le Goater                          RspBuffer *rsp)
16178bfffbccSCorey Minyard {
16188bfffbccSCorey Minyard     uint32_t val;
16198bfffbccSCorey Minyard     struct ipmi_time now;
16208bfffbccSCorey Minyard 
16218bfffbccSCorey Minyard     ipmi_gettime(&now);
16228bfffbccSCorey Minyard     val = now.tv_sec + ibs->sel.time_offset;
1623a580d820SCédric Le Goater     rsp_buffer_push(rsp, val & 0xff);
1624a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 8) & 0xff);
1625a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 16) & 0xff);
1626a580d820SCédric Le Goater     rsp_buffer_push(rsp, (val >> 24) & 0xff);
16278bfffbccSCorey Minyard }
16288bfffbccSCorey Minyard 
set_sel_time(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16298bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs,
16308bfffbccSCorey Minyard                          uint8_t *cmd, unsigned int cmd_len,
1631a580d820SCédric Le Goater                          RspBuffer *rsp)
16328bfffbccSCorey Minyard {
16338bfffbccSCorey Minyard     uint32_t val;
16348bfffbccSCorey Minyard     struct ipmi_time now;
16358bfffbccSCorey Minyard 
16368bfffbccSCorey Minyard     val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24);
16378bfffbccSCorey Minyard     ipmi_gettime(&now);
16388bfffbccSCorey Minyard     ibs->sel.time_offset = now.tv_sec - ((long) val);
16398bfffbccSCorey Minyard }
16408bfffbccSCorey Minyard 
platform_event_msg(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16419380d2edSCorey Minyard static void platform_event_msg(IPMIBmcSim *ibs,
16429380d2edSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
16439380d2edSCorey Minyard                                RspBuffer *rsp)
16449380d2edSCorey Minyard {
16459380d2edSCorey Minyard     uint8_t event[16];
16469380d2edSCorey Minyard 
16479380d2edSCorey Minyard     event[2] = 2; /* System event record */
16489380d2edSCorey Minyard     event[7] = cmd[2]; /* Generator ID */
16499380d2edSCorey Minyard     event[8] = 0;
16509380d2edSCorey Minyard     event[9] = cmd[3]; /* EvMRev */
16519380d2edSCorey Minyard     event[10] = cmd[4]; /* Sensor type */
16529380d2edSCorey Minyard     event[11] = cmd[5]; /* Sensor number */
16539380d2edSCorey Minyard     event[12] = cmd[6]; /* Event dir / Event type */
16549380d2edSCorey Minyard     event[13] = cmd[7]; /* Event data 1 */
16559380d2edSCorey Minyard     event[14] = cmd[8]; /* Event data 2 */
16569380d2edSCorey Minyard     event[15] = cmd[9]; /* Event data 3 */
16579380d2edSCorey Minyard 
16589380d2edSCorey Minyard     if (sel_add_event(ibs, event)) {
16599380d2edSCorey Minyard         rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE);
16609380d2edSCorey Minyard     }
16619380d2edSCorey Minyard }
16629380d2edSCorey Minyard 
set_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)16638bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs,
16648bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1665a580d820SCédric Le Goater                                   RspBuffer *rsp)
16668bfffbccSCorey Minyard {
16678bfffbccSCorey Minyard     IPMISensor *sens;
16688bfffbccSCorey Minyard 
166973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
16708bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
16716acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1672d13ada5dSCédric Le Goater         return;
16738bfffbccSCorey Minyard     }
16748bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
16758bfffbccSCorey Minyard     switch ((cmd[3] >> 4) & 0x3) {
16768bfffbccSCorey Minyard     case 0: /* Do not change */
16778bfffbccSCorey Minyard         break;
16788bfffbccSCorey Minyard     case 1: /* Enable bits */
16798bfffbccSCorey Minyard         if (cmd_len > 4) {
16808bfffbccSCorey Minyard             sens->assert_enable |= cmd[4];
16818bfffbccSCorey Minyard         }
16828bfffbccSCorey Minyard         if (cmd_len > 5) {
16838bfffbccSCorey Minyard             sens->assert_enable |= cmd[5] << 8;
16848bfffbccSCorey Minyard         }
16858bfffbccSCorey Minyard         if (cmd_len > 6) {
16868bfffbccSCorey Minyard             sens->deassert_enable |= cmd[6];
16878bfffbccSCorey Minyard         }
16888bfffbccSCorey Minyard         if (cmd_len > 7) {
16898bfffbccSCorey Minyard             sens->deassert_enable |= cmd[7] << 8;
16908bfffbccSCorey Minyard         }
16918bfffbccSCorey Minyard         break;
16928bfffbccSCorey Minyard     case 2: /* Disable bits */
16938bfffbccSCorey Minyard         if (cmd_len > 4) {
16948bfffbccSCorey Minyard             sens->assert_enable &= ~cmd[4];
16958bfffbccSCorey Minyard         }
16968bfffbccSCorey Minyard         if (cmd_len > 5) {
16978bfffbccSCorey Minyard             sens->assert_enable &= ~(cmd[5] << 8);
16988bfffbccSCorey Minyard         }
16998bfffbccSCorey Minyard         if (cmd_len > 6) {
17008bfffbccSCorey Minyard             sens->deassert_enable &= ~cmd[6];
17018bfffbccSCorey Minyard         }
17028bfffbccSCorey Minyard         if (cmd_len > 7) {
17038bfffbccSCorey Minyard             sens->deassert_enable &= ~(cmd[7] << 8);
17048bfffbccSCorey Minyard         }
17058bfffbccSCorey Minyard         break;
17068bfffbccSCorey Minyard     case 3:
17076acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1708d13ada5dSCédric Le Goater         return;
17098bfffbccSCorey Minyard     }
17108bfffbccSCorey Minyard     IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]);
17118bfffbccSCorey Minyard }
17128bfffbccSCorey Minyard 
get_sensor_evt_enable(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17138bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs,
17148bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1715a580d820SCédric Le Goater                                   RspBuffer *rsp)
17168bfffbccSCorey Minyard {
17178bfffbccSCorey Minyard     IPMISensor *sens;
17188bfffbccSCorey Minyard 
171973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17208bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17216acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1722d13ada5dSCédric Le Goater         return;
17238bfffbccSCorey Minyard     }
17248bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1725a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1726a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_enable & 0xff);
1727a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_enable >> 8) & 0xff);
1728a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_enable & 0xff);
1729a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_enable >> 8) & 0xff);
17308bfffbccSCorey Minyard }
17318bfffbccSCorey Minyard 
rearm_sensor_evts(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17328bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs,
17338bfffbccSCorey Minyard                               uint8_t *cmd, unsigned int cmd_len,
1734a580d820SCédric Le Goater                               RspBuffer *rsp)
17358bfffbccSCorey Minyard {
17368bfffbccSCorey Minyard     IPMISensor *sens;
17378bfffbccSCorey Minyard 
173873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17398bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17406acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1741d13ada5dSCédric Le Goater         return;
17428bfffbccSCorey Minyard     }
17438bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
17448bfffbccSCorey Minyard 
17458bfffbccSCorey Minyard     if ((cmd[3] & 0x80) == 0) {
17468bfffbccSCorey Minyard         /* Just clear everything */
17478bfffbccSCorey Minyard         sens->states = 0;
17488bfffbccSCorey Minyard         return;
17498bfffbccSCorey Minyard     }
1750d13ada5dSCédric Le Goater }
17518bfffbccSCorey Minyard 
get_sensor_evt_status(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17528bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs,
17538bfffbccSCorey Minyard                                   uint8_t *cmd, unsigned int cmd_len,
1754a580d820SCédric Le Goater                                   RspBuffer *rsp)
17558bfffbccSCorey Minyard {
17568bfffbccSCorey Minyard     IPMISensor *sens;
17578bfffbccSCorey Minyard 
175873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17598bfffbccSCorey Minyard         !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17606acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1761d13ada5dSCédric Le Goater         return;
17628bfffbccSCorey Minyard     }
17638bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1764a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1765a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1766a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->assert_states & 0xff);
1767a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->assert_states >> 8) & 0xff);
1768a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->deassert_states & 0xff);
1769a580d820SCédric Le Goater     rsp_buffer_push(rsp, (sens->deassert_states >> 8) & 0xff);
17708bfffbccSCorey Minyard }
17718bfffbccSCorey Minyard 
get_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)17728bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs,
17738bfffbccSCorey Minyard                                uint8_t *cmd, unsigned int cmd_len,
1774a580d820SCédric Le Goater                                RspBuffer *rsp)
17758bfffbccSCorey Minyard {
17768bfffbccSCorey Minyard     IPMISensor *sens;
17778bfffbccSCorey Minyard 
177873d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
17798bfffbccSCorey Minyard             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
17806acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1781d13ada5dSCédric Le Goater         return;
17828bfffbccSCorey Minyard     }
17838bfffbccSCorey Minyard     sens = ibs->sensors + cmd[2];
1784a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->reading);
1785a580d820SCédric Le Goater     rsp_buffer_push(rsp, IPMI_SENSOR_GET_RET_STATUS(sens));
1786a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->states & 0xff);
17878bfffbccSCorey Minyard     if (IPMI_SENSOR_IS_DISCRETE(sens)) {
1788a580d820SCédric Le Goater         rsp_buffer_push(rsp, (sens->states >> 8) & 0xff);
17898bfffbccSCorey Minyard     }
17908bfffbccSCorey Minyard }
17918bfffbccSCorey Minyard 
set_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1792728710e1SCédric Le Goater static void set_sensor_type(IPMIBmcSim *ibs,
1793728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1794a580d820SCédric Le Goater                             RspBuffer *rsp)
1795728710e1SCédric Le Goater {
1796728710e1SCédric Le Goater     IPMISensor *sens;
1797728710e1SCédric Le Goater 
1798728710e1SCédric Le Goater 
179973d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1800728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
18016acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1802728710e1SCédric Le Goater         return;
1803728710e1SCédric Le Goater     }
1804728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1805728710e1SCédric Le Goater     sens->sensor_type = cmd[3];
1806728710e1SCédric Le Goater     sens->evt_reading_type_code = cmd[4] & 0x7f;
1807728710e1SCédric Le Goater }
1808728710e1SCédric Le Goater 
get_sensor_type(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1809728710e1SCédric Le Goater static void get_sensor_type(IPMIBmcSim *ibs,
1810728710e1SCédric Le Goater                             uint8_t *cmd, unsigned int cmd_len,
1811a580d820SCédric Le Goater                             RspBuffer *rsp)
1812728710e1SCédric Le Goater {
1813728710e1SCédric Le Goater     IPMISensor *sens;
1814728710e1SCédric Le Goater 
1815728710e1SCédric Le Goater 
181673d60fa5SCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1817728710e1SCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
18186acb971aSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1819728710e1SCédric Le Goater         return;
1820728710e1SCédric Le Goater     }
1821728710e1SCédric Le Goater     sens = ibs->sensors + cmd[2];
1822a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->sensor_type);
1823a580d820SCédric Le Goater     rsp_buffer_push(rsp, sens->evt_reading_type_code);
1824728710e1SCédric Le Goater }
1825728710e1SCédric Le Goater 
1826e3f7320cSCédric Le Goater /*
1827e3f7320cSCédric Le Goater  * bytes   parameter
1828e3f7320cSCédric Le Goater  *    1    sensor number
1829e3f7320cSCédric Le Goater  *    2    operation (see below for bits meaning)
1830e3f7320cSCédric Le Goater  *    3    sensor reading
1831e3f7320cSCédric Le Goater  *  4:5    assertion states (optional)
1832e3f7320cSCédric Le Goater  *  6:7    deassertion states (optional)
1833e3f7320cSCédric Le Goater  *  8:10   event data 1,2,3 (optional)
1834e3f7320cSCédric Le Goater  */
set_sensor_reading(IPMIBmcSim * ibs,uint8_t * cmd,unsigned int cmd_len,RspBuffer * rsp)1835e3f7320cSCédric Le Goater static void set_sensor_reading(IPMIBmcSim *ibs,
1836e3f7320cSCédric Le Goater                                uint8_t *cmd, unsigned int cmd_len,
1837e3f7320cSCédric Le Goater                                RspBuffer *rsp)
1838e3f7320cSCédric Le Goater {
1839e3f7320cSCédric Le Goater     IPMISensor *sens;
1840e3f7320cSCédric Le Goater     uint8_t evd1 = 0;
1841e3f7320cSCédric Le Goater     uint8_t evd2 = 0;
1842e3f7320cSCédric Le Goater     uint8_t evd3 = 0;
1843e3f7320cSCédric Le Goater     uint8_t new_reading = 0;
1844e3f7320cSCédric Le Goater     uint16_t new_assert_states = 0;
1845e3f7320cSCédric Le Goater     uint16_t new_deassert_states = 0;
1846e3f7320cSCédric Le Goater     bool change_reading = false;
1847e3f7320cSCédric Le Goater     bool change_assert = false;
1848e3f7320cSCédric Le Goater     bool change_deassert = false;
1849e3f7320cSCédric Le Goater     enum {
1850e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_NONE,
1851e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_DATA,
1852e3f7320cSCédric Le Goater         SENSOR_GEN_EVENT_BMC,
1853e3f7320cSCédric Le Goater     } do_gen_event = SENSOR_GEN_EVENT_NONE;
1854e3f7320cSCédric Le Goater 
1855e3f7320cSCédric Le Goater     if ((cmd[2] >= MAX_SENSORS) ||
1856e3f7320cSCédric Le Goater             !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) {
1857e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_REQ_ENTRY_NOT_PRESENT);
1858e3f7320cSCédric Le Goater         return;
1859e3f7320cSCédric Le Goater     }
1860e3f7320cSCédric Le Goater 
1861e3f7320cSCédric Le Goater     sens = ibs->sensors + cmd[2];
1862e3f7320cSCédric Le Goater 
1863e3f7320cSCédric Le Goater     /* [1:0] Sensor Reading operation */
1864e3f7320cSCédric Le Goater     switch ((cmd[3]) & 0x3) {
1865e3f7320cSCédric Le Goater     case 0: /* Do not change */
1866e3f7320cSCédric Le Goater         break;
1867e3f7320cSCédric Le Goater     case 1: /* write given value to sensor reading byte */
1868e3f7320cSCédric Le Goater         new_reading = cmd[4];
1869e3f7320cSCédric Le Goater         if (sens->reading != new_reading) {
1870e3f7320cSCédric Le Goater             change_reading = true;
1871e3f7320cSCédric Le Goater         }
1872e3f7320cSCédric Le Goater         break;
1873e3f7320cSCédric Le Goater     case 2:
1874e3f7320cSCédric Le Goater     case 3:
1875e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1876e3f7320cSCédric Le Goater         return;
1877e3f7320cSCédric Le Goater     }
1878e3f7320cSCédric Le Goater 
1879e3f7320cSCédric Le Goater     /* [3:2] Deassertion bits operation */
1880e3f7320cSCédric Le Goater     switch ((cmd[3] >> 2) & 0x3) {
1881e3f7320cSCédric Le Goater     case 0: /* Do not change */
1882e3f7320cSCédric Le Goater         break;
1883e3f7320cSCédric Le Goater     case 1: /* write given value */
1884e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1885e3f7320cSCédric Le Goater             new_deassert_states = cmd[7];
1886e3f7320cSCédric Le Goater             change_deassert = true;
1887e3f7320cSCédric Le Goater         }
1888e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1889e3f7320cSCédric Le Goater             new_deassert_states |= (cmd[8] << 8);
1890e3f7320cSCédric Le Goater         }
1891e3f7320cSCédric Le Goater         break;
1892e3f7320cSCédric Le Goater 
1893e3f7320cSCédric Le Goater     case 2: /* mask on */
1894e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1895e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states | cmd[7]);
1896e3f7320cSCédric Le Goater             change_deassert = true;
1897e3f7320cSCédric Le Goater         }
1898e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1899e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states | (cmd[8] << 8));
1900e3f7320cSCédric Le Goater         }
1901e3f7320cSCédric Le Goater         break;
1902e3f7320cSCédric Le Goater 
1903e3f7320cSCédric Le Goater     case 3: /* mask off */
1904e3f7320cSCédric Le Goater         if (cmd_len > 7) {
1905e3f7320cSCédric Le Goater             new_deassert_states = (sens->deassert_states & cmd[7]);
1906e3f7320cSCédric Le Goater             change_deassert = true;
1907e3f7320cSCédric Le Goater         }
1908e3f7320cSCédric Le Goater         if (cmd_len > 8) {
1909e3f7320cSCédric Le Goater             new_deassert_states |= (sens->deassert_states & (cmd[8] << 8));
1910e3f7320cSCédric Le Goater         }
1911e3f7320cSCédric Le Goater         break;
1912e3f7320cSCédric Le Goater     }
1913e3f7320cSCédric Le Goater 
1914e3f7320cSCédric Le Goater     if (change_deassert && (new_deassert_states == sens->deassert_states)) {
1915e3f7320cSCédric Le Goater         change_deassert = false;
1916e3f7320cSCédric Le Goater     }
1917e3f7320cSCédric Le Goater 
1918e3f7320cSCédric Le Goater     /* [5:4] Assertion bits operation */
1919e3f7320cSCédric Le Goater     switch ((cmd[3] >> 4) & 0x3) {
1920e3f7320cSCédric Le Goater     case 0: /* Do not change */
1921e3f7320cSCédric Le Goater         break;
1922e3f7320cSCédric Le Goater     case 1: /* write given value */
1923e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1924e3f7320cSCédric Le Goater             new_assert_states = cmd[5];
1925e3f7320cSCédric Le Goater             change_assert = true;
1926e3f7320cSCédric Le Goater         }
1927e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1928e3f7320cSCédric Le Goater             new_assert_states |= (cmd[6] << 8);
1929e3f7320cSCédric Le Goater         }
1930e3f7320cSCédric Le Goater         break;
1931e3f7320cSCédric Le Goater 
1932e3f7320cSCédric Le Goater     case 2: /* mask on */
1933e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1934e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states | cmd[5]);
1935e3f7320cSCédric Le Goater             change_assert = true;
1936e3f7320cSCédric Le Goater         }
1937e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1938e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states | (cmd[6] << 8));
1939e3f7320cSCédric Le Goater         }
1940e3f7320cSCédric Le Goater         break;
1941e3f7320cSCédric Le Goater 
1942e3f7320cSCédric Le Goater     case 3: /* mask off */
1943e3f7320cSCédric Le Goater         if (cmd_len > 5) {
1944e3f7320cSCédric Le Goater             new_assert_states = (sens->assert_states & cmd[5]);
1945e3f7320cSCédric Le Goater             change_assert = true;
1946e3f7320cSCédric Le Goater         }
1947e3f7320cSCédric Le Goater         if (cmd_len > 6) {
1948e3f7320cSCédric Le Goater             new_assert_states |= (sens->assert_states & (cmd[6] << 8));
1949e3f7320cSCédric Le Goater         }
1950e3f7320cSCédric Le Goater         break;
1951e3f7320cSCédric Le Goater     }
1952e3f7320cSCédric Le Goater 
1953e3f7320cSCédric Le Goater     if (change_assert && (new_assert_states == sens->assert_states)) {
1954e3f7320cSCédric Le Goater         change_assert = false;
1955e3f7320cSCédric Le Goater     }
1956e3f7320cSCédric Le Goater 
1957e3f7320cSCédric Le Goater     if (cmd_len > 9) {
1958e3f7320cSCédric Le Goater         evd1 = cmd[9];
1959e3f7320cSCédric Le Goater     }
1960e3f7320cSCédric Le Goater     if (cmd_len > 10) {
1961e3f7320cSCédric Le Goater         evd2 = cmd[10];
1962e3f7320cSCédric Le Goater     }
1963e3f7320cSCédric Le Goater     if (cmd_len > 11) {
1964e3f7320cSCédric Le Goater         evd3 = cmd[11];
1965e3f7320cSCédric Le Goater     }
1966e3f7320cSCédric Le Goater 
1967e3f7320cSCédric Le Goater     /* [7:6] Event Data Bytes operation */
1968e3f7320cSCédric Le Goater     switch ((cmd[3] >> 6) & 0x3) {
1969e3f7320cSCédric Le Goater     case 0: /*
1970e3f7320cSCédric Le Goater              * Don’t use Event Data bytes from this command. BMC will
1971e3f7320cSCédric Le Goater              * generate it's own Event Data bytes based on its sensor
1972e3f7320cSCédric Le Goater              * implementation.
1973e3f7320cSCédric Le Goater              */
1974e3f7320cSCédric Le Goater         evd1 = evd2 = evd3 = 0x0;
1975e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_BMC;
1976e3f7320cSCédric Le Goater         break;
1977e3f7320cSCédric Le Goater     case 1: /*
1978e3f7320cSCédric Le Goater              * Write given values to event data bytes including bits
1979e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1980e3f7320cSCédric Le Goater              */
1981e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1982e3f7320cSCédric Le Goater         break;
1983e3f7320cSCédric Le Goater     case 2: /*
1984e3f7320cSCédric Le Goater              * Write given values to event data bytes excluding bits
1985e3f7320cSCédric Le Goater              * [3:0] Event Data 1.
1986e3f7320cSCédric Le Goater              */
1987e3f7320cSCédric Le Goater         evd1 &= 0xf0;
1988e3f7320cSCédric Le Goater         do_gen_event = SENSOR_GEN_EVENT_DATA;
1989e3f7320cSCédric Le Goater         break;
1990e3f7320cSCédric Le Goater     case 3:
1991e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
1992e3f7320cSCédric Le Goater         return;
1993e3f7320cSCédric Le Goater     }
1994e3f7320cSCédric Le Goater 
1995e3f7320cSCédric Le Goater     /*
1996e3f7320cSCédric Le Goater      * Event Data Bytes operation and parameter are inconsistent. The
1997e3f7320cSCédric Le Goater      * Specs are not clear on that topic but generating an error seems
1998e3f7320cSCédric Le Goater      * correct.
1999e3f7320cSCédric Le Goater      */
2000e3f7320cSCédric Le Goater     if (do_gen_event == SENSOR_GEN_EVENT_DATA && cmd_len < 10) {
2001e3f7320cSCédric Le Goater         rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD);
2002e3f7320cSCédric Le Goater         return;
2003e3f7320cSCédric Le Goater     }
2004e3f7320cSCédric Le Goater 
2005e3f7320cSCédric Le Goater     /* commit values */
2006e3f7320cSCédric Le Goater     if (change_reading) {
2007e3f7320cSCédric Le Goater         sens->reading = new_reading;
2008e3f7320cSCédric Le Goater     }
2009e3f7320cSCédric Le Goater 
2010e3f7320cSCédric Le Goater     if (change_assert) {
2011e3f7320cSCédric Le Goater         sens->assert_states = new_assert_states;
2012e3f7320cSCédric Le Goater     }
2013e3f7320cSCédric Le Goater 
2014e3f7320cSCédric Le Goater     if (change_deassert) {
2015e3f7320cSCédric Le Goater         sens->deassert_states = new_deassert_states;
2016e3f7320cSCédric Le Goater     }
2017e3f7320cSCédric Le Goater 
2018e3f7320cSCédric Le Goater     /* TODO: handle threshold sensor */
2019e3f7320cSCédric Le Goater     if (!IPMI_SENSOR_IS_DISCRETE(sens)) {
2020e3f7320cSCédric Le Goater         return;
2021e3f7320cSCédric Le Goater     }
2022e3f7320cSCédric Le Goater 
2023e3f7320cSCédric Le Goater     switch (do_gen_event) {
2024e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_DATA: {
2025e3f7320cSCédric Le Goater         unsigned int bit = evd1 & 0xf;
2026e3f7320cSCédric Le Goater         uint16_t mask = (1 << bit);
2027e3f7320cSCédric Le Goater 
2028e3f7320cSCédric Le Goater         if (sens->assert_states & mask & sens->assert_enable) {
2029e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 0, evd1, evd2, evd3);
2030e3f7320cSCédric Le Goater         }
2031e3f7320cSCédric Le Goater 
2032e3f7320cSCédric Le Goater         if (sens->deassert_states & mask & sens->deassert_enable) {
2033e3f7320cSCédric Le Goater             gen_event(ibs, cmd[2], 1, evd1, evd2, evd3);
2034e3f7320cSCédric Le Goater         }
2035e3f7320cSCédric Le Goater         break;
2036e3f7320cSCédric Le Goater     }
2037e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_BMC:
2038e3f7320cSCédric Le Goater         /*
2039e3f7320cSCédric Le Goater          * TODO: generate event and event data bytes depending on the
2040e3f7320cSCédric Le Goater          * sensor
2041e3f7320cSCédric Le Goater          */
2042e3f7320cSCédric Le Goater         break;
2043e3f7320cSCédric Le Goater     case SENSOR_GEN_EVENT_NONE:
2044e3f7320cSCédric Le Goater         break;
2045e3f7320cSCédric Le Goater     }
2046e3f7320cSCédric Le Goater }
2047728710e1SCédric Le Goater 
204862a4931dSCédric Le Goater static const IPMICmdHandler chassis_cmds[] = {
20494f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = { chassis_capabilities },
20504f298a4bSCédric Le Goater     [IPMI_CMD_GET_CHASSIS_STATUS] = { chassis_status },
20514f298a4bSCédric Le Goater     [IPMI_CMD_CHASSIS_CONTROL] = { chassis_control, 3 },
20524f298a4bSCédric Le Goater     [IPMI_CMD_GET_SYS_RESTART_CAUSE] = { chassis_get_sys_restart_cause }
20538bfffbccSCorey Minyard };
20548bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = {
205562a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(chassis_cmds),
20568bfffbccSCorey Minyard     .cmd_handlers = chassis_cmds
20578bfffbccSCorey Minyard };
20588bfffbccSCorey Minyard 
205962a4931dSCédric Le Goater static const IPMICmdHandler sensor_event_cmds[] = {
20609380d2edSCorey Minyard     [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 },
20614f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 },
20624f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 },
20634f298a4bSCédric Le Goater     [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 },
20644f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_EVT_STATUS] = { get_sensor_evt_status, 3 },
20654f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_READING] = { get_sensor_reading, 3 },
20664f298a4bSCédric Le Goater     [IPMI_CMD_SET_SENSOR_TYPE] = { set_sensor_type, 5 },
20674f298a4bSCédric Le Goater     [IPMI_CMD_GET_SENSOR_TYPE] = { get_sensor_type, 3 },
2068e3f7320cSCédric Le Goater     [IPMI_CMD_SET_SENSOR_READING] = { set_sensor_reading, 5 },
20698bfffbccSCorey Minyard };
20708bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = {
207162a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(sensor_event_cmds),
20728bfffbccSCorey Minyard     .cmd_handlers = sensor_event_cmds
20738bfffbccSCorey Minyard };
20748bfffbccSCorey Minyard 
207562a4931dSCédric Le Goater static const IPMICmdHandler app_cmds[] = {
20764f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_ID] = { get_device_id },
20774f298a4bSCédric Le Goater     [IPMI_CMD_COLD_RESET] = { cold_reset },
20784f298a4bSCédric Le Goater     [IPMI_CMD_WARM_RESET] = { warm_reset },
20794f298a4bSCédric Le Goater     [IPMI_CMD_SET_ACPI_POWER_STATE] = { set_acpi_power_state, 4 },
20804f298a4bSCédric Le Goater     [IPMI_CMD_GET_ACPI_POWER_STATE] = { get_acpi_power_state },
20814f298a4bSCédric Le Goater     [IPMI_CMD_GET_DEVICE_GUID] = { get_device_guid },
20824f298a4bSCédric Le Goater     [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = { set_bmc_global_enables, 3 },
20834f298a4bSCédric Le Goater     [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = { get_bmc_global_enables },
20844f298a4bSCédric Le Goater     [IPMI_CMD_CLR_MSG_FLAGS] = { clr_msg_flags, 3 },
20854f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG_FLAGS] = { get_msg_flags },
20864f298a4bSCédric Le Goater     [IPMI_CMD_GET_MSG] = { get_msg },
20874f298a4bSCédric Le Goater     [IPMI_CMD_SEND_MSG] = { send_msg, 3 },
20884f298a4bSCédric Le Goater     [IPMI_CMD_READ_EVT_MSG_BUF] = { read_evt_msg_buf },
20894f298a4bSCédric Le Goater     [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer },
20904f298a4bSCédric Le Goater     [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 },
20914f298a4bSCédric Le Goater     [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer },
20927f9e7af4SNicholas Piggin     [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 },
20938bfffbccSCorey Minyard };
20948bfffbccSCorey Minyard static const IPMINetfn app_netfn = {
209562a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(app_cmds),
20968bfffbccSCorey Minyard     .cmd_handlers = app_cmds
20978bfffbccSCorey Minyard };
20988bfffbccSCorey Minyard 
209962a4931dSCédric Le Goater static const IPMICmdHandler storage_cmds[] = {
2100540c07d3SCédric Le Goater     [IPMI_CMD_GET_FRU_AREA_INFO] = { get_fru_area_info, 3 },
2101540c07d3SCédric Le Goater     [IPMI_CMD_READ_FRU_DATA] = { read_fru_data, 5 },
2102540c07d3SCédric Le Goater     [IPMI_CMD_WRITE_FRU_DATA] = { write_fru_data, 5 },
21034f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR_REP_INFO] = { get_sdr_rep_info },
21044f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SDR_REP] = { reserve_sdr_rep },
21054f298a4bSCédric Le Goater     [IPMI_CMD_GET_SDR] = { get_sdr, 8 },
21064f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SDR] = { add_sdr },
21074f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SDR_REP] = { clear_sdr_rep, 8 },
21084f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_INFO] = { get_sel_info },
21094f298a4bSCédric Le Goater     [IPMI_CMD_RESERVE_SEL] = { reserve_sel },
21104f298a4bSCédric Le Goater     [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 },
21114f298a4bSCédric Le Goater     [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 },
21124f298a4bSCédric Le Goater     [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 },
21137f11cb65SCorey Minyard     [IPMI_CMD_GET_SEL_TIME] = { get_sel_time },
21147f11cb65SCorey Minyard     [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 },
21158bfffbccSCorey Minyard };
21168bfffbccSCorey Minyard 
21178bfffbccSCorey Minyard static const IPMINetfn storage_netfn = {
211862a4931dSCédric Le Goater     .cmd_nums = ARRAY_SIZE(storage_cmds),
21198bfffbccSCorey Minyard     .cmd_handlers = storage_cmds
21208bfffbccSCorey Minyard };
21218bfffbccSCorey Minyard 
register_cmds(IPMIBmcSim * s)21228bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s)
21238bfffbccSCorey Minyard {
2124ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn);
2125ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn);
2126ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_APP, &app_netfn);
2127ed8da05cSCédric Le Goater     ipmi_sim_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn);
21288bfffbccSCorey Minyard }
21298bfffbccSCorey Minyard 
21305167560bSCédric Le Goater static uint8_t init_sdrs[] = {
21318bfffbccSCorey Minyard     /* Watchdog device */
21328bfffbccSCorey Minyard     0x00, 0x00, 0x51, 0x02,   35, 0x20, 0x00, 0x00,
21338bfffbccSCorey Minyard     0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01,
21348bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21358bfffbccSCorey Minyard     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
21368bfffbccSCorey Minyard     'W',  'a',  't',  'c',  'h',  'd',  'o',  'g',
21378bfffbccSCorey Minyard };
21388bfffbccSCorey Minyard 
ipmi_sdr_init(IPMIBmcSim * ibs)21394fa9f08eSCédric Le Goater static void ipmi_sdr_init(IPMIBmcSim *ibs)
21404fa9f08eSCédric Le Goater {
21414fa9f08eSCédric Le Goater     unsigned int i;
21424fa9f08eSCédric Le Goater     int len;
21435167560bSCédric Le Goater     size_t sdrs_size;
21445167560bSCédric Le Goater     uint8_t *sdrs;
214552fc01d9SCédric Le Goater 
21465167560bSCédric Le Goater     sdrs_size = sizeof(init_sdrs);
21475167560bSCédric Le Goater     sdrs = init_sdrs;
21488c6fd7f3SCédric Le Goater     if (ibs->sdr_filename &&
21498c6fd7f3SCédric Le Goater         !g_file_get_contents(ibs->sdr_filename, (gchar **) &sdrs, &sdrs_size,
21508c6fd7f3SCédric Le Goater                              NULL)) {
21518c6fd7f3SCédric Le Goater         error_report("failed to load sdr file '%s'", ibs->sdr_filename);
21528c6fd7f3SCédric Le Goater         sdrs_size = sizeof(init_sdrs);
21538c6fd7f3SCédric Le Goater         sdrs = init_sdrs;
21548c6fd7f3SCédric Le Goater     }
21555167560bSCédric Le Goater 
21565167560bSCédric Le Goater     for (i = 0; i < sdrs_size; i += len) {
215752fc01d9SCédric Le Goater         struct ipmi_sdr_header *sdrh;
215852fc01d9SCédric Le Goater 
21595167560bSCédric Le Goater         if (i + IPMI_SDR_HEADER_SIZE > sdrs_size) {
21604fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
21618c6fd7f3SCédric Le Goater             break;
21624fa9f08eSCédric Le Goater         }
21635167560bSCédric Le Goater         sdrh = (struct ipmi_sdr_header *) &sdrs[i];
21644fa9f08eSCédric Le Goater         len = ipmi_sdr_length(sdrh);
21655167560bSCédric Le Goater         if (i + len > sdrs_size) {
21664fa9f08eSCédric Le Goater             error_report("Problem with recid 0x%4.4x", i);
21678c6fd7f3SCédric Le Goater             break;
21684fa9f08eSCédric Le Goater         }
21694fa9f08eSCédric Le Goater         sdr_add_entry(ibs, sdrh, len, NULL);
21704fa9f08eSCédric Le Goater     }
21718c6fd7f3SCédric Le Goater 
21728c6fd7f3SCédric Le Goater     if (sdrs != init_sdrs) {
21738c6fd7f3SCédric Le Goater         g_free(sdrs);
21748c6fd7f3SCédric Le Goater     }
21754fa9f08eSCédric Le Goater }
21764fa9f08eSCédric Le Goater 
2177bd66bcfcSCorey Minyard static const VMStateDescription vmstate_ipmi_sim = {
2178bd66bcfcSCorey Minyard     .name = TYPE_IPMI_BMC_SIMULATOR,
2179bd66bcfcSCorey Minyard     .version_id = 1,
2180bd66bcfcSCorey Minyard     .minimum_version_id = 1,
218109c6ac6dSRichard Henderson     .fields = (const VMStateField[]) {
2182bd66bcfcSCorey Minyard         VMSTATE_UINT8(bmc_global_enables, IPMIBmcSim),
2183bd66bcfcSCorey Minyard         VMSTATE_UINT8(msg_flags, IPMIBmcSim),
2184bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_initialized, IPMIBmcSim),
2185bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_use, IPMIBmcSim),
2186bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_action, IPMIBmcSim),
2187bd66bcfcSCorey Minyard         VMSTATE_UINT8(watchdog_pretimeout, IPMIBmcSim),
21889e744990SJinhua Cao         VMSTATE_UINT8(watchdog_expired, IPMIBmcSim),
2189bd66bcfcSCorey Minyard         VMSTATE_UINT16(watchdog_timeout, IPMIBmcSim),
2190bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_running, IPMIBmcSim),
2191bd66bcfcSCorey Minyard         VMSTATE_BOOL(watchdog_preaction_ran, IPMIBmcSim),
2192bd66bcfcSCorey Minyard         VMSTATE_INT64(watchdog_expiry, IPMIBmcSim),
2193bd66bcfcSCorey Minyard         VMSTATE_UINT8_ARRAY(evtbuf, IPMIBmcSim, 16),
2194bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].status, IPMIBmcSim),
2195bd66bcfcSCorey Minyard         VMSTATE_UINT8(sensors[IPMI_WATCHDOG_SENSOR].reading, IPMIBmcSim),
2196bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].states, IPMIBmcSim),
2197bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_states, IPMIBmcSim),
2198bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].deassert_states,
2199bd66bcfcSCorey Minyard                        IPMIBmcSim),
2200bd66bcfcSCorey Minyard         VMSTATE_UINT16(sensors[IPMI_WATCHDOG_SENSOR].assert_enable, IPMIBmcSim),
2201bd66bcfcSCorey Minyard         VMSTATE_END_OF_LIST()
2202bd66bcfcSCorey Minyard     }
2203bd66bcfcSCorey Minyard };
2204bd66bcfcSCorey Minyard 
ipmi_fru_init(IPMIFru * fru)2205540c07d3SCédric Le Goater static void ipmi_fru_init(IPMIFru *fru)
2206540c07d3SCédric Le Goater {
2207540c07d3SCédric Le Goater     int fsize;
2208540c07d3SCédric Le Goater     int size = 0;
2209540c07d3SCédric Le Goater 
2210540c07d3SCédric Le Goater     if (!fru->filename) {
2211540c07d3SCédric Le Goater         goto out;
2212540c07d3SCédric Le Goater     }
2213540c07d3SCédric Le Goater 
2214540c07d3SCédric Le Goater     fsize = get_image_size(fru->filename);
2215540c07d3SCédric Le Goater     if (fsize > 0) {
2216540c07d3SCédric Le Goater         size = QEMU_ALIGN_UP(fsize, fru->areasize);
2217540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2218540c07d3SCédric Le Goater         if (load_image_size(fru->filename, fru->data, fsize) != fsize) {
2219540c07d3SCédric Le Goater             error_report("Could not load file '%s'", fru->filename);
2220540c07d3SCédric Le Goater             g_free(fru->data);
2221540c07d3SCédric Le Goater             fru->data = NULL;
2222540c07d3SCédric Le Goater         }
2223540c07d3SCédric Le Goater     }
2224540c07d3SCédric Le Goater 
2225540c07d3SCédric Le Goater out:
2226540c07d3SCédric Le Goater     if (!fru->data) {
2227540c07d3SCédric Le Goater         /* give one default FRU */
2228540c07d3SCédric Le Goater         size = fru->areasize;
2229540c07d3SCédric Le Goater         fru->data = g_malloc0(size);
2230540c07d3SCédric Le Goater     }
2231540c07d3SCédric Le Goater 
2232540c07d3SCédric Le Goater     fru->nentries = size / fru->areasize;
2233540c07d3SCédric Le Goater }
2234540c07d3SCédric Le Goater 
ipmi_sim_realize(DeviceState * dev,Error ** errp)22350bc6001fSCédric Le Goater static void ipmi_sim_realize(DeviceState *dev, Error **errp)
22368bfffbccSCorey Minyard {
22370bc6001fSCédric Le Goater     IPMIBmc *b = IPMI_BMC(dev);
22388bfffbccSCorey Minyard     unsigned int i;
22398bfffbccSCorey Minyard     IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b);
22408bfffbccSCorey Minyard 
22418bfffbccSCorey Minyard     QTAILQ_INIT(&ibs->rcvbufs);
22428bfffbccSCorey Minyard 
22438bfffbccSCorey Minyard     ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT);
22448bfffbccSCorey Minyard     ibs->device_id = 0x20;
22458bfffbccSCorey Minyard     ibs->ipmi_version = 0x02; /* IPMI 2.0 */
2246b7088392SCédric Le Goater     ibs->restart_cause = 0;
22478bfffbccSCorey Minyard     for (i = 0; i < 4; i++) {
22488bfffbccSCorey Minyard         ibs->sel.last_addition[i] = 0xff;
22498bfffbccSCorey Minyard         ibs->sel.last_clear[i] = 0xff;
22508bfffbccSCorey Minyard         ibs->sdr.last_addition[i] = 0xff;
22518bfffbccSCorey Minyard         ibs->sdr.last_clear[i] = 0xff;
22528bfffbccSCorey Minyard     }
22538bfffbccSCorey Minyard 
22544fa9f08eSCédric Le Goater     ipmi_sdr_init(ibs);
22558bfffbccSCorey Minyard 
2256540c07d3SCédric Le Goater     ipmi_fru_init(&ibs->fru);
2257540c07d3SCédric Le Goater 
225852ba4d50SCédric Le Goater     ibs->acpi_power_state[0] = 0;
225952ba4d50SCédric Le Goater     ibs->acpi_power_state[1] = 0;
226052ba4d50SCédric Le Goater 
22618bfffbccSCorey Minyard     ipmi_init_sensors_from_sdrs(ibs);
22628bfffbccSCorey Minyard     register_cmds(ibs);
22638bfffbccSCorey Minyard 
22648bfffbccSCorey Minyard     ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs);
22658bfffbccSCorey Minyard }
22668bfffbccSCorey Minyard 
22672acf1403SRichard Henderson static const Property ipmi_sim_properties[] = {
2268540c07d3SCédric Le Goater     DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024),
2269540c07d3SCédric Le Goater     DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename),
22708c6fd7f3SCédric Le Goater     DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename),
227120b23364SCorey Minyard     DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20),
227220b23364SCorey Minyard     DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02),
227320b23364SCorey Minyard     DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0),
227420b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0),
227520b23364SCorey Minyard     DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0),
227620b23364SCorey Minyard     DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0),
227720b23364SCorey Minyard     DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0),
22787b0cd78bSCorey Minyard     DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid),
22798c6fd7f3SCédric Le Goater };
22808c6fd7f3SCédric Le Goater 
ipmi_sim_class_init(ObjectClass * oc,const void * data)2281*12d1a768SPhilippe Mathieu-Daudé static void ipmi_sim_class_init(ObjectClass *oc, const void *data)
22828bfffbccSCorey Minyard {
22830bc6001fSCédric Le Goater     DeviceClass *dc = DEVICE_CLASS(oc);
22848bfffbccSCorey Minyard     IPMIBmcClass *bk = IPMI_BMC_CLASS(oc);
22858bfffbccSCorey Minyard 
228666abfddbSCorey Minyard     dc->hotpluggable = false;
22870bc6001fSCédric Le Goater     dc->realize = ipmi_sim_realize;
2288d11d904cSCorey Minyard     dc->vmsd = &vmstate_ipmi_sim;
22894f67d30bSMarc-André Lureau     device_class_set_props(dc, ipmi_sim_properties);
22908bfffbccSCorey Minyard     bk->handle_command = ipmi_sim_handle_command;
22918bfffbccSCorey Minyard }
22928bfffbccSCorey Minyard 
22938bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = {
22948bfffbccSCorey Minyard     .name          = TYPE_IPMI_BMC_SIMULATOR,
22958bfffbccSCorey Minyard     .parent        = TYPE_IPMI_BMC,
22968bfffbccSCorey Minyard     .instance_size = sizeof(IPMIBmcSim),
22978bfffbccSCorey Minyard     .class_init    = ipmi_sim_class_init,
22988bfffbccSCorey Minyard };
22998bfffbccSCorey Minyard 
ipmi_sim_register_types(void)23008bfffbccSCorey Minyard static void ipmi_sim_register_types(void)
23018bfffbccSCorey Minyard {
23028bfffbccSCorey Minyard     type_register_static(&ipmi_sim_type);
23038bfffbccSCorey Minyard }
23048bfffbccSCorey Minyard 
23058bfffbccSCorey Minyard type_init(ipmi_sim_register_types)
2306