1*8bfffbccSCorey Minyard /* 2*8bfffbccSCorey Minyard * IPMI BMC emulation 3*8bfffbccSCorey Minyard * 4*8bfffbccSCorey Minyard * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC 5*8bfffbccSCorey Minyard * 6*8bfffbccSCorey Minyard * Permission is hereby granted, free of charge, to any person obtaining a copy 7*8bfffbccSCorey Minyard * of this software and associated documentation files (the "Software"), to deal 8*8bfffbccSCorey Minyard * in the Software without restriction, including without limitation the rights 9*8bfffbccSCorey Minyard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10*8bfffbccSCorey Minyard * copies of the Software, and to permit persons to whom the Software is 11*8bfffbccSCorey Minyard * furnished to do so, subject to the following conditions: 12*8bfffbccSCorey Minyard * 13*8bfffbccSCorey Minyard * The above copyright notice and this permission notice shall be included in 14*8bfffbccSCorey Minyard * all copies or substantial portions of the Software. 15*8bfffbccSCorey Minyard * 16*8bfffbccSCorey Minyard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*8bfffbccSCorey Minyard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*8bfffbccSCorey Minyard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19*8bfffbccSCorey Minyard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*8bfffbccSCorey Minyard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*8bfffbccSCorey Minyard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22*8bfffbccSCorey Minyard * THE SOFTWARE. 23*8bfffbccSCorey Minyard */ 24*8bfffbccSCorey Minyard 25*8bfffbccSCorey Minyard #include <stdio.h> 26*8bfffbccSCorey Minyard #include <string.h> 27*8bfffbccSCorey Minyard #include <stdint.h> 28*8bfffbccSCorey Minyard #include "qemu/timer.h" 29*8bfffbccSCorey Minyard #include "hw/ipmi/ipmi.h" 30*8bfffbccSCorey Minyard #include "qemu/error-report.h" 31*8bfffbccSCorey Minyard 32*8bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS 0x00 33*8bfffbccSCorey Minyard #define IPMI_NETFN_CHASSIS_MAXCMD 0x03 34*8bfffbccSCorey Minyard 35*8bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_CAPABILITIES 0x00 36*8bfffbccSCorey Minyard #define IPMI_CMD_GET_CHASSIS_STATUS 0x01 37*8bfffbccSCorey Minyard #define IPMI_CMD_CHASSIS_CONTROL 0x02 38*8bfffbccSCorey Minyard 39*8bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT 0x04 40*8bfffbccSCorey Minyard #define IPMI_NETFN_SENSOR_EVENT_MAXCMD 0x2e 41*8bfffbccSCorey Minyard 42*8bfffbccSCorey Minyard #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 43*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 44*8bfffbccSCorey Minyard #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a 45*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_EVT_STATUS 0x2b 46*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SENSOR_READING 0x2d 47*8bfffbccSCorey Minyard 48*8bfffbccSCorey Minyard /* #define IPMI_NETFN_APP 0x06 In ipmi.h */ 49*8bfffbccSCorey Minyard #define IPMI_NETFN_APP_MAXCMD 0x36 50*8bfffbccSCorey Minyard 51*8bfffbccSCorey Minyard #define IPMI_CMD_GET_DEVICE_ID 0x01 52*8bfffbccSCorey Minyard #define IPMI_CMD_COLD_RESET 0x02 53*8bfffbccSCorey Minyard #define IPMI_CMD_WARM_RESET 0x03 54*8bfffbccSCorey Minyard #define IPMI_CMD_RESET_WATCHDOG_TIMER 0x22 55*8bfffbccSCorey Minyard #define IPMI_CMD_SET_WATCHDOG_TIMER 0x24 56*8bfffbccSCorey Minyard #define IPMI_CMD_GET_WATCHDOG_TIMER 0x25 57*8bfffbccSCorey Minyard #define IPMI_CMD_SET_BMC_GLOBAL_ENABLES 0x2e 58*8bfffbccSCorey Minyard #define IPMI_CMD_GET_BMC_GLOBAL_ENABLES 0x2f 59*8bfffbccSCorey Minyard #define IPMI_CMD_CLR_MSG_FLAGS 0x30 60*8bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG_FLAGS 0x31 61*8bfffbccSCorey Minyard #define IPMI_CMD_GET_MSG 0x33 62*8bfffbccSCorey Minyard #define IPMI_CMD_SEND_MSG 0x34 63*8bfffbccSCorey Minyard #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 64*8bfffbccSCorey Minyard 65*8bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE 0x0a 66*8bfffbccSCorey Minyard #define IPMI_NETFN_STORAGE_MAXCMD 0x4a 67*8bfffbccSCorey Minyard 68*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_INFO 0x20 69*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_ALLOC_INFO 0x21 70*8bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SDR_REP 0x22 71*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR 0x23 72*8bfffbccSCorey Minyard #define IPMI_CMD_ADD_SDR 0x24 73*8bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SDR 0x25 74*8bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SDR 0x26 75*8bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SDR_REP 0x27 76*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SDR_REP_TIME 0x28 77*8bfffbccSCorey Minyard #define IPMI_CMD_SET_SDR_REP_TIME 0x29 78*8bfffbccSCorey Minyard #define IPMI_CMD_ENTER_SDR_REP_UPD_MODE 0x2A 79*8bfffbccSCorey Minyard #define IPMI_CMD_EXIT_SDR_REP_UPD_MODE 0x2B 80*8bfffbccSCorey Minyard #define IPMI_CMD_RUN_INIT_AGENT 0x2C 81*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_INFO 0x40 82*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ALLOC_INFO 0x41 83*8bfffbccSCorey Minyard #define IPMI_CMD_RESERVE_SEL 0x42 84*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_ENTRY 0x43 85*8bfffbccSCorey Minyard #define IPMI_CMD_ADD_SEL_ENTRY 0x44 86*8bfffbccSCorey Minyard #define IPMI_CMD_PARTIAL_ADD_SEL_ENTRY 0x45 87*8bfffbccSCorey Minyard #define IPMI_CMD_DELETE_SEL_ENTRY 0x46 88*8bfffbccSCorey Minyard #define IPMI_CMD_CLEAR_SEL 0x47 89*8bfffbccSCorey Minyard #define IPMI_CMD_GET_SEL_TIME 0x48 90*8bfffbccSCorey Minyard #define IPMI_CMD_SET_SEL_TIME 0x49 91*8bfffbccSCorey Minyard 92*8bfffbccSCorey Minyard 93*8bfffbccSCorey Minyard /* Same as a timespec struct. */ 94*8bfffbccSCorey Minyard struct ipmi_time { 95*8bfffbccSCorey Minyard long tv_sec; 96*8bfffbccSCorey Minyard long tv_nsec; 97*8bfffbccSCorey Minyard }; 98*8bfffbccSCorey Minyard 99*8bfffbccSCorey Minyard #define MAX_SEL_SIZE 128 100*8bfffbccSCorey Minyard 101*8bfffbccSCorey Minyard typedef struct IPMISel { 102*8bfffbccSCorey Minyard uint8_t sel[MAX_SEL_SIZE][16]; 103*8bfffbccSCorey Minyard unsigned int next_free; 104*8bfffbccSCorey Minyard long time_offset; 105*8bfffbccSCorey Minyard uint16_t reservation; 106*8bfffbccSCorey Minyard uint8_t last_addition[4]; 107*8bfffbccSCorey Minyard uint8_t last_clear[4]; 108*8bfffbccSCorey Minyard uint8_t overflow; 109*8bfffbccSCorey Minyard } IPMISel; 110*8bfffbccSCorey Minyard 111*8bfffbccSCorey Minyard #define MAX_SDR_SIZE 16384 112*8bfffbccSCorey Minyard 113*8bfffbccSCorey Minyard typedef struct IPMISdr { 114*8bfffbccSCorey Minyard uint8_t sdr[MAX_SDR_SIZE]; 115*8bfffbccSCorey Minyard unsigned int next_free; 116*8bfffbccSCorey Minyard uint16_t next_rec_id; 117*8bfffbccSCorey Minyard uint16_t reservation; 118*8bfffbccSCorey Minyard uint8_t last_addition[4]; 119*8bfffbccSCorey Minyard uint8_t last_clear[4]; 120*8bfffbccSCorey Minyard uint8_t overflow; 121*8bfffbccSCorey Minyard } IPMISdr; 122*8bfffbccSCorey Minyard 123*8bfffbccSCorey Minyard typedef struct IPMISensor { 124*8bfffbccSCorey Minyard uint8_t status; 125*8bfffbccSCorey Minyard uint8_t reading; 126*8bfffbccSCorey Minyard uint16_t states_suppt; 127*8bfffbccSCorey Minyard uint16_t assert_suppt; 128*8bfffbccSCorey Minyard uint16_t deassert_suppt; 129*8bfffbccSCorey Minyard uint16_t states; 130*8bfffbccSCorey Minyard uint16_t assert_states; 131*8bfffbccSCorey Minyard uint16_t deassert_states; 132*8bfffbccSCorey Minyard uint16_t assert_enable; 133*8bfffbccSCorey Minyard uint16_t deassert_enable; 134*8bfffbccSCorey Minyard uint8_t sensor_type; 135*8bfffbccSCorey Minyard uint8_t evt_reading_type_code; 136*8bfffbccSCorey Minyard } IPMISensor; 137*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_PRESENT(s) ((s)->status & 0x01) 138*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_PRESENT(s, v) ((s)->status = (s->status & ~0x01) | \ 139*8bfffbccSCorey Minyard !!(v)) 140*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_SCAN_ON(s) ((s)->status & 0x40) 141*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_SCAN_ON(s, v) ((s)->status = (s->status & ~0x40) | \ 142*8bfffbccSCorey Minyard ((!!(v)) << 6)) 143*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_EVENTS_ON(s) ((s)->status & 0x80) 144*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_EVENTS_ON(s, v) ((s)->status = (s->status & ~0x80) | \ 145*8bfffbccSCorey Minyard ((!!(v)) << 7)) 146*8bfffbccSCorey Minyard #define IPMI_SENSOR_GET_RET_STATUS(s) ((s)->status & 0xc0) 147*8bfffbccSCorey Minyard #define IPMI_SENSOR_SET_RET_STATUS(s, v) ((s)->status = (s->status & ~0xc0) | \ 148*8bfffbccSCorey Minyard (v & 0xc0)) 149*8bfffbccSCorey Minyard #define IPMI_SENSOR_IS_DISCRETE(s) ((s)->evt_reading_type_code != 1) 150*8bfffbccSCorey Minyard 151*8bfffbccSCorey Minyard #define MAX_SENSORS 20 152*8bfffbccSCorey Minyard #define IPMI_WATCHDOG_SENSOR 0 153*8bfffbccSCorey Minyard 154*8bfffbccSCorey Minyard typedef struct IPMIBmcSim IPMIBmcSim; 155*8bfffbccSCorey Minyard 156*8bfffbccSCorey Minyard #define MAX_NETFNS 64 157*8bfffbccSCorey Minyard typedef void (*IPMICmdHandler)(IPMIBmcSim *s, 158*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 159*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 160*8bfffbccSCorey Minyard unsigned int max_rsp_len); 161*8bfffbccSCorey Minyard typedef struct IPMINetfn { 162*8bfffbccSCorey Minyard unsigned int cmd_nums; 163*8bfffbccSCorey Minyard const IPMICmdHandler *cmd_handlers; 164*8bfffbccSCorey Minyard } IPMINetfn; 165*8bfffbccSCorey Minyard 166*8bfffbccSCorey Minyard typedef struct IPMIRcvBufEntry { 167*8bfffbccSCorey Minyard QTAILQ_ENTRY(IPMIRcvBufEntry) entry; 168*8bfffbccSCorey Minyard uint8_t len; 169*8bfffbccSCorey Minyard uint8_t buf[MAX_IPMI_MSG_SIZE]; 170*8bfffbccSCorey Minyard } IPMIRcvBufEntry; 171*8bfffbccSCorey Minyard 172*8bfffbccSCorey Minyard #define TYPE_IPMI_BMC_SIMULATOR "ipmi-bmc-sim" 173*8bfffbccSCorey Minyard #define IPMI_BMC_SIMULATOR(obj) OBJECT_CHECK(IPMIBmcSim, (obj), \ 174*8bfffbccSCorey Minyard TYPE_IPMI_BMC_SIMULATOR) 175*8bfffbccSCorey Minyard struct IPMIBmcSim { 176*8bfffbccSCorey Minyard IPMIBmc parent; 177*8bfffbccSCorey Minyard 178*8bfffbccSCorey Minyard QEMUTimer *timer; 179*8bfffbccSCorey Minyard 180*8bfffbccSCorey Minyard uint8_t bmc_global_enables; 181*8bfffbccSCorey Minyard uint8_t msg_flags; 182*8bfffbccSCorey Minyard 183*8bfffbccSCorey Minyard bool watchdog_initialized; 184*8bfffbccSCorey Minyard uint8_t watchdog_use; 185*8bfffbccSCorey Minyard uint8_t watchdog_action; 186*8bfffbccSCorey Minyard uint8_t watchdog_pretimeout; /* In seconds */ 187*8bfffbccSCorey Minyard bool watchdog_expired; 188*8bfffbccSCorey Minyard uint16_t watchdog_timeout; /* in 100's of milliseconds */ 189*8bfffbccSCorey Minyard 190*8bfffbccSCorey Minyard bool watchdog_running; 191*8bfffbccSCorey Minyard bool watchdog_preaction_ran; 192*8bfffbccSCorey Minyard int64_t watchdog_expiry; 193*8bfffbccSCorey Minyard 194*8bfffbccSCorey Minyard uint8_t device_id; 195*8bfffbccSCorey Minyard uint8_t ipmi_version; 196*8bfffbccSCorey Minyard uint8_t device_rev; 197*8bfffbccSCorey Minyard uint8_t fwrev1; 198*8bfffbccSCorey Minyard uint8_t fwrev2; 199*8bfffbccSCorey Minyard uint8_t mfg_id[3]; 200*8bfffbccSCorey Minyard uint8_t product_id[2]; 201*8bfffbccSCorey Minyard 202*8bfffbccSCorey Minyard IPMISel sel; 203*8bfffbccSCorey Minyard IPMISdr sdr; 204*8bfffbccSCorey Minyard IPMISensor sensors[MAX_SENSORS]; 205*8bfffbccSCorey Minyard 206*8bfffbccSCorey Minyard /* Odd netfns are for responses, so we only need the even ones. */ 207*8bfffbccSCorey Minyard const IPMINetfn *netfns[MAX_NETFNS / 2]; 208*8bfffbccSCorey Minyard 209*8bfffbccSCorey Minyard QemuMutex lock; 210*8bfffbccSCorey Minyard /* We allow one event in the buffer */ 211*8bfffbccSCorey Minyard uint8_t evtbuf[16]; 212*8bfffbccSCorey Minyard 213*8bfffbccSCorey Minyard QTAILQ_HEAD(, IPMIRcvBufEntry) rcvbufs; 214*8bfffbccSCorey Minyard }; 215*8bfffbccSCorey Minyard 216*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK (1 << 3) 217*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL (1 << 1) 218*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE (1 << 0) 219*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(s) \ 220*8bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK & (s)->msg_flags) 221*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(s) \ 222*8bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_EVT_BUF_FULL & (s)->msg_flags) 223*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ 224*8bfffbccSCorey Minyard (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) 225*8bfffbccSCorey Minyard 226*8bfffbccSCorey Minyard #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 227*8bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 228*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 229*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_BIT 3 230*8bfffbccSCorey Minyard #define IPMI_BMC_MSG_INTS_ON(s) ((s)->bmc_global_enables & \ 231*8bfffbccSCorey Minyard (1 << IPMI_BMC_RCV_MSG_QUEUE_INT_BIT)) 232*8bfffbccSCorey Minyard #define IPMI_BMC_EVBUF_FULL_INT_ENABLED(s) ((s)->bmc_global_enables & \ 233*8bfffbccSCorey Minyard (1 << IPMI_BMC_EVBUF_FULL_INT_BIT)) 234*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_LOG_ENABLED(s) ((s)->bmc_global_enables & \ 235*8bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_LOG_BIT)) 236*8bfffbccSCorey Minyard #define IPMI_BMC_EVENT_MSG_BUF_ENABLED(s) ((s)->bmc_global_enables & \ 237*8bfffbccSCorey Minyard (1 << IPMI_BMC_EVENT_MSG_BUF_BIT)) 238*8bfffbccSCorey Minyard 239*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_USE_MASK 0xc7 240*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_MASK 0x77 241*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_USE(s) ((s)->watchdog_use & 0x7) 242*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_LOG(s) (((s)->watchdog_use >> 7) & 0x1) 243*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_DONT_STOP(s) (((s)->watchdog_use >> 6) & 0x1) 244*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_PRE_ACTION(s) (((s)->watchdog_action >> 4) & 0x7) 245*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NONE 0 246*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_SMI 1 247*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_NMI 2 248*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_PRE_MSG_INT 3 249*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_GET_ACTION(s) ((s)->watchdog_action & 0x7) 250*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_NONE 0 251*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_RESET 1 252*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN 2 253*8bfffbccSCorey Minyard #define IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE 3 254*8bfffbccSCorey Minyard 255*8bfffbccSCorey Minyard 256*8bfffbccSCorey Minyard /* Add a byte to the response. */ 257*8bfffbccSCorey Minyard #define IPMI_ADD_RSP_DATA(b) \ 258*8bfffbccSCorey Minyard do { \ 259*8bfffbccSCorey Minyard if (*rsp_len >= max_rsp_len) { \ 260*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; \ 261*8bfffbccSCorey Minyard goto out; \ 262*8bfffbccSCorey Minyard } \ 263*8bfffbccSCorey Minyard rsp[(*rsp_len)++] = (b); \ 264*8bfffbccSCorey Minyard } while (0) 265*8bfffbccSCorey Minyard 266*8bfffbccSCorey Minyard /* Verify that the received command is a certain length. */ 267*8bfffbccSCorey Minyard #define IPMI_CHECK_CMD_LEN(l) \ 268*8bfffbccSCorey Minyard if (cmd_len < l) { \ 269*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; \ 270*8bfffbccSCorey Minyard goto out; \ 271*8bfffbccSCorey Minyard } 272*8bfffbccSCorey Minyard 273*8bfffbccSCorey Minyard /* Check that the reservation in the command is valid. */ 274*8bfffbccSCorey Minyard #define IPMI_CHECK_RESERVATION(off, r) \ 275*8bfffbccSCorey Minyard do { \ 276*8bfffbccSCorey Minyard if ((cmd[off] | (cmd[off + 1] << 8)) != r) { \ 277*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_RESERVATION; \ 278*8bfffbccSCorey Minyard goto out; \ 279*8bfffbccSCorey Minyard } \ 280*8bfffbccSCorey Minyard } while (0) 281*8bfffbccSCorey Minyard 282*8bfffbccSCorey Minyard 283*8bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs); 284*8bfffbccSCorey Minyard 285*8bfffbccSCorey Minyard static void ipmi_gettime(struct ipmi_time *time) 286*8bfffbccSCorey Minyard { 287*8bfffbccSCorey Minyard int64_t stime; 288*8bfffbccSCorey Minyard 289*8bfffbccSCorey Minyard stime = qemu_clock_get_ns(QEMU_CLOCK_HOST); 290*8bfffbccSCorey Minyard time->tv_sec = stime / 1000000000LL; 291*8bfffbccSCorey Minyard time->tv_nsec = stime % 1000000000LL; 292*8bfffbccSCorey Minyard } 293*8bfffbccSCorey Minyard 294*8bfffbccSCorey Minyard static int64_t ipmi_getmonotime(void) 295*8bfffbccSCorey Minyard { 296*8bfffbccSCorey Minyard return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 297*8bfffbccSCorey Minyard } 298*8bfffbccSCorey Minyard 299*8bfffbccSCorey Minyard static void ipmi_timeout(void *opaque) 300*8bfffbccSCorey Minyard { 301*8bfffbccSCorey Minyard IPMIBmcSim *ibs = opaque; 302*8bfffbccSCorey Minyard 303*8bfffbccSCorey Minyard ipmi_sim_handle_timeout(ibs); 304*8bfffbccSCorey Minyard } 305*8bfffbccSCorey Minyard 306*8bfffbccSCorey Minyard static void set_timestamp(IPMIBmcSim *ibs, uint8_t *ts) 307*8bfffbccSCorey Minyard { 308*8bfffbccSCorey Minyard unsigned int val; 309*8bfffbccSCorey Minyard struct ipmi_time now; 310*8bfffbccSCorey Minyard 311*8bfffbccSCorey Minyard ipmi_gettime(&now); 312*8bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 313*8bfffbccSCorey Minyard ts[0] = val & 0xff; 314*8bfffbccSCorey Minyard ts[1] = (val >> 8) & 0xff; 315*8bfffbccSCorey Minyard ts[2] = (val >> 16) & 0xff; 316*8bfffbccSCorey Minyard ts[3] = (val >> 24) & 0xff; 317*8bfffbccSCorey Minyard } 318*8bfffbccSCorey Minyard 319*8bfffbccSCorey Minyard static void sdr_inc_reservation(IPMISdr *sdr) 320*8bfffbccSCorey Minyard { 321*8bfffbccSCorey Minyard sdr->reservation++; 322*8bfffbccSCorey Minyard if (sdr->reservation == 0) { 323*8bfffbccSCorey Minyard sdr->reservation = 1; 324*8bfffbccSCorey Minyard } 325*8bfffbccSCorey Minyard } 326*8bfffbccSCorey Minyard 327*8bfffbccSCorey Minyard static int sdr_add_entry(IPMIBmcSim *ibs, const uint8_t *entry, 328*8bfffbccSCorey Minyard unsigned int len, uint16_t *recid) 329*8bfffbccSCorey Minyard { 330*8bfffbccSCorey Minyard if ((len < 5) || (len > 255)) { 331*8bfffbccSCorey Minyard return 1; 332*8bfffbccSCorey Minyard } 333*8bfffbccSCorey Minyard 334*8bfffbccSCorey Minyard if (entry[4] != len - 5) { 335*8bfffbccSCorey Minyard return 1; 336*8bfffbccSCorey Minyard } 337*8bfffbccSCorey Minyard 338*8bfffbccSCorey Minyard if (ibs->sdr.next_free + len > MAX_SDR_SIZE) { 339*8bfffbccSCorey Minyard ibs->sdr.overflow = 1; 340*8bfffbccSCorey Minyard return 1; 341*8bfffbccSCorey Minyard } 342*8bfffbccSCorey Minyard 343*8bfffbccSCorey Minyard memcpy(ibs->sdr.sdr + ibs->sdr.next_free, entry, len); 344*8bfffbccSCorey Minyard ibs->sdr.sdr[ibs->sdr.next_free] = ibs->sdr.next_rec_id & 0xff; 345*8bfffbccSCorey Minyard ibs->sdr.sdr[ibs->sdr.next_free+1] = (ibs->sdr.next_rec_id >> 8) & 0xff; 346*8bfffbccSCorey Minyard ibs->sdr.sdr[ibs->sdr.next_free+2] = 0x51; /* Conform to IPMI 1.5 spec */ 347*8bfffbccSCorey Minyard 348*8bfffbccSCorey Minyard if (recid) { 349*8bfffbccSCorey Minyard *recid = ibs->sdr.next_rec_id; 350*8bfffbccSCorey Minyard } 351*8bfffbccSCorey Minyard ibs->sdr.next_rec_id++; 352*8bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_addition); 353*8bfffbccSCorey Minyard ibs->sdr.next_free += len; 354*8bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 355*8bfffbccSCorey Minyard return 0; 356*8bfffbccSCorey Minyard } 357*8bfffbccSCorey Minyard 358*8bfffbccSCorey Minyard static int sdr_find_entry(IPMISdr *sdr, uint16_t recid, 359*8bfffbccSCorey Minyard unsigned int *retpos, uint16_t *nextrec) 360*8bfffbccSCorey Minyard { 361*8bfffbccSCorey Minyard unsigned int pos = *retpos; 362*8bfffbccSCorey Minyard 363*8bfffbccSCorey Minyard while (pos < sdr->next_free) { 364*8bfffbccSCorey Minyard uint16_t trec = sdr->sdr[pos] | (sdr->sdr[pos + 1] << 8); 365*8bfffbccSCorey Minyard unsigned int nextpos = pos + sdr->sdr[pos + 4]; 366*8bfffbccSCorey Minyard 367*8bfffbccSCorey Minyard if (trec == recid) { 368*8bfffbccSCorey Minyard if (nextrec) { 369*8bfffbccSCorey Minyard if (nextpos >= sdr->next_free) { 370*8bfffbccSCorey Minyard *nextrec = 0xffff; 371*8bfffbccSCorey Minyard } else { 372*8bfffbccSCorey Minyard *nextrec = (sdr->sdr[nextpos] | 373*8bfffbccSCorey Minyard (sdr->sdr[nextpos + 1] << 8)); 374*8bfffbccSCorey Minyard } 375*8bfffbccSCorey Minyard } 376*8bfffbccSCorey Minyard *retpos = pos; 377*8bfffbccSCorey Minyard return 0; 378*8bfffbccSCorey Minyard } 379*8bfffbccSCorey Minyard pos = nextpos; 380*8bfffbccSCorey Minyard } 381*8bfffbccSCorey Minyard return 1; 382*8bfffbccSCorey Minyard } 383*8bfffbccSCorey Minyard 384*8bfffbccSCorey Minyard static void sel_inc_reservation(IPMISel *sel) 385*8bfffbccSCorey Minyard { 386*8bfffbccSCorey Minyard sel->reservation++; 387*8bfffbccSCorey Minyard if (sel->reservation == 0) { 388*8bfffbccSCorey Minyard sel->reservation = 1; 389*8bfffbccSCorey Minyard } 390*8bfffbccSCorey Minyard } 391*8bfffbccSCorey Minyard 392*8bfffbccSCorey Minyard /* Returns 1 if the SEL is full and can't hold the event. */ 393*8bfffbccSCorey Minyard static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) 394*8bfffbccSCorey Minyard { 395*8bfffbccSCorey Minyard event[0] = 0xff; 396*8bfffbccSCorey Minyard event[1] = 0xff; 397*8bfffbccSCorey Minyard set_timestamp(ibs, event + 3); 398*8bfffbccSCorey Minyard if (ibs->sel.next_free == MAX_SEL_SIZE) { 399*8bfffbccSCorey Minyard ibs->sel.overflow = 1; 400*8bfffbccSCorey Minyard return 1; 401*8bfffbccSCorey Minyard } 402*8bfffbccSCorey Minyard event[0] = ibs->sel.next_free & 0xff; 403*8bfffbccSCorey Minyard event[1] = (ibs->sel.next_free >> 8) & 0xff; 404*8bfffbccSCorey Minyard memcpy(ibs->sel.last_addition, event + 3, 4); 405*8bfffbccSCorey Minyard memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); 406*8bfffbccSCorey Minyard ibs->sel.next_free++; 407*8bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 408*8bfffbccSCorey Minyard return 0; 409*8bfffbccSCorey Minyard } 410*8bfffbccSCorey Minyard 411*8bfffbccSCorey Minyard static int attn_set(IPMIBmcSim *ibs) 412*8bfffbccSCorey Minyard { 413*8bfffbccSCorey Minyard return IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs) 414*8bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs) 415*8bfffbccSCorey Minyard || IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK_SET(ibs); 416*8bfffbccSCorey Minyard } 417*8bfffbccSCorey Minyard 418*8bfffbccSCorey Minyard static int attn_irq_enabled(IPMIBmcSim *ibs) 419*8bfffbccSCorey Minyard { 420*8bfffbccSCorey Minyard return (IPMI_BMC_MSG_INTS_ON(ibs) && IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(ibs)) 421*8bfffbccSCorey Minyard || (IPMI_BMC_EVBUF_FULL_INT_ENABLED(ibs) && 422*8bfffbccSCorey Minyard IPMI_BMC_MSG_FLAG_EVT_BUF_FULL_SET(ibs)); 423*8bfffbccSCorey Minyard } 424*8bfffbccSCorey Minyard 425*8bfffbccSCorey Minyard static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, 426*8bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 427*8bfffbccSCorey Minyard { 428*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 429*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 430*8bfffbccSCorey Minyard uint8_t evt[16]; 431*8bfffbccSCorey Minyard IPMISensor *sens = ibs->sensors + sens_num; 432*8bfffbccSCorey Minyard 433*8bfffbccSCorey Minyard if (!IPMI_BMC_EVENT_MSG_BUF_ENABLED(ibs)) { 434*8bfffbccSCorey Minyard return; 435*8bfffbccSCorey Minyard } 436*8bfffbccSCorey Minyard if (!IPMI_SENSOR_GET_EVENTS_ON(sens)) { 437*8bfffbccSCorey Minyard return; 438*8bfffbccSCorey Minyard } 439*8bfffbccSCorey Minyard 440*8bfffbccSCorey Minyard evt[2] = 0x2; /* System event record */ 441*8bfffbccSCorey Minyard evt[7] = ibs->parent.slave_addr; 442*8bfffbccSCorey Minyard evt[8] = 0; 443*8bfffbccSCorey Minyard evt[9] = 0x04; /* Format version */ 444*8bfffbccSCorey Minyard evt[10] = sens->sensor_type; 445*8bfffbccSCorey Minyard evt[11] = sens_num; 446*8bfffbccSCorey Minyard evt[12] = sens->evt_reading_type_code | (!!deassert << 7); 447*8bfffbccSCorey Minyard evt[13] = evd1; 448*8bfffbccSCorey Minyard evt[14] = evd2; 449*8bfffbccSCorey Minyard evt[15] = evd3; 450*8bfffbccSCorey Minyard 451*8bfffbccSCorey Minyard if (IPMI_BMC_EVENT_LOG_ENABLED(ibs)) { 452*8bfffbccSCorey Minyard sel_add_event(ibs, evt); 453*8bfffbccSCorey Minyard } 454*8bfffbccSCorey Minyard 455*8bfffbccSCorey Minyard if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { 456*8bfffbccSCorey Minyard goto out; 457*8bfffbccSCorey Minyard } 458*8bfffbccSCorey Minyard 459*8bfffbccSCorey Minyard memcpy(ibs->evtbuf, evt, 16); 460*8bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 461*8bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 462*8bfffbccSCorey Minyard out: 463*8bfffbccSCorey Minyard return; 464*8bfffbccSCorey Minyard } 465*8bfffbccSCorey Minyard 466*8bfffbccSCorey Minyard static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, 467*8bfffbccSCorey Minyard unsigned int bit, unsigned int val, 468*8bfffbccSCorey Minyard uint8_t evd1, uint8_t evd2, uint8_t evd3) 469*8bfffbccSCorey Minyard { 470*8bfffbccSCorey Minyard IPMISensor *sens; 471*8bfffbccSCorey Minyard uint16_t mask; 472*8bfffbccSCorey Minyard 473*8bfffbccSCorey Minyard if (sensor >= MAX_SENSORS) { 474*8bfffbccSCorey Minyard return; 475*8bfffbccSCorey Minyard } 476*8bfffbccSCorey Minyard if (bit >= 16) { 477*8bfffbccSCorey Minyard return; 478*8bfffbccSCorey Minyard } 479*8bfffbccSCorey Minyard 480*8bfffbccSCorey Minyard mask = (1 << bit); 481*8bfffbccSCorey Minyard sens = ibs->sensors + sensor; 482*8bfffbccSCorey Minyard if (val) { 483*8bfffbccSCorey Minyard sens->states |= mask & sens->states_suppt; 484*8bfffbccSCorey Minyard if (sens->assert_states & mask) { 485*8bfffbccSCorey Minyard return; /* Already asserted */ 486*8bfffbccSCorey Minyard } 487*8bfffbccSCorey Minyard sens->assert_states |= mask & sens->assert_suppt; 488*8bfffbccSCorey Minyard if (sens->assert_enable & mask & sens->assert_states) { 489*8bfffbccSCorey Minyard /* Send an event on assert */ 490*8bfffbccSCorey Minyard gen_event(ibs, sensor, 0, evd1, evd2, evd3); 491*8bfffbccSCorey Minyard } 492*8bfffbccSCorey Minyard } else { 493*8bfffbccSCorey Minyard sens->states &= ~(mask & sens->states_suppt); 494*8bfffbccSCorey Minyard if (sens->deassert_states & mask) { 495*8bfffbccSCorey Minyard return; /* Already deasserted */ 496*8bfffbccSCorey Minyard } 497*8bfffbccSCorey Minyard sens->deassert_states |= mask & sens->deassert_suppt; 498*8bfffbccSCorey Minyard if (sens->deassert_enable & mask & sens->deassert_states) { 499*8bfffbccSCorey Minyard /* Send an event on deassert */ 500*8bfffbccSCorey Minyard gen_event(ibs, sensor, 1, evd1, evd2, evd3); 501*8bfffbccSCorey Minyard } 502*8bfffbccSCorey Minyard } 503*8bfffbccSCorey Minyard } 504*8bfffbccSCorey Minyard 505*8bfffbccSCorey Minyard static void ipmi_init_sensors_from_sdrs(IPMIBmcSim *s) 506*8bfffbccSCorey Minyard { 507*8bfffbccSCorey Minyard unsigned int i, pos; 508*8bfffbccSCorey Minyard IPMISensor *sens; 509*8bfffbccSCorey Minyard 510*8bfffbccSCorey Minyard for (i = 0; i < MAX_SENSORS; i++) { 511*8bfffbccSCorey Minyard memset(s->sensors + i, 0, sizeof(*sens)); 512*8bfffbccSCorey Minyard } 513*8bfffbccSCorey Minyard 514*8bfffbccSCorey Minyard pos = 0; 515*8bfffbccSCorey Minyard for (i = 0; !sdr_find_entry(&s->sdr, i, &pos, NULL); i++) { 516*8bfffbccSCorey Minyard uint8_t *sdr = s->sdr.sdr + pos; 517*8bfffbccSCorey Minyard unsigned int len = sdr[4]; 518*8bfffbccSCorey Minyard 519*8bfffbccSCorey Minyard if (len < 20) { 520*8bfffbccSCorey Minyard continue; 521*8bfffbccSCorey Minyard } 522*8bfffbccSCorey Minyard if ((sdr[3] < 1) || (sdr[3] > 2)) { 523*8bfffbccSCorey Minyard continue; /* Not a sensor SDR we set from */ 524*8bfffbccSCorey Minyard } 525*8bfffbccSCorey Minyard 526*8bfffbccSCorey Minyard if (sdr[7] > MAX_SENSORS) { 527*8bfffbccSCorey Minyard continue; 528*8bfffbccSCorey Minyard } 529*8bfffbccSCorey Minyard sens = s->sensors + sdr[7]; 530*8bfffbccSCorey Minyard 531*8bfffbccSCorey Minyard IPMI_SENSOR_SET_PRESENT(sens, 1); 532*8bfffbccSCorey Minyard IPMI_SENSOR_SET_SCAN_ON(sens, (sdr[10] >> 6) & 1); 533*8bfffbccSCorey Minyard IPMI_SENSOR_SET_EVENTS_ON(sens, (sdr[10] >> 5) & 1); 534*8bfffbccSCorey Minyard sens->assert_suppt = sdr[14] | (sdr[15] << 8); 535*8bfffbccSCorey Minyard sens->deassert_suppt = sdr[16] | (sdr[17] << 8); 536*8bfffbccSCorey Minyard sens->states_suppt = sdr[18] | (sdr[19] << 8); 537*8bfffbccSCorey Minyard sens->sensor_type = sdr[12]; 538*8bfffbccSCorey Minyard sens->evt_reading_type_code = sdr[13] & 0x7f; 539*8bfffbccSCorey Minyard 540*8bfffbccSCorey Minyard /* Enable all the events that are supported. */ 541*8bfffbccSCorey Minyard sens->assert_enable = sens->assert_suppt; 542*8bfffbccSCorey Minyard sens->deassert_enable = sens->deassert_suppt; 543*8bfffbccSCorey Minyard } 544*8bfffbccSCorey Minyard } 545*8bfffbccSCorey Minyard 546*8bfffbccSCorey Minyard static int ipmi_register_netfn(IPMIBmcSim *s, unsigned int netfn, 547*8bfffbccSCorey Minyard const IPMINetfn *netfnd) 548*8bfffbccSCorey Minyard { 549*8bfffbccSCorey Minyard if ((netfn & 1) || (netfn > MAX_NETFNS) || (s->netfns[netfn / 2])) { 550*8bfffbccSCorey Minyard return -1; 551*8bfffbccSCorey Minyard } 552*8bfffbccSCorey Minyard s->netfns[netfn / 2] = netfnd; 553*8bfffbccSCorey Minyard return 0; 554*8bfffbccSCorey Minyard } 555*8bfffbccSCorey Minyard 556*8bfffbccSCorey Minyard static void next_timeout(IPMIBmcSim *ibs) 557*8bfffbccSCorey Minyard { 558*8bfffbccSCorey Minyard int64_t next; 559*8bfffbccSCorey Minyard if (ibs->watchdog_running) { 560*8bfffbccSCorey Minyard next = ibs->watchdog_expiry; 561*8bfffbccSCorey Minyard } else { 562*8bfffbccSCorey Minyard /* Wait a minute */ 563*8bfffbccSCorey Minyard next = ipmi_getmonotime() + 60 * 1000000000LL; 564*8bfffbccSCorey Minyard } 565*8bfffbccSCorey Minyard timer_mod_ns(ibs->timer, next); 566*8bfffbccSCorey Minyard } 567*8bfffbccSCorey Minyard 568*8bfffbccSCorey Minyard static void ipmi_sim_handle_command(IPMIBmc *b, 569*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 570*8bfffbccSCorey Minyard unsigned int max_cmd_len, 571*8bfffbccSCorey Minyard uint8_t msg_id) 572*8bfffbccSCorey Minyard { 573*8bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 574*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 575*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 576*8bfffbccSCorey Minyard unsigned int netfn; 577*8bfffbccSCorey Minyard uint8_t rsp[MAX_IPMI_MSG_SIZE]; 578*8bfffbccSCorey Minyard unsigned int rsp_len_holder = 0; 579*8bfffbccSCorey Minyard unsigned int *rsp_len = &rsp_len_holder; 580*8bfffbccSCorey Minyard unsigned int max_rsp_len = sizeof(rsp); 581*8bfffbccSCorey Minyard 582*8bfffbccSCorey Minyard /* Set up the response, set the low bit of NETFN. */ 583*8bfffbccSCorey Minyard /* Note that max_rsp_len must be at least 3 */ 584*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[0] | 0x04); 585*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[1]); 586*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); /* Assume success */ 587*8bfffbccSCorey Minyard 588*8bfffbccSCorey Minyard /* If it's too short or it was truncated, return an error. */ 589*8bfffbccSCorey Minyard if (cmd_len < 2) { 590*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID; 591*8bfffbccSCorey Minyard goto out; 592*8bfffbccSCorey Minyard } 593*8bfffbccSCorey Minyard if (cmd_len > max_cmd_len) { 594*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQUEST_DATA_TRUNCATED; 595*8bfffbccSCorey Minyard goto out; 596*8bfffbccSCorey Minyard } 597*8bfffbccSCorey Minyard 598*8bfffbccSCorey Minyard if ((cmd[0] & 0x03) != 0) { 599*8bfffbccSCorey Minyard /* Only have stuff on LUN 0 */ 600*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_COMMAND_INVALID_FOR_LUN; 601*8bfffbccSCorey Minyard goto out; 602*8bfffbccSCorey Minyard } 603*8bfffbccSCorey Minyard 604*8bfffbccSCorey Minyard netfn = cmd[0] >> 2; 605*8bfffbccSCorey Minyard 606*8bfffbccSCorey Minyard /* Odd netfns are not valid, make sure the command is registered */ 607*8bfffbccSCorey Minyard if ((netfn & 1) || !ibs->netfns[netfn / 2] || 608*8bfffbccSCorey Minyard (cmd[1] >= ibs->netfns[netfn / 2]->cmd_nums) || 609*8bfffbccSCorey Minyard (!ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]])) { 610*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_CMD; 611*8bfffbccSCorey Minyard goto out; 612*8bfffbccSCorey Minyard } 613*8bfffbccSCorey Minyard 614*8bfffbccSCorey Minyard ibs->netfns[netfn / 2]->cmd_handlers[cmd[1]](ibs, cmd, cmd_len, rsp, rsp_len, 615*8bfffbccSCorey Minyard max_rsp_len); 616*8bfffbccSCorey Minyard 617*8bfffbccSCorey Minyard out: 618*8bfffbccSCorey Minyard k->handle_rsp(s, msg_id, rsp, *rsp_len); 619*8bfffbccSCorey Minyard 620*8bfffbccSCorey Minyard next_timeout(ibs); 621*8bfffbccSCorey Minyard } 622*8bfffbccSCorey Minyard 623*8bfffbccSCorey Minyard static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) 624*8bfffbccSCorey Minyard { 625*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 626*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 627*8bfffbccSCorey Minyard 628*8bfffbccSCorey Minyard if (!ibs->watchdog_running) { 629*8bfffbccSCorey Minyard goto out; 630*8bfffbccSCorey Minyard } 631*8bfffbccSCorey Minyard 632*8bfffbccSCorey Minyard if (!ibs->watchdog_preaction_ran) { 633*8bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs)) { 634*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 635*8bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 636*8bfffbccSCorey Minyard k->do_hw_op(s, IPMI_SEND_NMI, 0); 637*8bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 638*8bfffbccSCorey Minyard 0xc8, (2 << 4) | 0xf, 0xff); 639*8bfffbccSCorey Minyard break; 640*8bfffbccSCorey Minyard 641*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 642*8bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; 643*8bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 644*8bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, 645*8bfffbccSCorey Minyard 0xc8, (3 << 4) | 0xf, 0xff); 646*8bfffbccSCorey Minyard break; 647*8bfffbccSCorey Minyard 648*8bfffbccSCorey Minyard default: 649*8bfffbccSCorey Minyard goto do_full_expiry; 650*8bfffbccSCorey Minyard } 651*8bfffbccSCorey Minyard 652*8bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 1; 653*8bfffbccSCorey Minyard /* Issued the pretimeout, do the rest of the timeout now. */ 654*8bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 655*8bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_pretimeout * 1000000000LL; 656*8bfffbccSCorey Minyard goto out; 657*8bfffbccSCorey Minyard } 658*8bfffbccSCorey Minyard 659*8bfffbccSCorey Minyard do_full_expiry: 660*8bfffbccSCorey Minyard ibs->watchdog_running = 0; /* Stop the watchdog on a timeout */ 661*8bfffbccSCorey Minyard ibs->watchdog_expired |= (1 << IPMI_BMC_WATCHDOG_GET_USE(ibs)); 662*8bfffbccSCorey Minyard switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { 663*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 664*8bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, 665*8bfffbccSCorey Minyard 0xc0, ibs->watchdog_use & 0xf, 0xff); 666*8bfffbccSCorey Minyard break; 667*8bfffbccSCorey Minyard 668*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 669*8bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, 670*8bfffbccSCorey Minyard 0xc1, ibs->watchdog_use & 0xf, 0xff); 671*8bfffbccSCorey Minyard k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 672*8bfffbccSCorey Minyard break; 673*8bfffbccSCorey Minyard 674*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 675*8bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 676*8bfffbccSCorey Minyard 0xc2, ibs->watchdog_use & 0xf, 0xff); 677*8bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 678*8bfffbccSCorey Minyard break; 679*8bfffbccSCorey Minyard 680*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 681*8bfffbccSCorey Minyard sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, 682*8bfffbccSCorey Minyard 0xc3, ibs->watchdog_use & 0xf, 0xff); 683*8bfffbccSCorey Minyard k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 684*8bfffbccSCorey Minyard break; 685*8bfffbccSCorey Minyard } 686*8bfffbccSCorey Minyard 687*8bfffbccSCorey Minyard out: 688*8bfffbccSCorey Minyard next_timeout(ibs); 689*8bfffbccSCorey Minyard } 690*8bfffbccSCorey Minyard 691*8bfffbccSCorey Minyard static void chassis_capabilities(IPMIBmcSim *ibs, 692*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 693*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 694*8bfffbccSCorey Minyard unsigned int max_rsp_len) 695*8bfffbccSCorey Minyard { 696*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 697*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 698*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 699*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 700*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->parent.slave_addr); 701*8bfffbccSCorey Minyard out: 702*8bfffbccSCorey Minyard return; 703*8bfffbccSCorey Minyard } 704*8bfffbccSCorey Minyard 705*8bfffbccSCorey Minyard static void chassis_status(IPMIBmcSim *ibs, 706*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 707*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 708*8bfffbccSCorey Minyard unsigned int max_rsp_len) 709*8bfffbccSCorey Minyard { 710*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x61); /* Unknown power restore, power is on */ 711*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 712*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 713*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 714*8bfffbccSCorey Minyard out: 715*8bfffbccSCorey Minyard return; 716*8bfffbccSCorey Minyard } 717*8bfffbccSCorey Minyard 718*8bfffbccSCorey Minyard static void chassis_control(IPMIBmcSim *ibs, 719*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 720*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 721*8bfffbccSCorey Minyard unsigned int max_rsp_len) 722*8bfffbccSCorey Minyard { 723*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 724*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 725*8bfffbccSCorey Minyard 726*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 727*8bfffbccSCorey Minyard switch (cmd[2] & 0xf) { 728*8bfffbccSCorey Minyard case 0: /* power down */ 729*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); 730*8bfffbccSCorey Minyard break; 731*8bfffbccSCorey Minyard case 1: /* power up */ 732*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERON_CHASSIS, 0); 733*8bfffbccSCorey Minyard break; 734*8bfffbccSCorey Minyard case 2: /* power cycle */ 735*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); 736*8bfffbccSCorey Minyard break; 737*8bfffbccSCorey Minyard case 3: /* hard reset */ 738*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); 739*8bfffbccSCorey Minyard break; 740*8bfffbccSCorey Minyard case 4: /* pulse diagnostic interrupt */ 741*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_PULSE_DIAG_IRQ, 0); 742*8bfffbccSCorey Minyard break; 743*8bfffbccSCorey Minyard case 5: /* soft shutdown via ACPI by overtemp emulation */ 744*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, 745*8bfffbccSCorey Minyard IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP, 0); 746*8bfffbccSCorey Minyard break; 747*8bfffbccSCorey Minyard default: 748*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 749*8bfffbccSCorey Minyard goto out; 750*8bfffbccSCorey Minyard } 751*8bfffbccSCorey Minyard out: 752*8bfffbccSCorey Minyard return; 753*8bfffbccSCorey Minyard } 754*8bfffbccSCorey Minyard 755*8bfffbccSCorey Minyard static void get_device_id(IPMIBmcSim *ibs, 756*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 757*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 758*8bfffbccSCorey Minyard unsigned int max_rsp_len) 759*8bfffbccSCorey Minyard { 760*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_id); 761*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->device_rev & 0xf); 762*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev1 & 0x7f); 763*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->fwrev2); 764*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->ipmi_version); 765*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x07); /* sensor, SDR, and SEL. */ 766*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[0]); 767*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[1]); 768*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->mfg_id[2]); 769*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[0]); 770*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->product_id[1]); 771*8bfffbccSCorey Minyard out: 772*8bfffbccSCorey Minyard return; 773*8bfffbccSCorey Minyard } 774*8bfffbccSCorey Minyard 775*8bfffbccSCorey Minyard static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) 776*8bfffbccSCorey Minyard { 777*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 778*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 779*8bfffbccSCorey Minyard bool irqs_on; 780*8bfffbccSCorey Minyard 781*8bfffbccSCorey Minyard ibs->bmc_global_enables = val; 782*8bfffbccSCorey Minyard 783*8bfffbccSCorey Minyard irqs_on = val & (IPMI_BMC_EVBUF_FULL_INT_BIT | 784*8bfffbccSCorey Minyard IPMI_BMC_RCV_MSG_QUEUE_INT_BIT); 785*8bfffbccSCorey Minyard 786*8bfffbccSCorey Minyard k->set_irq_enable(s, irqs_on); 787*8bfffbccSCorey Minyard } 788*8bfffbccSCorey Minyard 789*8bfffbccSCorey Minyard static void cold_reset(IPMIBmcSim *ibs, 790*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 791*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 792*8bfffbccSCorey Minyard unsigned int max_rsp_len) 793*8bfffbccSCorey Minyard { 794*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 795*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 796*8bfffbccSCorey Minyard 797*8bfffbccSCorey Minyard /* Disable all interrupts */ 798*8bfffbccSCorey Minyard set_global_enables(ibs, 1 << IPMI_BMC_EVENT_LOG_BIT); 799*8bfffbccSCorey Minyard 800*8bfffbccSCorey Minyard if (k->reset) { 801*8bfffbccSCorey Minyard k->reset(s, true); 802*8bfffbccSCorey Minyard } 803*8bfffbccSCorey Minyard } 804*8bfffbccSCorey Minyard 805*8bfffbccSCorey Minyard static void warm_reset(IPMIBmcSim *ibs, 806*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 807*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 808*8bfffbccSCorey Minyard unsigned int max_rsp_len) 809*8bfffbccSCorey Minyard { 810*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 811*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 812*8bfffbccSCorey Minyard 813*8bfffbccSCorey Minyard if (k->reset) { 814*8bfffbccSCorey Minyard k->reset(s, false); 815*8bfffbccSCorey Minyard } 816*8bfffbccSCorey Minyard } 817*8bfffbccSCorey Minyard 818*8bfffbccSCorey Minyard static void set_bmc_global_enables(IPMIBmcSim *ibs, 819*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 820*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 821*8bfffbccSCorey Minyard unsigned int max_rsp_len) 822*8bfffbccSCorey Minyard { 823*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 824*8bfffbccSCorey Minyard set_global_enables(ibs, cmd[2]); 825*8bfffbccSCorey Minyard out: 826*8bfffbccSCorey Minyard return; 827*8bfffbccSCorey Minyard } 828*8bfffbccSCorey Minyard 829*8bfffbccSCorey Minyard static void get_bmc_global_enables(IPMIBmcSim *ibs, 830*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 831*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 832*8bfffbccSCorey Minyard unsigned int max_rsp_len) 833*8bfffbccSCorey Minyard { 834*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->bmc_global_enables); 835*8bfffbccSCorey Minyard out: 836*8bfffbccSCorey Minyard return; 837*8bfffbccSCorey Minyard } 838*8bfffbccSCorey Minyard 839*8bfffbccSCorey Minyard static void clr_msg_flags(IPMIBmcSim *ibs, 840*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 841*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 842*8bfffbccSCorey Minyard unsigned int max_rsp_len) 843*8bfffbccSCorey Minyard { 844*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 845*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 846*8bfffbccSCorey Minyard 847*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 848*8bfffbccSCorey Minyard ibs->msg_flags &= ~cmd[2]; 849*8bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 850*8bfffbccSCorey Minyard out: 851*8bfffbccSCorey Minyard return; 852*8bfffbccSCorey Minyard } 853*8bfffbccSCorey Minyard 854*8bfffbccSCorey Minyard static void get_msg_flags(IPMIBmcSim *ibs, 855*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 856*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 857*8bfffbccSCorey Minyard unsigned int max_rsp_len) 858*8bfffbccSCorey Minyard { 859*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->msg_flags); 860*8bfffbccSCorey Minyard out: 861*8bfffbccSCorey Minyard return; 862*8bfffbccSCorey Minyard } 863*8bfffbccSCorey Minyard 864*8bfffbccSCorey Minyard static void read_evt_msg_buf(IPMIBmcSim *ibs, 865*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 866*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 867*8bfffbccSCorey Minyard unsigned int max_rsp_len) 868*8bfffbccSCorey Minyard { 869*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 870*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 871*8bfffbccSCorey Minyard unsigned int i; 872*8bfffbccSCorey Minyard 873*8bfffbccSCorey Minyard if (!(ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL)) { 874*8bfffbccSCorey Minyard rsp[2] = 0x80; 875*8bfffbccSCorey Minyard goto out; 876*8bfffbccSCorey Minyard } 877*8bfffbccSCorey Minyard for (i = 0; i < 16; i++) { 878*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->evtbuf[i]); 879*8bfffbccSCorey Minyard } 880*8bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; 881*8bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 882*8bfffbccSCorey Minyard out: 883*8bfffbccSCorey Minyard return; 884*8bfffbccSCorey Minyard } 885*8bfffbccSCorey Minyard 886*8bfffbccSCorey Minyard static void get_msg(IPMIBmcSim *ibs, 887*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 888*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 889*8bfffbccSCorey Minyard unsigned int max_rsp_len) 890*8bfffbccSCorey Minyard { 891*8bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 892*8bfffbccSCorey Minyard 893*8bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 894*8bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 895*8bfffbccSCorey Minyard rsp[2] = 0x80; /* Queue empty */ 896*8bfffbccSCorey Minyard goto out; 897*8bfffbccSCorey Minyard } 898*8bfffbccSCorey Minyard rsp[3] = 0; /* Channel 0 */ 899*8bfffbccSCorey Minyard *rsp_len += 1; 900*8bfffbccSCorey Minyard msg = QTAILQ_FIRST(&ibs->rcvbufs); 901*8bfffbccSCorey Minyard memcpy(rsp + 4, msg->buf, msg->len); 902*8bfffbccSCorey Minyard *rsp_len += msg->len; 903*8bfffbccSCorey Minyard QTAILQ_REMOVE(&ibs->rcvbufs, msg, entry); 904*8bfffbccSCorey Minyard g_free(msg); 905*8bfffbccSCorey Minyard 906*8bfffbccSCorey Minyard if (QTAILQ_EMPTY(&ibs->rcvbufs)) { 907*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 908*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 909*8bfffbccSCorey Minyard 910*8bfffbccSCorey Minyard ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 911*8bfffbccSCorey Minyard k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); 912*8bfffbccSCorey Minyard } 913*8bfffbccSCorey Minyard 914*8bfffbccSCorey Minyard out: 915*8bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 916*8bfffbccSCorey Minyard return; 917*8bfffbccSCorey Minyard } 918*8bfffbccSCorey Minyard 919*8bfffbccSCorey Minyard static unsigned char 920*8bfffbccSCorey Minyard ipmb_checksum(unsigned char *data, int size, unsigned char csum) 921*8bfffbccSCorey Minyard { 922*8bfffbccSCorey Minyard for (; size > 0; size--, data++) { 923*8bfffbccSCorey Minyard csum += *data; 924*8bfffbccSCorey Minyard } 925*8bfffbccSCorey Minyard 926*8bfffbccSCorey Minyard return -csum; 927*8bfffbccSCorey Minyard } 928*8bfffbccSCorey Minyard 929*8bfffbccSCorey Minyard static void send_msg(IPMIBmcSim *ibs, 930*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 931*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 932*8bfffbccSCorey Minyard unsigned int max_rsp_len) 933*8bfffbccSCorey Minyard { 934*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 935*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 936*8bfffbccSCorey Minyard IPMIRcvBufEntry *msg; 937*8bfffbccSCorey Minyard uint8_t *buf; 938*8bfffbccSCorey Minyard uint8_t netfn, rqLun, rsLun, rqSeq; 939*8bfffbccSCorey Minyard 940*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 941*8bfffbccSCorey Minyard 942*8bfffbccSCorey Minyard if (cmd[2] != 0) { 943*8bfffbccSCorey Minyard /* We only handle channel 0 with no options */ 944*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 945*8bfffbccSCorey Minyard goto out; 946*8bfffbccSCorey Minyard } 947*8bfffbccSCorey Minyard 948*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(10); 949*8bfffbccSCorey Minyard if (cmd[3] != 0x40) { 950*8bfffbccSCorey Minyard /* We only emulate a MC at address 0x40. */ 951*8bfffbccSCorey Minyard rsp[2] = 0x83; /* NAK on write */ 952*8bfffbccSCorey Minyard goto out; 953*8bfffbccSCorey Minyard } 954*8bfffbccSCorey Minyard 955*8bfffbccSCorey Minyard cmd += 3; /* Skip the header. */ 956*8bfffbccSCorey Minyard cmd_len -= 3; 957*8bfffbccSCorey Minyard 958*8bfffbccSCorey Minyard /* 959*8bfffbccSCorey Minyard * At this point we "send" the message successfully. Any error will 960*8bfffbccSCorey Minyard * be returned in the response. 961*8bfffbccSCorey Minyard */ 962*8bfffbccSCorey Minyard if (ipmb_checksum(cmd, cmd_len, 0) != 0 || 963*8bfffbccSCorey Minyard cmd[3] != 0x20) { /* Improper response address */ 964*8bfffbccSCorey Minyard goto out; /* No response */ 965*8bfffbccSCorey Minyard } 966*8bfffbccSCorey Minyard 967*8bfffbccSCorey Minyard netfn = cmd[1] >> 2; 968*8bfffbccSCorey Minyard rqLun = cmd[4] & 0x3; 969*8bfffbccSCorey Minyard rsLun = cmd[1] & 0x3; 970*8bfffbccSCorey Minyard rqSeq = cmd[4] >> 2; 971*8bfffbccSCorey Minyard 972*8bfffbccSCorey Minyard if (rqLun != 2) { 973*8bfffbccSCorey Minyard /* We only support LUN 2 coming back to us. */ 974*8bfffbccSCorey Minyard goto out; 975*8bfffbccSCorey Minyard } 976*8bfffbccSCorey Minyard 977*8bfffbccSCorey Minyard msg = g_malloc(sizeof(*msg)); 978*8bfffbccSCorey Minyard msg->buf[0] = ((netfn | 1) << 2) | rqLun; /* NetFN, and make a response */ 979*8bfffbccSCorey Minyard msg->buf[1] = ipmb_checksum(msg->buf, 1, 0); 980*8bfffbccSCorey Minyard msg->buf[2] = cmd[0]; /* rsSA */ 981*8bfffbccSCorey Minyard msg->buf[3] = (rqSeq << 2) | rsLun; 982*8bfffbccSCorey Minyard msg->buf[4] = cmd[5]; /* Cmd */ 983*8bfffbccSCorey Minyard msg->buf[5] = 0; /* Completion Code */ 984*8bfffbccSCorey Minyard msg->len = 6; 985*8bfffbccSCorey Minyard 986*8bfffbccSCorey Minyard if ((cmd[1] >> 2) != IPMI_NETFN_APP || cmd[5] != IPMI_CMD_GET_DEVICE_ID) { 987*8bfffbccSCorey Minyard /* Not a command we handle. */ 988*8bfffbccSCorey Minyard msg->buf[5] = IPMI_CC_INVALID_CMD; 989*8bfffbccSCorey Minyard goto end_msg; 990*8bfffbccSCorey Minyard } 991*8bfffbccSCorey Minyard 992*8bfffbccSCorey Minyard buf = msg->buf + msg->len; /* After the CC */ 993*8bfffbccSCorey Minyard buf[0] = 0; 994*8bfffbccSCorey Minyard buf[1] = 0; 995*8bfffbccSCorey Minyard buf[2] = 0; 996*8bfffbccSCorey Minyard buf[3] = 0; 997*8bfffbccSCorey Minyard buf[4] = 0x51; 998*8bfffbccSCorey Minyard buf[5] = 0; 999*8bfffbccSCorey Minyard buf[6] = 0; 1000*8bfffbccSCorey Minyard buf[7] = 0; 1001*8bfffbccSCorey Minyard buf[8] = 0; 1002*8bfffbccSCorey Minyard buf[9] = 0; 1003*8bfffbccSCorey Minyard buf[10] = 0; 1004*8bfffbccSCorey Minyard msg->len += 11; 1005*8bfffbccSCorey Minyard 1006*8bfffbccSCorey Minyard end_msg: 1007*8bfffbccSCorey Minyard msg->buf[msg->len] = ipmb_checksum(msg->buf, msg->len, 0); 1008*8bfffbccSCorey Minyard msg->len++; 1009*8bfffbccSCorey Minyard qemu_mutex_lock(&ibs->lock); 1010*8bfffbccSCorey Minyard QTAILQ_INSERT_TAIL(&ibs->rcvbufs, msg, entry); 1011*8bfffbccSCorey Minyard ibs->msg_flags |= IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; 1012*8bfffbccSCorey Minyard k->set_atn(s, 1, attn_irq_enabled(ibs)); 1013*8bfffbccSCorey Minyard qemu_mutex_unlock(&ibs->lock); 1014*8bfffbccSCorey Minyard 1015*8bfffbccSCorey Minyard out: 1016*8bfffbccSCorey Minyard return; 1017*8bfffbccSCorey Minyard } 1018*8bfffbccSCorey Minyard 1019*8bfffbccSCorey Minyard static void do_watchdog_reset(IPMIBmcSim *ibs) 1020*8bfffbccSCorey Minyard { 1021*8bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_ACTION(ibs) == 1022*8bfffbccSCorey Minyard IPMI_BMC_WATCHDOG_ACTION_NONE) { 1023*8bfffbccSCorey Minyard ibs->watchdog_running = 0; 1024*8bfffbccSCorey Minyard return; 1025*8bfffbccSCorey Minyard } 1026*8bfffbccSCorey Minyard ibs->watchdog_preaction_ran = 0; 1027*8bfffbccSCorey Minyard 1028*8bfffbccSCorey Minyard 1029*8bfffbccSCorey Minyard /* Timeout is in tenths of a second, offset is in seconds */ 1030*8bfffbccSCorey Minyard ibs->watchdog_expiry = ipmi_getmonotime(); 1031*8bfffbccSCorey Minyard ibs->watchdog_expiry += ibs->watchdog_timeout * 100000000LL; 1032*8bfffbccSCorey Minyard if (IPMI_BMC_WATCHDOG_GET_PRE_ACTION(ibs) != IPMI_BMC_WATCHDOG_PRE_NONE) { 1033*8bfffbccSCorey Minyard ibs->watchdog_expiry -= ibs->watchdog_pretimeout * 1000000000LL; 1034*8bfffbccSCorey Minyard } 1035*8bfffbccSCorey Minyard ibs->watchdog_running = 1; 1036*8bfffbccSCorey Minyard } 1037*8bfffbccSCorey Minyard 1038*8bfffbccSCorey Minyard static void reset_watchdog_timer(IPMIBmcSim *ibs, 1039*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1040*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1041*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1042*8bfffbccSCorey Minyard { 1043*8bfffbccSCorey Minyard if (!ibs->watchdog_initialized) { 1044*8bfffbccSCorey Minyard rsp[2] = 0x80; 1045*8bfffbccSCorey Minyard goto out; 1046*8bfffbccSCorey Minyard } 1047*8bfffbccSCorey Minyard do_watchdog_reset(ibs); 1048*8bfffbccSCorey Minyard out: 1049*8bfffbccSCorey Minyard return; 1050*8bfffbccSCorey Minyard } 1051*8bfffbccSCorey Minyard 1052*8bfffbccSCorey Minyard static void set_watchdog_timer(IPMIBmcSim *ibs, 1053*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1054*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1055*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1056*8bfffbccSCorey Minyard { 1057*8bfffbccSCorey Minyard IPMIInterface *s = ibs->parent.intf; 1058*8bfffbccSCorey Minyard IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); 1059*8bfffbccSCorey Minyard unsigned int val; 1060*8bfffbccSCorey Minyard 1061*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 1062*8bfffbccSCorey Minyard val = cmd[2] & 0x7; /* Validate use */ 1063*8bfffbccSCorey Minyard if (val == 0 || val > 5) { 1064*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1065*8bfffbccSCorey Minyard goto out; 1066*8bfffbccSCorey Minyard } 1067*8bfffbccSCorey Minyard val = cmd[3] & 0x7; /* Validate action */ 1068*8bfffbccSCorey Minyard switch (val) { 1069*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_NONE: 1070*8bfffbccSCorey Minyard break; 1071*8bfffbccSCorey Minyard 1072*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_RESET: 1073*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_RESET_CHASSIS, 1); 1074*8bfffbccSCorey Minyard break; 1075*8bfffbccSCorey Minyard 1076*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: 1077*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 1); 1078*8bfffbccSCorey Minyard break; 1079*8bfffbccSCorey Minyard 1080*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: 1081*8bfffbccSCorey Minyard rsp[2] = k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 1); 1082*8bfffbccSCorey Minyard break; 1083*8bfffbccSCorey Minyard 1084*8bfffbccSCorey Minyard default: 1085*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1086*8bfffbccSCorey Minyard } 1087*8bfffbccSCorey Minyard if (rsp[2]) { 1088*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1089*8bfffbccSCorey Minyard goto out; 1090*8bfffbccSCorey Minyard } 1091*8bfffbccSCorey Minyard 1092*8bfffbccSCorey Minyard val = (cmd[3] >> 4) & 0x7; /* Validate preaction */ 1093*8bfffbccSCorey Minyard switch (val) { 1094*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_MSG_INT: 1095*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NONE: 1096*8bfffbccSCorey Minyard break; 1097*8bfffbccSCorey Minyard 1098*8bfffbccSCorey Minyard case IPMI_BMC_WATCHDOG_PRE_NMI: 1099*8bfffbccSCorey Minyard if (!k->do_hw_op(s, IPMI_SEND_NMI, 1)) { 1100*8bfffbccSCorey Minyard /* NMI not supported. */ 1101*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1102*8bfffbccSCorey Minyard goto out; 1103*8bfffbccSCorey Minyard } 1104*8bfffbccSCorey Minyard default: 1105*8bfffbccSCorey Minyard /* We don't support PRE_SMI */ 1106*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1107*8bfffbccSCorey Minyard goto out; 1108*8bfffbccSCorey Minyard } 1109*8bfffbccSCorey Minyard 1110*8bfffbccSCorey Minyard ibs->watchdog_initialized = 1; 1111*8bfffbccSCorey Minyard ibs->watchdog_use = cmd[2] & IPMI_BMC_WATCHDOG_USE_MASK; 1112*8bfffbccSCorey Minyard ibs->watchdog_action = cmd[3] & IPMI_BMC_WATCHDOG_ACTION_MASK; 1113*8bfffbccSCorey Minyard ibs->watchdog_pretimeout = cmd[4]; 1114*8bfffbccSCorey Minyard ibs->watchdog_expired &= ~cmd[5]; 1115*8bfffbccSCorey Minyard ibs->watchdog_timeout = cmd[6] | (((uint16_t) cmd[7]) << 8); 1116*8bfffbccSCorey Minyard if (ibs->watchdog_running & IPMI_BMC_WATCHDOG_GET_DONT_STOP(ibs)) { 1117*8bfffbccSCorey Minyard do_watchdog_reset(ibs); 1118*8bfffbccSCorey Minyard } else { 1119*8bfffbccSCorey Minyard ibs->watchdog_running = 0; 1120*8bfffbccSCorey Minyard } 1121*8bfffbccSCorey Minyard out: 1122*8bfffbccSCorey Minyard return; 1123*8bfffbccSCorey Minyard } 1124*8bfffbccSCorey Minyard 1125*8bfffbccSCorey Minyard static void get_watchdog_timer(IPMIBmcSim *ibs, 1126*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1127*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1128*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1129*8bfffbccSCorey Minyard { 1130*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_use); 1131*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_action); 1132*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_pretimeout); 1133*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->watchdog_expired); 1134*8bfffbccSCorey Minyard if (ibs->watchdog_running) { 1135*8bfffbccSCorey Minyard long timeout; 1136*8bfffbccSCorey Minyard timeout = ((ibs->watchdog_expiry - ipmi_getmonotime() + 50000000) 1137*8bfffbccSCorey Minyard / 100000000); 1138*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(timeout & 0xff); 1139*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((timeout >> 8) & 0xff); 1140*8bfffbccSCorey Minyard } else { 1141*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 1142*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0); 1143*8bfffbccSCorey Minyard } 1144*8bfffbccSCorey Minyard out: 1145*8bfffbccSCorey Minyard return; 1146*8bfffbccSCorey Minyard } 1147*8bfffbccSCorey Minyard 1148*8bfffbccSCorey Minyard static void get_sdr_rep_info(IPMIBmcSim *ibs, 1149*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1150*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1151*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1152*8bfffbccSCorey Minyard { 1153*8bfffbccSCorey Minyard unsigned int i; 1154*8bfffbccSCorey Minyard 1155*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 spec */ 1156*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.next_rec_id & 0xff); 1157*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.next_rec_id >> 8) & 0xff); 1158*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((MAX_SDR_SIZE - ibs->sdr.next_free) & 0xff); 1159*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((MAX_SDR_SIZE - ibs->sdr.next_free) >> 8) & 0xff); 1160*8bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1161*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_addition[i]); 1162*8bfffbccSCorey Minyard } 1163*8bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1164*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.last_clear[i]); 1165*8bfffbccSCorey Minyard } 1166*8bfffbccSCorey Minyard /* Only modal support, reserve supported */ 1167*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.overflow << 7) | 0x22); 1168*8bfffbccSCorey Minyard out: 1169*8bfffbccSCorey Minyard return; 1170*8bfffbccSCorey Minyard } 1171*8bfffbccSCorey Minyard 1172*8bfffbccSCorey Minyard static void reserve_sdr_rep(IPMIBmcSim *ibs, 1173*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1174*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1175*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1176*8bfffbccSCorey Minyard { 1177*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sdr.reservation & 0xff); 1178*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sdr.reservation >> 8) & 0xff); 1179*8bfffbccSCorey Minyard out: 1180*8bfffbccSCorey Minyard return; 1181*8bfffbccSCorey Minyard } 1182*8bfffbccSCorey Minyard 1183*8bfffbccSCorey Minyard static void get_sdr(IPMIBmcSim *ibs, 1184*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1185*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1186*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1187*8bfffbccSCorey Minyard { 1188*8bfffbccSCorey Minyard unsigned int pos; 1189*8bfffbccSCorey Minyard uint16_t nextrec; 1190*8bfffbccSCorey Minyard 1191*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 1192*8bfffbccSCorey Minyard if (cmd[6]) { 1193*8bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 1194*8bfffbccSCorey Minyard } 1195*8bfffbccSCorey Minyard pos = 0; 1196*8bfffbccSCorey Minyard if (sdr_find_entry(&ibs->sdr, cmd[4] | (cmd[5] << 8), 1197*8bfffbccSCorey Minyard &pos, &nextrec)) { 1198*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1199*8bfffbccSCorey Minyard goto out; 1200*8bfffbccSCorey Minyard } 1201*8bfffbccSCorey Minyard if (cmd[6] > (ibs->sdr.sdr[pos + 4])) { 1202*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_PARM_OUT_OF_RANGE; 1203*8bfffbccSCorey Minyard goto out; 1204*8bfffbccSCorey Minyard } 1205*8bfffbccSCorey Minyard 1206*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(nextrec & 0xff); 1207*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((nextrec >> 8) & 0xff); 1208*8bfffbccSCorey Minyard 1209*8bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1210*8bfffbccSCorey Minyard cmd[7] = ibs->sdr.sdr[pos + 4] - cmd[6]; 1211*8bfffbccSCorey Minyard } 1212*8bfffbccSCorey Minyard 1213*8bfffbccSCorey Minyard if ((cmd[7] + *rsp_len) > max_rsp_len) { 1214*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES; 1215*8bfffbccSCorey Minyard goto out; 1216*8bfffbccSCorey Minyard } 1217*8bfffbccSCorey Minyard memcpy(rsp + *rsp_len, ibs->sdr.sdr + pos + cmd[6], cmd[7]); 1218*8bfffbccSCorey Minyard *rsp_len += cmd[7]; 1219*8bfffbccSCorey Minyard out: 1220*8bfffbccSCorey Minyard return; 1221*8bfffbccSCorey Minyard } 1222*8bfffbccSCorey Minyard 1223*8bfffbccSCorey Minyard static void add_sdr(IPMIBmcSim *ibs, 1224*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1225*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1226*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1227*8bfffbccSCorey Minyard { 1228*8bfffbccSCorey Minyard uint16_t recid; 1229*8bfffbccSCorey Minyard 1230*8bfffbccSCorey Minyard if (sdr_add_entry(ibs, cmd + 2, cmd_len - 2, &recid)) { 1231*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1232*8bfffbccSCorey Minyard goto out; 1233*8bfffbccSCorey Minyard } 1234*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(recid & 0xff); 1235*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((recid >> 8) & 0xff); 1236*8bfffbccSCorey Minyard out: 1237*8bfffbccSCorey Minyard return; 1238*8bfffbccSCorey Minyard } 1239*8bfffbccSCorey Minyard 1240*8bfffbccSCorey Minyard static void clear_sdr_rep(IPMIBmcSim *ibs, 1241*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1242*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1243*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1244*8bfffbccSCorey Minyard { 1245*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 1246*8bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sdr.reservation); 1247*8bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 1248*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1249*8bfffbccSCorey Minyard goto out; 1250*8bfffbccSCorey Minyard } 1251*8bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 1252*8bfffbccSCorey Minyard ibs->sdr.next_free = 0; 1253*8bfffbccSCorey Minyard ibs->sdr.overflow = 0; 1254*8bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1255*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 1256*8bfffbccSCorey Minyard sdr_inc_reservation(&ibs->sdr); 1257*8bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1258*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 1259*8bfffbccSCorey Minyard } else { 1260*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1261*8bfffbccSCorey Minyard goto out; 1262*8bfffbccSCorey Minyard } 1263*8bfffbccSCorey Minyard out: 1264*8bfffbccSCorey Minyard return; 1265*8bfffbccSCorey Minyard } 1266*8bfffbccSCorey Minyard 1267*8bfffbccSCorey Minyard static void get_sel_info(IPMIBmcSim *ibs, 1268*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1269*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1270*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1271*8bfffbccSCorey Minyard { 1272*8bfffbccSCorey Minyard unsigned int i, val; 1273*8bfffbccSCorey Minyard 1274*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0x51); /* Conform to IPMI 1.5 */ 1275*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.next_free & 0xff); 1276*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.next_free >> 8) & 0xff); 1277*8bfffbccSCorey Minyard val = (MAX_SEL_SIZE - ibs->sel.next_free) * 16; 1278*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 1279*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 1280*8bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1281*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_addition[i]); 1282*8bfffbccSCorey Minyard } 1283*8bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1284*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.last_clear[i]); 1285*8bfffbccSCorey Minyard } 1286*8bfffbccSCorey Minyard /* Only support Reserve SEL */ 1287*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.overflow << 7) | 0x02); 1288*8bfffbccSCorey Minyard out: 1289*8bfffbccSCorey Minyard return; 1290*8bfffbccSCorey Minyard } 1291*8bfffbccSCorey Minyard 1292*8bfffbccSCorey Minyard static void reserve_sel(IPMIBmcSim *ibs, 1293*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1294*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1295*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1296*8bfffbccSCorey Minyard { 1297*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.reservation & 0xff); 1298*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((ibs->sel.reservation >> 8) & 0xff); 1299*8bfffbccSCorey Minyard out: 1300*8bfffbccSCorey Minyard return; 1301*8bfffbccSCorey Minyard } 1302*8bfffbccSCorey Minyard 1303*8bfffbccSCorey Minyard static void get_sel_entry(IPMIBmcSim *ibs, 1304*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1305*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1306*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1307*8bfffbccSCorey Minyard { 1308*8bfffbccSCorey Minyard unsigned int val; 1309*8bfffbccSCorey Minyard 1310*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 1311*8bfffbccSCorey Minyard if (cmd[6]) { 1312*8bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 1313*8bfffbccSCorey Minyard } 1314*8bfffbccSCorey Minyard if (ibs->sel.next_free == 0) { 1315*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1316*8bfffbccSCorey Minyard goto out; 1317*8bfffbccSCorey Minyard } 1318*8bfffbccSCorey Minyard if (cmd[6] > 15) { 1319*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1320*8bfffbccSCorey Minyard goto out; 1321*8bfffbccSCorey Minyard } 1322*8bfffbccSCorey Minyard if (cmd[7] == 0xff) { 1323*8bfffbccSCorey Minyard cmd[7] = 16; 1324*8bfffbccSCorey Minyard } else if ((cmd[7] + cmd[6]) > 16) { 1325*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1326*8bfffbccSCorey Minyard goto out; 1327*8bfffbccSCorey Minyard } else { 1328*8bfffbccSCorey Minyard cmd[7] += cmd[6]; 1329*8bfffbccSCorey Minyard } 1330*8bfffbccSCorey Minyard 1331*8bfffbccSCorey Minyard val = cmd[4] | (cmd[5] << 8); 1332*8bfffbccSCorey Minyard if (val == 0xffff) { 1333*8bfffbccSCorey Minyard val = ibs->sel.next_free - 1; 1334*8bfffbccSCorey Minyard } else if (val >= ibs->sel.next_free) { 1335*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1336*8bfffbccSCorey Minyard goto out; 1337*8bfffbccSCorey Minyard } 1338*8bfffbccSCorey Minyard if ((val + 1) == ibs->sel.next_free) { 1339*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 1340*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(0xff); 1341*8bfffbccSCorey Minyard } else { 1342*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val + 1) & 0xff); 1343*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(((val + 1) >> 8) & 0xff); 1344*8bfffbccSCorey Minyard } 1345*8bfffbccSCorey Minyard for (; cmd[6] < cmd[7]; cmd[6]++) { 1346*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(ibs->sel.sel[val][cmd[6]]); 1347*8bfffbccSCorey Minyard } 1348*8bfffbccSCorey Minyard out: 1349*8bfffbccSCorey Minyard return; 1350*8bfffbccSCorey Minyard } 1351*8bfffbccSCorey Minyard 1352*8bfffbccSCorey Minyard static void add_sel_entry(IPMIBmcSim *ibs, 1353*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1354*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1355*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1356*8bfffbccSCorey Minyard { 1357*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(18); 1358*8bfffbccSCorey Minyard if (sel_add_event(ibs, cmd + 2)) { 1359*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_OUT_OF_SPACE; 1360*8bfffbccSCorey Minyard goto out; 1361*8bfffbccSCorey Minyard } 1362*8bfffbccSCorey Minyard /* sel_add_event fills in the record number. */ 1363*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[2]); 1364*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(cmd[3]); 1365*8bfffbccSCorey Minyard out: 1366*8bfffbccSCorey Minyard return; 1367*8bfffbccSCorey Minyard } 1368*8bfffbccSCorey Minyard 1369*8bfffbccSCorey Minyard static void clear_sel(IPMIBmcSim *ibs, 1370*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1371*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1372*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1373*8bfffbccSCorey Minyard { 1374*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(8); 1375*8bfffbccSCorey Minyard IPMI_CHECK_RESERVATION(2, ibs->sel.reservation); 1376*8bfffbccSCorey Minyard if (cmd[4] != 'C' || cmd[5] != 'L' || cmd[6] != 'R') { 1377*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1378*8bfffbccSCorey Minyard goto out; 1379*8bfffbccSCorey Minyard } 1380*8bfffbccSCorey Minyard if (cmd[7] == 0xaa) { 1381*8bfffbccSCorey Minyard ibs->sel.next_free = 0; 1382*8bfffbccSCorey Minyard ibs->sel.overflow = 0; 1383*8bfffbccSCorey Minyard set_timestamp(ibs, ibs->sdr.last_clear); 1384*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 1385*8bfffbccSCorey Minyard sel_inc_reservation(&ibs->sel); 1386*8bfffbccSCorey Minyard } else if (cmd[7] == 0) { 1387*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(1); /* Erasure complete */ 1388*8bfffbccSCorey Minyard } else { 1389*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1390*8bfffbccSCorey Minyard goto out; 1391*8bfffbccSCorey Minyard } 1392*8bfffbccSCorey Minyard out: 1393*8bfffbccSCorey Minyard return; 1394*8bfffbccSCorey Minyard } 1395*8bfffbccSCorey Minyard 1396*8bfffbccSCorey Minyard static void get_sel_time(IPMIBmcSim *ibs, 1397*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1398*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1399*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1400*8bfffbccSCorey Minyard { 1401*8bfffbccSCorey Minyard uint32_t val; 1402*8bfffbccSCorey Minyard struct ipmi_time now; 1403*8bfffbccSCorey Minyard 1404*8bfffbccSCorey Minyard ipmi_gettime(&now); 1405*8bfffbccSCorey Minyard val = now.tv_sec + ibs->sel.time_offset; 1406*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(val & 0xff); 1407*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 8) & 0xff); 1408*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 16) & 0xff); 1409*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((val >> 24) & 0xff); 1410*8bfffbccSCorey Minyard out: 1411*8bfffbccSCorey Minyard return; 1412*8bfffbccSCorey Minyard } 1413*8bfffbccSCorey Minyard 1414*8bfffbccSCorey Minyard static void set_sel_time(IPMIBmcSim *ibs, 1415*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1416*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1417*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1418*8bfffbccSCorey Minyard { 1419*8bfffbccSCorey Minyard uint32_t val; 1420*8bfffbccSCorey Minyard struct ipmi_time now; 1421*8bfffbccSCorey Minyard 1422*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(6); 1423*8bfffbccSCorey Minyard val = cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24); 1424*8bfffbccSCorey Minyard ipmi_gettime(&now); 1425*8bfffbccSCorey Minyard ibs->sel.time_offset = now.tv_sec - ((long) val); 1426*8bfffbccSCorey Minyard out: 1427*8bfffbccSCorey Minyard return; 1428*8bfffbccSCorey Minyard } 1429*8bfffbccSCorey Minyard 1430*8bfffbccSCorey Minyard static void set_sensor_evt_enable(IPMIBmcSim *ibs, 1431*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1432*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1433*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1434*8bfffbccSCorey Minyard { 1435*8bfffbccSCorey Minyard IPMISensor *sens; 1436*8bfffbccSCorey Minyard 1437*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 1438*8bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 1439*8bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1440*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1441*8bfffbccSCorey Minyard goto out; 1442*8bfffbccSCorey Minyard } 1443*8bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1444*8bfffbccSCorey Minyard switch ((cmd[3] >> 4) & 0x3) { 1445*8bfffbccSCorey Minyard case 0: /* Do not change */ 1446*8bfffbccSCorey Minyard break; 1447*8bfffbccSCorey Minyard case 1: /* Enable bits */ 1448*8bfffbccSCorey Minyard if (cmd_len > 4) { 1449*8bfffbccSCorey Minyard sens->assert_enable |= cmd[4]; 1450*8bfffbccSCorey Minyard } 1451*8bfffbccSCorey Minyard if (cmd_len > 5) { 1452*8bfffbccSCorey Minyard sens->assert_enable |= cmd[5] << 8; 1453*8bfffbccSCorey Minyard } 1454*8bfffbccSCorey Minyard if (cmd_len > 6) { 1455*8bfffbccSCorey Minyard sens->deassert_enable |= cmd[6]; 1456*8bfffbccSCorey Minyard } 1457*8bfffbccSCorey Minyard if (cmd_len > 7) { 1458*8bfffbccSCorey Minyard sens->deassert_enable |= cmd[7] << 8; 1459*8bfffbccSCorey Minyard } 1460*8bfffbccSCorey Minyard break; 1461*8bfffbccSCorey Minyard case 2: /* Disable bits */ 1462*8bfffbccSCorey Minyard if (cmd_len > 4) { 1463*8bfffbccSCorey Minyard sens->assert_enable &= ~cmd[4]; 1464*8bfffbccSCorey Minyard } 1465*8bfffbccSCorey Minyard if (cmd_len > 5) { 1466*8bfffbccSCorey Minyard sens->assert_enable &= ~(cmd[5] << 8); 1467*8bfffbccSCorey Minyard } 1468*8bfffbccSCorey Minyard if (cmd_len > 6) { 1469*8bfffbccSCorey Minyard sens->deassert_enable &= ~cmd[6]; 1470*8bfffbccSCorey Minyard } 1471*8bfffbccSCorey Minyard if (cmd_len > 7) { 1472*8bfffbccSCorey Minyard sens->deassert_enable &= ~(cmd[7] << 8); 1473*8bfffbccSCorey Minyard } 1474*8bfffbccSCorey Minyard break; 1475*8bfffbccSCorey Minyard case 3: 1476*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_INVALID_DATA_FIELD; 1477*8bfffbccSCorey Minyard goto out; 1478*8bfffbccSCorey Minyard } 1479*8bfffbccSCorey Minyard IPMI_SENSOR_SET_RET_STATUS(sens, cmd[3]); 1480*8bfffbccSCorey Minyard out: 1481*8bfffbccSCorey Minyard return; 1482*8bfffbccSCorey Minyard } 1483*8bfffbccSCorey Minyard 1484*8bfffbccSCorey Minyard static void get_sensor_evt_enable(IPMIBmcSim *ibs, 1485*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1486*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1487*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1488*8bfffbccSCorey Minyard { 1489*8bfffbccSCorey Minyard IPMISensor *sens; 1490*8bfffbccSCorey Minyard 1491*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 1492*8bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 1493*8bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1494*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1495*8bfffbccSCorey Minyard goto out; 1496*8bfffbccSCorey Minyard } 1497*8bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1498*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 1499*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_enable & 0xff); 1500*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_enable >> 8) & 0xff); 1501*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_enable & 0xff); 1502*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_enable >> 8) & 0xff); 1503*8bfffbccSCorey Minyard out: 1504*8bfffbccSCorey Minyard return; 1505*8bfffbccSCorey Minyard } 1506*8bfffbccSCorey Minyard 1507*8bfffbccSCorey Minyard static void rearm_sensor_evts(IPMIBmcSim *ibs, 1508*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1509*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1510*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1511*8bfffbccSCorey Minyard { 1512*8bfffbccSCorey Minyard IPMISensor *sens; 1513*8bfffbccSCorey Minyard 1514*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(4); 1515*8bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 1516*8bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1517*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1518*8bfffbccSCorey Minyard goto out; 1519*8bfffbccSCorey Minyard } 1520*8bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1521*8bfffbccSCorey Minyard 1522*8bfffbccSCorey Minyard if ((cmd[3] & 0x80) == 0) { 1523*8bfffbccSCorey Minyard /* Just clear everything */ 1524*8bfffbccSCorey Minyard sens->states = 0; 1525*8bfffbccSCorey Minyard goto out; 1526*8bfffbccSCorey Minyard } 1527*8bfffbccSCorey Minyard out: 1528*8bfffbccSCorey Minyard return; 1529*8bfffbccSCorey Minyard } 1530*8bfffbccSCorey Minyard 1531*8bfffbccSCorey Minyard static void get_sensor_evt_status(IPMIBmcSim *ibs, 1532*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1533*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1534*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1535*8bfffbccSCorey Minyard { 1536*8bfffbccSCorey Minyard IPMISensor *sens; 1537*8bfffbccSCorey Minyard 1538*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 1539*8bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 1540*8bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1541*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1542*8bfffbccSCorey Minyard goto out; 1543*8bfffbccSCorey Minyard } 1544*8bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1545*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 1546*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 1547*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->assert_states & 0xff); 1548*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->assert_states >> 8) & 0xff); 1549*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->deassert_states & 0xff); 1550*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->deassert_states >> 8) & 0xff); 1551*8bfffbccSCorey Minyard out: 1552*8bfffbccSCorey Minyard return; 1553*8bfffbccSCorey Minyard } 1554*8bfffbccSCorey Minyard 1555*8bfffbccSCorey Minyard static void get_sensor_reading(IPMIBmcSim *ibs, 1556*8bfffbccSCorey Minyard uint8_t *cmd, unsigned int cmd_len, 1557*8bfffbccSCorey Minyard uint8_t *rsp, unsigned int *rsp_len, 1558*8bfffbccSCorey Minyard unsigned int max_rsp_len) 1559*8bfffbccSCorey Minyard { 1560*8bfffbccSCorey Minyard IPMISensor *sens; 1561*8bfffbccSCorey Minyard 1562*8bfffbccSCorey Minyard IPMI_CHECK_CMD_LEN(3); 1563*8bfffbccSCorey Minyard if ((cmd[2] > MAX_SENSORS) || 1564*8bfffbccSCorey Minyard !IPMI_SENSOR_GET_PRESENT(ibs->sensors + cmd[2])) { 1565*8bfffbccSCorey Minyard rsp[2] = IPMI_CC_REQ_ENTRY_NOT_PRESENT; 1566*8bfffbccSCorey Minyard goto out; 1567*8bfffbccSCorey Minyard } 1568*8bfffbccSCorey Minyard sens = ibs->sensors + cmd[2]; 1569*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->reading); 1570*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(IPMI_SENSOR_GET_RET_STATUS(sens)); 1571*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA(sens->states & 0xff); 1572*8bfffbccSCorey Minyard if (IPMI_SENSOR_IS_DISCRETE(sens)) { 1573*8bfffbccSCorey Minyard IPMI_ADD_RSP_DATA((sens->states >> 8) & 0xff); 1574*8bfffbccSCorey Minyard } 1575*8bfffbccSCorey Minyard out: 1576*8bfffbccSCorey Minyard return; 1577*8bfffbccSCorey Minyard } 1578*8bfffbccSCorey Minyard 1579*8bfffbccSCorey Minyard static const IPMICmdHandler chassis_cmds[IPMI_NETFN_CHASSIS_MAXCMD] = { 1580*8bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_CAPABILITIES] = chassis_capabilities, 1581*8bfffbccSCorey Minyard [IPMI_CMD_GET_CHASSIS_STATUS] = chassis_status, 1582*8bfffbccSCorey Minyard [IPMI_CMD_CHASSIS_CONTROL] = chassis_control 1583*8bfffbccSCorey Minyard }; 1584*8bfffbccSCorey Minyard static const IPMINetfn chassis_netfn = { 1585*8bfffbccSCorey Minyard .cmd_nums = IPMI_NETFN_CHASSIS_MAXCMD, 1586*8bfffbccSCorey Minyard .cmd_handlers = chassis_cmds 1587*8bfffbccSCorey Minyard }; 1588*8bfffbccSCorey Minyard 1589*8bfffbccSCorey Minyard static const IPMICmdHandler 1590*8bfffbccSCorey Minyard sensor_event_cmds[IPMI_NETFN_SENSOR_EVENT_MAXCMD] = { 1591*8bfffbccSCorey Minyard [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = set_sensor_evt_enable, 1592*8bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = get_sensor_evt_enable, 1593*8bfffbccSCorey Minyard [IPMI_CMD_REARM_SENSOR_EVTS] = rearm_sensor_evts, 1594*8bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_EVT_STATUS] = get_sensor_evt_status, 1595*8bfffbccSCorey Minyard [IPMI_CMD_GET_SENSOR_READING] = get_sensor_reading 1596*8bfffbccSCorey Minyard }; 1597*8bfffbccSCorey Minyard static const IPMINetfn sensor_event_netfn = { 1598*8bfffbccSCorey Minyard .cmd_nums = IPMI_NETFN_SENSOR_EVENT_MAXCMD, 1599*8bfffbccSCorey Minyard .cmd_handlers = sensor_event_cmds 1600*8bfffbccSCorey Minyard }; 1601*8bfffbccSCorey Minyard 1602*8bfffbccSCorey Minyard static const IPMICmdHandler app_cmds[IPMI_NETFN_APP_MAXCMD] = { 1603*8bfffbccSCorey Minyard [IPMI_CMD_GET_DEVICE_ID] = get_device_id, 1604*8bfffbccSCorey Minyard [IPMI_CMD_COLD_RESET] = cold_reset, 1605*8bfffbccSCorey Minyard [IPMI_CMD_WARM_RESET] = warm_reset, 1606*8bfffbccSCorey Minyard [IPMI_CMD_SET_BMC_GLOBAL_ENABLES] = set_bmc_global_enables, 1607*8bfffbccSCorey Minyard [IPMI_CMD_GET_BMC_GLOBAL_ENABLES] = get_bmc_global_enables, 1608*8bfffbccSCorey Minyard [IPMI_CMD_CLR_MSG_FLAGS] = clr_msg_flags, 1609*8bfffbccSCorey Minyard [IPMI_CMD_GET_MSG_FLAGS] = get_msg_flags, 1610*8bfffbccSCorey Minyard [IPMI_CMD_GET_MSG] = get_msg, 1611*8bfffbccSCorey Minyard [IPMI_CMD_SEND_MSG] = send_msg, 1612*8bfffbccSCorey Minyard [IPMI_CMD_READ_EVT_MSG_BUF] = read_evt_msg_buf, 1613*8bfffbccSCorey Minyard [IPMI_CMD_RESET_WATCHDOG_TIMER] = reset_watchdog_timer, 1614*8bfffbccSCorey Minyard [IPMI_CMD_SET_WATCHDOG_TIMER] = set_watchdog_timer, 1615*8bfffbccSCorey Minyard [IPMI_CMD_GET_WATCHDOG_TIMER] = get_watchdog_timer, 1616*8bfffbccSCorey Minyard }; 1617*8bfffbccSCorey Minyard static const IPMINetfn app_netfn = { 1618*8bfffbccSCorey Minyard .cmd_nums = IPMI_NETFN_APP_MAXCMD, 1619*8bfffbccSCorey Minyard .cmd_handlers = app_cmds 1620*8bfffbccSCorey Minyard }; 1621*8bfffbccSCorey Minyard 1622*8bfffbccSCorey Minyard static const IPMICmdHandler storage_cmds[IPMI_NETFN_STORAGE_MAXCMD] = { 1623*8bfffbccSCorey Minyard [IPMI_CMD_GET_SDR_REP_INFO] = get_sdr_rep_info, 1624*8bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SDR_REP] = reserve_sdr_rep, 1625*8bfffbccSCorey Minyard [IPMI_CMD_GET_SDR] = get_sdr, 1626*8bfffbccSCorey Minyard [IPMI_CMD_ADD_SDR] = add_sdr, 1627*8bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SDR_REP] = clear_sdr_rep, 1628*8bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_INFO] = get_sel_info, 1629*8bfffbccSCorey Minyard [IPMI_CMD_RESERVE_SEL] = reserve_sel, 1630*8bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_ENTRY] = get_sel_entry, 1631*8bfffbccSCorey Minyard [IPMI_CMD_ADD_SEL_ENTRY] = add_sel_entry, 1632*8bfffbccSCorey Minyard [IPMI_CMD_CLEAR_SEL] = clear_sel, 1633*8bfffbccSCorey Minyard [IPMI_CMD_GET_SEL_TIME] = get_sel_time, 1634*8bfffbccSCorey Minyard [IPMI_CMD_SET_SEL_TIME] = set_sel_time, 1635*8bfffbccSCorey Minyard }; 1636*8bfffbccSCorey Minyard 1637*8bfffbccSCorey Minyard static const IPMINetfn storage_netfn = { 1638*8bfffbccSCorey Minyard .cmd_nums = IPMI_NETFN_STORAGE_MAXCMD, 1639*8bfffbccSCorey Minyard .cmd_handlers = storage_cmds 1640*8bfffbccSCorey Minyard }; 1641*8bfffbccSCorey Minyard 1642*8bfffbccSCorey Minyard static void register_cmds(IPMIBmcSim *s) 1643*8bfffbccSCorey Minyard { 1644*8bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_CHASSIS, &chassis_netfn); 1645*8bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_SENSOR_EVENT, &sensor_event_netfn); 1646*8bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_APP, &app_netfn); 1647*8bfffbccSCorey Minyard ipmi_register_netfn(s, IPMI_NETFN_STORAGE, &storage_netfn); 1648*8bfffbccSCorey Minyard } 1649*8bfffbccSCorey Minyard 1650*8bfffbccSCorey Minyard static const uint8_t init_sdrs[] = { 1651*8bfffbccSCorey Minyard /* Watchdog device */ 1652*8bfffbccSCorey Minyard 0x00, 0x00, 0x51, 0x02, 35, 0x20, 0x00, 0x00, 1653*8bfffbccSCorey Minyard 0x23, 0x01, 0x63, 0x00, 0x23, 0x6f, 0x0f, 0x01, 1654*8bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1655*8bfffbccSCorey Minyard 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 1656*8bfffbccSCorey Minyard 'W', 'a', 't', 'c', 'h', 'd', 'o', 'g', 1657*8bfffbccSCorey Minyard /* End */ 1658*8bfffbccSCorey Minyard 0xff, 0xff, 0x00, 0x00, 0x00 1659*8bfffbccSCorey Minyard }; 1660*8bfffbccSCorey Minyard 1661*8bfffbccSCorey Minyard static void ipmi_sim_init(Object *obj) 1662*8bfffbccSCorey Minyard { 1663*8bfffbccSCorey Minyard IPMIBmc *b = IPMI_BMC(obj); 1664*8bfffbccSCorey Minyard unsigned int i; 1665*8bfffbccSCorey Minyard unsigned int recid; 1666*8bfffbccSCorey Minyard IPMIBmcSim *ibs = IPMI_BMC_SIMULATOR(b); 1667*8bfffbccSCorey Minyard 1668*8bfffbccSCorey Minyard qemu_mutex_init(&ibs->lock); 1669*8bfffbccSCorey Minyard QTAILQ_INIT(&ibs->rcvbufs); 1670*8bfffbccSCorey Minyard 1671*8bfffbccSCorey Minyard ibs->bmc_global_enables = (1 << IPMI_BMC_EVENT_LOG_BIT); 1672*8bfffbccSCorey Minyard ibs->device_id = 0x20; 1673*8bfffbccSCorey Minyard ibs->ipmi_version = 0x02; /* IPMI 2.0 */ 1674*8bfffbccSCorey Minyard for (i = 0; i < 4; i++) { 1675*8bfffbccSCorey Minyard ibs->sel.last_addition[i] = 0xff; 1676*8bfffbccSCorey Minyard ibs->sel.last_clear[i] = 0xff; 1677*8bfffbccSCorey Minyard ibs->sdr.last_addition[i] = 0xff; 1678*8bfffbccSCorey Minyard ibs->sdr.last_clear[i] = 0xff; 1679*8bfffbccSCorey Minyard } 1680*8bfffbccSCorey Minyard 1681*8bfffbccSCorey Minyard for (i = 0;;) { 1682*8bfffbccSCorey Minyard int len; 1683*8bfffbccSCorey Minyard if ((i + 5) > sizeof(init_sdrs)) { 1684*8bfffbccSCorey Minyard error_report("Problem with recid 0x%4.4x: \n", i); 1685*8bfffbccSCorey Minyard return; 1686*8bfffbccSCorey Minyard } 1687*8bfffbccSCorey Minyard len = init_sdrs[i + 4]; 1688*8bfffbccSCorey Minyard recid = init_sdrs[i] | (init_sdrs[i + 1] << 8); 1689*8bfffbccSCorey Minyard if (recid == 0xffff) { 1690*8bfffbccSCorey Minyard break; 1691*8bfffbccSCorey Minyard } 1692*8bfffbccSCorey Minyard if ((i + len + 5) > sizeof(init_sdrs)) { 1693*8bfffbccSCorey Minyard error_report("Problem with recid 0x%4.4x\n", i); 1694*8bfffbccSCorey Minyard return; 1695*8bfffbccSCorey Minyard } 1696*8bfffbccSCorey Minyard sdr_add_entry(ibs, init_sdrs + i, len, NULL); 1697*8bfffbccSCorey Minyard i += len + 5; 1698*8bfffbccSCorey Minyard } 1699*8bfffbccSCorey Minyard 1700*8bfffbccSCorey Minyard ipmi_init_sensors_from_sdrs(ibs); 1701*8bfffbccSCorey Minyard register_cmds(ibs); 1702*8bfffbccSCorey Minyard 1703*8bfffbccSCorey Minyard ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); 1704*8bfffbccSCorey Minyard } 1705*8bfffbccSCorey Minyard 1706*8bfffbccSCorey Minyard static void ipmi_sim_class_init(ObjectClass *oc, void *data) 1707*8bfffbccSCorey Minyard { 1708*8bfffbccSCorey Minyard IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); 1709*8bfffbccSCorey Minyard 1710*8bfffbccSCorey Minyard bk->handle_command = ipmi_sim_handle_command; 1711*8bfffbccSCorey Minyard } 1712*8bfffbccSCorey Minyard 1713*8bfffbccSCorey Minyard static const TypeInfo ipmi_sim_type = { 1714*8bfffbccSCorey Minyard .name = TYPE_IPMI_BMC_SIMULATOR, 1715*8bfffbccSCorey Minyard .parent = TYPE_IPMI_BMC, 1716*8bfffbccSCorey Minyard .instance_size = sizeof(IPMIBmcSim), 1717*8bfffbccSCorey Minyard .instance_init = ipmi_sim_init, 1718*8bfffbccSCorey Minyard .class_init = ipmi_sim_class_init, 1719*8bfffbccSCorey Minyard }; 1720*8bfffbccSCorey Minyard 1721*8bfffbccSCorey Minyard static void ipmi_sim_register_types(void) 1722*8bfffbccSCorey Minyard { 1723*8bfffbccSCorey Minyard type_register_static(&ipmi_sim_type); 1724*8bfffbccSCorey Minyard } 1725*8bfffbccSCorey Minyard 1726*8bfffbccSCorey Minyard type_init(ipmi_sim_register_types) 1727