2 * QEMU IPMI SMBus (SSIF) emulation
4 * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "qemu/osdep.h"
25 #include "migration/vmstate.h"
26 #include "hw/i2c/smbus_slave.h"
27 #include "qapi/error.h"
28 #include "qemu/error-report.h"
29 #include "hw/ipmi/ipmi.h"
30 #include "qom/object.h"
32 #define TYPE_SMBUS_IPMI "smbus-ipmi"
33 OBJECT_DECLARE_SIMPLE_TYPE(SMBusIPMIDevice
, SMBUS_IPMI
)
35 #define SSIF_IPMI_REQUEST 2
36 #define SSIF_IPMI_MULTI_PART_REQUEST_START 6
37 #define SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE 7
38 #define SSIF_IPMI_MULTI_PART_REQUEST_END 8
39 #define SSIF_IPMI_RESPONSE 3
40 #define SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE 9
41 #define SSIF_IPMI_MULTI_PART_RETRY 0xa
43 #define MAX_SSIF_IPMI_MSG_SIZE 255
44 #define MAX_SSIF_IPMI_MSG_CHUNK 32
46 #define IPMI_GET_SYS_INTF_CAP_CMD 0x57
48 struct SMBusIPMIDevice
{
53 uint8_t outmsg
[MAX_SSIF_IPMI_MSG_SIZE
];
57 /* Holds the SMBUS message currently being sent to the host. */
58 uint8_t outbuf
[MAX_SSIF_IPMI_MSG_CHUNK
+ 1]; /* len + message. */
61 uint8_t inmsg
[MAX_SSIF_IPMI_MSG_SIZE
];
65 * This is a response number that we send with the command to make
66 * sure that the response matches the command.
73 static void smbus_ipmi_handle_event(IPMIInterface
*ii
)
75 /* No interrupts, so nothing to do here. */
78 static void smbus_ipmi_handle_rsp(IPMIInterface
*ii
, uint8_t msg_id
,
79 unsigned char *rsp
, unsigned int rsp_len
)
81 SMBusIPMIDevice
*sid
= SMBUS_IPMI(ii
);
83 if (sid
->waiting_rsp
== msg_id
) {
86 if (rsp_len
> MAX_SSIF_IPMI_MSG_SIZE
) {
87 rsp
[2] = IPMI_CC_REQUEST_DATA_TRUNCATED
;
88 rsp_len
= MAX_SSIF_IPMI_MSG_SIZE
;
90 memcpy(sid
->outmsg
, rsp
, rsp_len
);
91 sid
->outlen
= rsp_len
;
97 static void smbus_ipmi_set_atn(IPMIInterface
*ii
, int val
, int irq
)
99 /* This is where PEC would go. */
102 static void smbus_ipmi_set_irq_enable(IPMIInterface
*ii
, int val
)
106 static void smbus_ipmi_send_msg(SMBusIPMIDevice
*sid
)
108 uint8_t *msg
= sid
->inmsg
;
109 uint32_t len
= sid
->inlen
;
110 IPMIBmcClass
*bk
= IPMI_BMC_GET_CLASS(sid
->bmc
);
116 if (msg
[0] == (IPMI_NETFN_APP
<< 2) && msg
[1] == IPMI_GET_SYS_INTF_CAP_CMD
)
118 /* We handle this ourself. */
119 sid
->outmsg
[0] = (IPMI_NETFN_APP
+ 1) << 2;
120 sid
->outmsg
[1] = msg
[1];
122 sid
->outmsg
[2] = IPMI_CC_REQUEST_DATA_LENGTH_INVALID
;
124 } else if ((msg
[2] & 0x0f) != 0) {
125 sid
->outmsg
[2] = IPMI_CC_INVALID_DATA_FIELD
;
130 sid
->outmsg
[4] = (2 << 6); /* Multi-part supported. */
131 sid
->outmsg
[5] = MAX_SSIF_IPMI_MSG_SIZE
;
132 sid
->outmsg
[6] = MAX_SSIF_IPMI_MSG_SIZE
;
138 bk
->handle_command(sid
->bmc
, sid
->inmsg
, sid
->inlen
, sizeof(sid
->inmsg
),
142 static uint8_t ipmi_receive_byte(SMBusDevice
*dev
)
144 SMBusIPMIDevice
*sid
= SMBUS_IPMI(dev
);
146 if (sid
->outpos
>= sizeof(sid
->outbuf
)) {
150 return sid
->outbuf
[sid
->outpos
++];
153 static int ipmi_load_readbuf(SMBusIPMIDevice
*sid
)
155 unsigned int block
= sid
->currblk
, pos
, len
;
157 if (sid
->outlen
== 0) {
161 if (sid
->outlen
<= 32) {
165 sid
->outbuf
[0] = sid
->outlen
;
166 memcpy(sid
->outbuf
+ 1, sid
->outmsg
, sid
->outlen
);
175 memcpy(sid
->outbuf
+ 3, sid
->outmsg
, 30);
181 * Calculate the position in outmsg. 30 for the first block, 31
182 * for the rest of the blocks.
184 pos
= 30 + (block
- 1) * 31;
186 if (pos
>= sid
->outlen
) {
190 len
= sid
->outlen
- pos
;
192 /* More chunks after this. */
194 /* Blocks start at 0 for the first middle transaction. */
195 sid
->outbuf
[1] = block
- 1;
197 sid
->outbuf
[1] = 0xff; /* End of message marker. */
200 sid
->outbuf
[0] = len
+ 1;
201 memcpy(sid
->outbuf
+ 2, sid
->outmsg
+ pos
, len
);
206 static int ipmi_write_data(SMBusDevice
*dev
, uint8_t *buf
, uint8_t len
)
208 SMBusIPMIDevice
*sid
= SMBUS_IPMI(dev
);
213 /* length is guaranteed to be >= 1. */
217 /* Handle read request, which don't have any data in the write part. */
219 case SSIF_IPMI_RESPONSE
:
221 ret
= ipmi_load_readbuf(sid
);
224 case SSIF_IPMI_MULTI_PART_RESPONSE_MIDDLE
:
226 ret
= ipmi_load_readbuf(sid
);
229 case SSIF_IPMI_MULTI_PART_RETRY
:
231 sid
->currblk
= buf
[0];
232 ret
= ipmi_load_readbuf(sid
);
242 /* This should be a message write, make the length is there and correct. */
244 if (*buf
!= len
- 1 || *buf
> MAX_SSIF_IPMI_MSG_CHUNK
) {
245 return -1; /* Bogus message */
252 case SSIF_IPMI_REQUEST
:
255 case SSIF_IPMI_MULTI_PART_REQUEST_START
:
257 return -1; /* Bogus. */
259 memcpy(sid
->inmsg
, buf
, len
);
263 case SSIF_IPMI_MULTI_PART_REQUEST_END
:
266 case SSIF_IPMI_MULTI_PART_REQUEST_MIDDLE
:
268 return -1; /* Bogus. */
270 if (sid
->inlen
+ len
> MAX_SSIF_IPMI_MSG_SIZE
) {
271 sid
->inlen
= 0; /* Discard the message. */
272 return -1; /* Bogus. */
276 * Special hack, a multi-part middle that is less than 32 bytes
277 * marks the end of a message. The specification is fairly
278 * confusing, so some systems to this, even sending a zero
279 * length end message to mark the end.
283 memcpy(sid
->inmsg
+ sid
->inlen
, buf
, len
);
288 if (send
&& sid
->inlen
) {
289 smbus_ipmi_send_msg(sid
);
295 static const VMStateDescription vmstate_smbus_ipmi
= {
296 .name
= TYPE_SMBUS_IPMI
,
298 .minimum_version_id
= 1,
299 .fields
= (VMStateField
[]) {
300 VMSTATE_SMBUS_DEVICE(parent
, SMBusIPMIDevice
),
301 VMSTATE_UINT8(waiting_rsp
, SMBusIPMIDevice
),
302 VMSTATE_UINT32(outlen
, SMBusIPMIDevice
),
303 VMSTATE_UINT32(currblk
, SMBusIPMIDevice
),
304 VMSTATE_UINT8_ARRAY(outmsg
, SMBusIPMIDevice
, MAX_SSIF_IPMI_MSG_SIZE
),
305 VMSTATE_UINT32(outpos
, SMBusIPMIDevice
),
306 VMSTATE_UINT8_ARRAY(outbuf
, SMBusIPMIDevice
,
307 MAX_SSIF_IPMI_MSG_CHUNK
+ 1),
308 VMSTATE_UINT32(inlen
, SMBusIPMIDevice
),
309 VMSTATE_UINT8_ARRAY(inmsg
, SMBusIPMIDevice
, MAX_SSIF_IPMI_MSG_SIZE
),
310 VMSTATE_END_OF_LIST()
314 static void smbus_ipmi_realize(DeviceState
*dev
, Error
**errp
)
316 SMBusIPMIDevice
*sid
= SMBUS_IPMI(dev
);
317 IPMIInterface
*ii
= IPMI_INTERFACE(dev
);
320 error_setg(errp
, "IPMI device requires a bmc attribute to be set");
324 sid
->uuid
= ipmi_next_uuid();
329 static void smbus_ipmi_init(Object
*obj
)
331 SMBusIPMIDevice
*sid
= SMBUS_IPMI(obj
);
333 ipmi_bmc_find_and_link(obj
, (Object
**) &sid
->bmc
);
336 static void smbus_ipmi_get_fwinfo(struct IPMIInterface
*ii
, IPMIFwInfo
*info
)
338 SMBusIPMIDevice
*sid
= SMBUS_IPMI(ii
);
340 info
->interface_name
= "smbus";
341 info
->interface_type
= IPMI_SMBIOS_SSIF
;
342 info
->ipmi_spec_major_revision
= 2;
343 info
->ipmi_spec_minor_revision
= 0;
344 info
->i2c_slave_address
= sid
->bmc
->slave_addr
;
345 info
->base_address
= sid
->parent
.i2c
.address
;
346 info
->memspace
= IPMI_MEMSPACE_SMBUS
;
347 info
->register_spacing
= 1;
348 info
->uuid
= sid
->uuid
;
351 static void smbus_ipmi_class_init(ObjectClass
*oc
, void *data
)
353 DeviceClass
*dc
= DEVICE_CLASS(oc
);
354 IPMIInterfaceClass
*iic
= IPMI_INTERFACE_CLASS(oc
);
355 SMBusDeviceClass
*sc
= SMBUS_DEVICE_CLASS(oc
);
357 sc
->receive_byte
= ipmi_receive_byte
;
358 sc
->write_data
= ipmi_write_data
;
359 dc
->vmsd
= &vmstate_smbus_ipmi
;
360 dc
->realize
= smbus_ipmi_realize
;
361 iic
->set_atn
= smbus_ipmi_set_atn
;
362 iic
->handle_rsp
= smbus_ipmi_handle_rsp
;
363 iic
->handle_if_event
= smbus_ipmi_handle_event
;
364 iic
->set_irq_enable
= smbus_ipmi_set_irq_enable
;
365 iic
->get_fwinfo
= smbus_ipmi_get_fwinfo
;
368 static const TypeInfo smbus_ipmi_info
= {
369 .name
= TYPE_SMBUS_IPMI
,
370 .parent
= TYPE_SMBUS_DEVICE
,
371 .instance_size
= sizeof(SMBusIPMIDevice
),
372 .instance_init
= smbus_ipmi_init
,
373 .class_init
= smbus_ipmi_class_init
,
374 .interfaces
= (InterfaceInfo
[]) {
375 { TYPE_IPMI_INTERFACE
},
380 static void smbus_ipmi_register_types(void)
382 type_register_static(&smbus_ipmi_info
);
385 type_init(smbus_ipmi_register_types
)