Add an OpenIPMI mostly compatible driver. This driver was developed

to work with ipmitools.  It works with other tools that have an OpenIPMI
driver interface.  The port will need to get updated to used this.
I have not implemented the IPMB mode yet so ioctl's for that don't
really do much otherwise it should work like the OpenIPMI version.
The ipmi.h definitions was derived from the ipmitool header file.
The bus attachments are done for smbios and pci/smbios.  Differences
in bus probe order for modules/static are delt with.  ACPI attachment
should be done.

This drivers registers with the watchdod(4) interface

Work to do:
     - BT interface
     - IPMB mode

This has been tested on Dell PE2850, PE2650 & PE850 with i386 & amd64
kernel.

I will link this into the build on next week.

Tom Rhodes, helped me with the man page.

Sponsored by:   IronPort Systems Inc.
Inspired from:  ipmitool & Linux
This commit is contained in:
Doug Ambrisko 2006-02-10 20:51:35 +00:00
parent 595dedc1b0
commit 37b1ce132c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=155517
7 changed files with 2396 additions and 0 deletions

187
share/man/man4/ipmi.4 Normal file
View file

@ -0,0 +1,187 @@
.\"
.\" Copyright (c) 2006 Tom Rhodes
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd February 10, 2006
.Dt IPMI 4
.Os
.Sh NAME
.Nm ipmi
.Nd "OpenIPMI compatible IPMI interface driver"
.Sh SYNOPSIS
.Cd "options IPMI"
.Pp
.In sys/dev/ipmi.h
.Ft int
.Fn ioctl "int d" "IPMICTL_RECEIVE_MSG_TRUNC" "struct ipmi_recv *"
.Ft int
.Fn ioctl "int d" "IPMICTL_RECEIVE_MSG" "struct ipmi_recv *"
.Ft int
.Fn ioctl "int d" "IPMICTL_SEND_COMMAND" "struct ipmi_req *"
.Ft int
.Fn ioctl "int d" "IPMICTL_REGISTER_FOR_CMD" "struct ipmi_cmdspec *"
.Ft int
.Fn ioctl "int d" "IPMICTL_UNREGISTER_FOR_CMD" "struct ipmi_cmdspec *"
.Ft int
.Fn ioctl "int d" "IPMICTL_SET_GETS_EVENTS_CMD" "int *"
.Ft int
.Fn ioctl "int d" "IPMICTL_SET_MY_ADDRESS_CMD" "unsigned int *"
.Ft int
.Fn ioctl "int d" "IPMICTL_GET_MY_ADDRESS_CMD" "unsigned int *"
.Ft int
.Fn ioctl "int d" "IPMICTL_SET_MY_LUN_CMD" "unsigned int *"
.Ft int
.Fn ioctl "int d" "IPMICTL_GET_MY_LUN_CMD" "unsigned int *"
.Sh DESCRIPTION
The
.Tn IPMI
(Intelligent Platform Management Interface) is a standard for
monitoring system hardware by permitting generic code to detect
and monitor the sensors in a system.
The
.Tn IPMI
standard offers watchdog support, an FRU database, and other
support extensions.
It is currently being adopted by the makers of many
single board and embedded system manufacturers.
.Pp
The
.Nm
driver in
.Fx
is heavily adopted from the standard and
.Lx
driver; however, not all features described in the
standard are supported.
.Sh IOCTL
Sending and receiving messages through the
.Nm
driver requires the use of IOCTLs.
The IOCTLs are used due to the complexity of
data sent to and from the device.
Currently the following IOCTLs are defined:
.Pp
.Dv IPMI_IOC_MAGIC
The magic IOCTL value for this interface.
.Pp
.Dv IPMICTL_RECEIVE_MSG_TRUNC
Like
.Dv RECEIVE_MSG
but if the message can not fit into the buffer, it
will truncate the contents instead of leaving the data
in the buffer.
.Pp
.Dv IPMICTL_RECEIVE_MSG
Receive a message.
Possible error values:
.Bl -tag -width Er
.It Bq Er EAGAIN
No messages are in the process queue.
.It Bq Er EFAULT
An address supplied was invalid.
.It Bq Er EMSGSIZE
The address could not fit in the message buffer and
will remain in the buffer.
.El
.Pp
.Dv IPMICTL_SEND_COMMAND
Send a message to the interface.
Possible error values:
.Bl -tag -width Er
.It Bq Er EFAULT
An address supplied was invalid
.It Bq Er ENOMEM
Buffers could not be allowed for the command, out of memory.
.El
.Pp
.Dv IPMICTL_SET_MY_ADDRESS_CMD
Set the slave address for source messages.
.Pp
.Dv IPMICTL_GET_MY_ADDRESS_CMD
Get the slave address for source messages.
.Pp
.Dv IPMICTL_SET_MY_LUN_CMD
Set the slave LUN for source messages.
.Pp
.Dv IPMICTL_GET_MY_LUN_CMD
Get the slave LUN for source messages.
.Pp
.Ss Unimplemented IOCTLS:
.Pp
.Dv IPMICTL_REGISTER_FOR_CMD
Register to receive a specfic command
Possible error values:
.Bl -tag -width Er
.It Bq Er EFAULT
An supplied address was invalid.
.It Bq Er EBUSY
The network function/command is already in use.
.It Bq Er ENOMEM
Could not allocate memory.
.El
.Pp
.Dv IPMICTL_UNREGISTER_FOR_CMD
Unregister to receive a specfic command
Possible error values:
.Bl -tag -width Er
.It Bq Er EFAULT
An address supplied was invalid.
.It Bq Er ENOENT
The network function/command was not found.
.El
.Pp
.Ss Stub only IOCTL:
.Pp
.Dv IPMICTL_SET_GETS_EVENTS_CMD
Set whether this interface receives events.
Possible error values:
.Bl -tag -width Er
.It Bq Er EFAULT
An address supplied was invalid.
.El
.Pp
.Sh SEE ALSO
.Xr ioctl 2 ,
.Xr watchdog 4 ,
.Xr watchdog 8 ,
.Xr watchdogd 8 ,
.Xr watchdog 9
.Sh HISTORY
The
.Nm
driver first appeared in
.Fx 7.0 .
.Sh AUTHORS
The
.Nm
driver was written by
.Ar Doug Ambrisko An ambrisko@FreeBSD.org .
This manual page was written by
.Ar Tom Rhodes An trhodes@FreeBSD.org .
.Sh BUGS
Not all features of the MontaVista driver are supported.
.Pp
Currently, IPMB and BT modes are not implemented.

1096
sys/dev/ipmi/ipmi.c Normal file

File diff suppressed because it is too large Load diff

309
sys/dev/ipmi/ipmi_pci.c Normal file
View file

@ -0,0 +1,309 @@
/*-
* Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/selinfo.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#ifdef LOCAL_MODULE
#include <ipmivars.h>
#else
#include <dev/ipmi/ipmivars.h>
#endif
static int ipmi_pci_probe(device_t dev);
static int ipmi_pci_attach(device_t dev);
static int ipmi_pci_detach(device_t dev);
static device_method_t ipmi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ipmi_pci_probe),
DEVMETHOD(device_attach, ipmi_pci_attach),
DEVMETHOD(device_detach, ipmi_pci_detach),
{ 0, 0 }
};
struct ipmi_ident
{
u_int16_t vendor;
u_int16_t device;
char *desc;
} ipmi_identifiers[] = {
{0x1028, 0x000d, "Dell PE2650 SMIC interface"},
{0, 0, 0}
};
static int
ipmi_pci_probe(device_t dev) {
struct ipmi_ident *m;
if (ipmi_attached)
return ENXIO;
for (m = ipmi_identifiers; m->vendor != 0; m++) {
if ((m->vendor == pci_get_vendor(dev)) &&
(m->device == pci_get_device(dev))) {
device_set_desc(dev, m->desc);
return (BUS_PROBE_DEFAULT);
}
}
return ENXIO;
}
static int
ipmi_pci_attach(device_t dev) {
struct ipmi_softc *sc = device_get_softc(dev);
device_t parent, smbios_attach_dev = NULL;
devclass_t dc;
int status, flags;
int error;
/*
* We need to attach to something that can address the BIOS/
* SMBIOS memory range. This is usually the isa bus however
* during a static kernel boot the isa bus is not available
* so we run up the tree to the nexus bus. A module load
* will use the isa bus attachment. If neither work bail
* since the SMBIOS defines stuff we need to know to attach to
* this device.
*/
dc = devclass_find("isa");
if (dc != NULL) {
smbios_attach_dev = devclass_get_device(dc, 0);
}
if (smbios_attach_dev == NULL) {
smbios_attach_dev = dev;
for (;;) {
parent = device_get_parent(smbios_attach_dev);
if (parent == NULL)
break;
if (strcmp(device_get_name(smbios_attach_dev),
"nexus") == 0)
break;
smbios_attach_dev = parent;
}
}
if (smbios_attach_dev == NULL) {
device_printf(dev, "Couldn't find isa/nexus device\n");
goto bad;
}
sc->ipmi_smbios_dev = ipmi_smbios_identify(NULL, smbios_attach_dev);
if (sc->ipmi_smbios_dev == NULL) {
device_printf(dev, "Couldn't find isa device\n");
goto bad;
}
error = ipmi_smbios_probe(sc->ipmi_smbios_dev);
if (error != 0) {
goto bad;
}
sc->ipmi_dev = dev;
error = ipmi_smbios_query(dev);
device_delete_child(dev, sc->ipmi_smbios_dev);
if (error != 0)
goto bad;
/* Now we know about the IPMI attachment info. */
if (sc->ipmi_bios_info.kcs_mode) {
if (sc->ipmi_bios_info.io_mode)
device_printf(dev, "KCS mode found at io 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
else
device_printf(dev, "KCS mode found at mem 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
sc->ipmi_kcs_status_reg = sc->ipmi_bios_info.offset;
sc->ipmi_kcs_command_reg = sc->ipmi_bios_info.offset;
sc->ipmi_kcs_data_out_reg = 0;
sc->ipmi_kcs_data_in_reg = 0;
if (sc->ipmi_bios_info.io_mode) {
sc->ipmi_io_rid = PCIR_BAR(0);
sc->ipmi_io_res = bus_alloc_resource(dev,
SYS_RES_IOPORT, &sc->ipmi_io_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 2),
sc->ipmi_bios_info.offset * 2,
RF_ACTIVE);
} else {
sc->ipmi_mem_rid = PCIR_BAR(0);
sc->ipmi_mem_res = bus_alloc_resource(dev,
SYS_RES_MEMORY, &sc->ipmi_mem_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 2),
sc->ipmi_bios_info.offset * 2,
RF_ACTIVE);
}
if (!sc->ipmi_io_res){
device_printf(dev, "couldn't configure pci io res\n");
goto bad;
}
status = INB(sc, sc->ipmi_kcs_status_reg);
if (status == 0xff) {
device_printf(dev, "couldn't find it\n");
goto bad;
}
if(status & KCS_STATUS_OBF){
ipmi_read(dev, NULL, 0);
}
} else if (sc->ipmi_bios_info.smic_mode) {
if (sc->ipmi_bios_info.io_mode)
device_printf(dev, "SMIC mode found at io 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
else
device_printf(dev, "SMIC mode found at mem 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
sc->ipmi_smic_data = 0;
sc->ipmi_smic_ctl_sts = sc->ipmi_bios_info.offset;
sc->ipmi_smic_flags = sc->ipmi_bios_info.offset * 2;
if (sc->ipmi_bios_info.io_mode) {
sc->ipmi_io_rid = PCIR_BAR(0);
sc->ipmi_io_res = bus_alloc_resource(dev,
SYS_RES_IOPORT, &sc->ipmi_io_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 3),
sc->ipmi_bios_info.offset * 3,
RF_ACTIVE);
} else {
sc->ipmi_mem_rid = PCIR_BAR(0);
sc->ipmi_mem_res = bus_alloc_resource(dev,
SYS_RES_MEMORY, &sc->ipmi_mem_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 2),
sc->ipmi_bios_info.offset * 2,
RF_ACTIVE);
}
if (!sc->ipmi_io_res && !sc->ipmi_mem_res){
device_printf(dev, "couldn't configure pci res\n");
goto bad;
}
flags = INB(sc, sc->ipmi_smic_flags);
if (flags == 0xff) {
device_printf(dev, "couldn't find it\n");
goto bad;
}
if ((flags & SMIC_STATUS_SMS_ATN)
&& (flags & SMIC_STATUS_RX_RDY)){
ipmi_read(dev, NULL, 0);
}
} else {
device_printf(dev, "No IPMI interface found\n");
goto bad;
}
ipmi_attach(dev);
sc->ipmi_irq_rid = 0;
sc->ipmi_irq_res = bus_alloc_resource_any(sc->ipmi_dev, SYS_RES_IRQ,
&sc->ipmi_irq_rid, RF_SHAREABLE | RF_ACTIVE);
if (sc->ipmi_irq_res == NULL) {
device_printf(sc->ipmi_dev, "can't allocate interrupt\n");
} else {
if (bus_setup_intr(sc->ipmi_dev, sc->ipmi_irq_res,
INTR_TYPE_MISC, ipmi_intr,
sc->ipmi_dev, &sc->ipmi_irq)) {
device_printf(sc->ipmi_dev,
"can't set up interrupt\n");
return (EINVAL);
}
}
return 0;
bad:
return ENXIO;
}
static int ipmi_pci_detach(device_t dev) {
struct ipmi_softc *sc;
sc = device_get_softc(dev);
ipmi_detach(dev);
if (sc->ipmi_ev_tag)
EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_ev_tag);
if (sc->ipmi_mem_res)
bus_release_resource(dev, SYS_RES_MEMORY, sc->ipmi_mem_rid,
sc->ipmi_mem_res);
if (sc->ipmi_io_res)
bus_release_resource(dev, SYS_RES_IOPORT, sc->ipmi_io_rid,
sc->ipmi_io_res);
if (sc->ipmi_irq)
bus_teardown_intr(sc->ipmi_dev, sc->ipmi_irq_res,
sc->ipmi_irq);
if (sc->ipmi_irq_res)
bus_release_resource(sc->ipmi_dev, SYS_RES_IRQ,
sc->ipmi_irq_rid, sc->ipmi_irq_res);
return 0;
}
static driver_t ipmi_pci_driver = {
"ipmi",
ipmi_methods,
sizeof(struct ipmi_softc)
};
DRIVER_MODULE(ipmi_foo, pci, ipmi_pci_driver, ipmi_devclass, 0, 0);

538
sys/dev/ipmi/ipmi_smbios.c Normal file
View file

@ -0,0 +1,538 @@
/*-
* Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/poll.h>
#include <sys/selinfo.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <sys/watchdog.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <machine/pc/bios.h>
#ifdef LOCAL_MODULE
#include <ipmi.h>
#include <ipmivars.h>
#else
#include <sys/ipmi.h>
#include <dev/ipmi/ipmivars.h>
#endif
struct smbios_table_entry {
uint8_t anchor_string[4];
uint8_t checksum;
uint8_t length;
uint8_t major_version;
uint8_t minor_version;
uint16_t maximum_structure_size;
uint8_t entry_point_revision;
uint8_t formatted_area[5];
uint8_t DMI_anchor_string[5];
uint8_t intermediate_checksum;
uint16_t structure_table_length;
uint32_t structure_table_address;
uint16_t number_structures;
uint8_t BCD_revision;
};
struct structure_header {
uint8_t type;
uint8_t length;
uint16_t handle;
};
struct ipmi_device {
uint8_t type;
uint8_t length;
uint16_t handle;
uint8_t interface_type;
uint8_t spec_revision;
uint8_t i2c_slave_address;
uint8_t NV_storage_device_address;
uint64_t base_address;
uint8_t base_address_modifier;
uint8_t interrupt_number;
};
#define SMBIOS_START 0xf0000
#define SMBIOS_STEP 0x10
#define SMBIOS_OFF 0
#define SMBIOS_LEN 4
#define SMBIOS_SIG "_SM_"
devclass_t ipmi_devclass;
typedef void (*dispatchproc_t)(uint8_t *p, char **table,
struct ipmi_get_info *info);
static void smbios_run_table(uint8_t *, int, dispatchproc_t *,
struct ipmi_get_info *);
static char *get_strings(char *, char **);
static int smbios_cksum (struct smbios_table_entry *);
static void smbios_t38_proc_info(uint8_t *, char **, struct ipmi_get_info *);
static int ipmi_smbios_attach (device_t);
static int ipmi_smbios_modevent(module_t, int, void *);
static void
smbios_t38_proc_info(uint8_t *p, char **table, struct ipmi_get_info *info)
{
struct ipmi_device *s = (struct ipmi_device *) p;
bzero(info, sizeof(struct ipmi_get_info));
if (s->interface_type == 0x01)
info->kcs_mode = 1;
if (s->interface_type == 0x02)
info->smic_mode = 1;
info->address = s->base_address & ~1;
switch (s->base_address_modifier >> 6) {
case 0x00:
info->offset = 1;
break;
case 0x01:
info->offset = 4;
break;
case 0x10:
info->offset = 2;
break;
case 0x11:
info->offset = 0;
break;
}
info->io_mode = s->base_address & 1;
}
static char *
get_strings(char *p, char **table)
{
/* Scan for strings, stoping at a single null byte */
while (*p != 0) {
*table++ = p;
p += strlen(p) + 1;
}
*table = 0;
/* Skip past terminating null byte */
return p + 1;
}
static void
smbios_run_table(uint8_t *p, int entries, dispatchproc_t *dispatchstatus,
struct ipmi_get_info *info)
{
struct structure_header *s;
char *table[20];
uint8_t *nextp;
while(entries--) {
s = (struct structure_header *) p;
nextp = get_strings(p + s->length, table);
/*
* No strings still has a double-null at the end,
* skip over it
*/
if (table[0] == 0)
nextp++;
if (dispatchstatus[*p]) {
(dispatchstatus[*p])(p, table, info);
}
p = nextp;
}
}
device_t
ipmi_smbios_identify (driver_t *driver, device_t parent)
{
device_t child = NULL;
u_int32_t addr;
int length;
int rid1, rid2;
addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN,
SMBIOS_STEP, SMBIOS_OFF);
if (addr != 0) {
rid1 = 0;
length = ((struct smbios_table_entry *)BIOS_PADDRTOVADDR(addr))
->length;
child = BUS_ADD_CHILD(parent, 0, "ipmi", -1);
if (driver != NULL)
device_set_driver(child, driver);
bus_set_resource(child, SYS_RES_MEMORY, rid1, addr, length);
rid2 = 1;
length = ((struct smbios_table_entry *)BIOS_PADDRTOVADDR(addr))
->structure_table_length;
addr = ((struct smbios_table_entry *)BIOS_PADDRTOVADDR(addr))
->structure_table_address;
bus_set_resource(child, SYS_RES_MEMORY, rid2, addr, length);
device_set_desc(child, "System Management BIOS");
} else {
device_printf(parent, "Failed to find SMBIOS signature\n");
}
return child;
}
int
ipmi_smbios_probe(device_t dev)
{
struct resource *res1 = NULL, *res2 = NULL;
int rid1, rid2;
int error;
if (ipmi_attached)
return(EBUSY);
error = 0;
rid1 = 0;
rid2 = 1;
res1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid1,
0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE);
if (res1 == NULL) {
device_printf(dev, "Unable to allocate memory resource.\n");
error = ENOMEM;
goto bad;
}
res2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid2,
0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE);
if (res2 == NULL) {
device_printf(dev, "Unable to allocate memory resource.\n");
error = ENOMEM;
goto bad;
}
if (smbios_cksum(
(struct smbios_table_entry *)rman_get_virtual(res1))) {
device_printf(dev, "SMBIOS checksum failed.\n");
error = ENXIO;
goto bad;
}
bad:
if (res1)
bus_release_resource(dev, SYS_RES_MEMORY, rid1, res1);
if (res2)
bus_release_resource(dev, SYS_RES_MEMORY, rid2, res2);
return error;
}
int
ipmi_smbios_query(device_t dev)
{
struct ipmi_softc *sc = device_get_softc(dev);
dispatchproc_t dispatch_smbios_ipmi[256];
struct resource *res = NULL , *res2 = NULL;
int rid, rid2;
int error;
error = 0;
rid = 0;
res = bus_alloc_resource(sc->ipmi_smbios_dev, SYS_RES_MEMORY, &rid,
0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE );
if (res == NULL) {
device_printf(dev, "Unable to allocate memory resource.\n");
error = ENOMEM;
goto bad;
}
rid2 = 1;
res2 = bus_alloc_resource(sc->ipmi_smbios_dev, SYS_RES_MEMORY, &rid2,
0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE);
if (res2 == NULL) {
device_printf(dev, "Unable to allocate memory resource.\n");
error = ENOMEM;
goto bad;
}
sc->ipmi_smbios =
(struct smbios_table_entry *)rman_get_virtual(res);
sc->ipmi_busy = 0;
device_printf(sc->ipmi_smbios_dev, "SMBIOS Version: %d.%02d",
sc->ipmi_smbios->major_version,
sc->ipmi_smbios->minor_version);
if (bcd2bin(sc->ipmi_smbios->BCD_revision))
printf(", revision: %d.%02d",
bcd2bin(sc->ipmi_smbios->BCD_revision >> 4),
bcd2bin(sc->ipmi_smbios->BCD_revision & 0x0f));
printf("\n");
bzero(&sc->ipmi_bios_info, sizeof(sc->ipmi_bios_info));
bzero((void *)dispatch_smbios_ipmi, sizeof(dispatch_smbios_ipmi));
dispatch_smbios_ipmi[38] = (void *)smbios_t38_proc_info;
smbios_run_table(
(void *)rman_get_virtual(res2),
sc->ipmi_smbios->number_structures,
dispatch_smbios_ipmi,
(void*)&sc->ipmi_bios_info);
bad:
if (res)
bus_release_resource(sc->ipmi_smbios_dev, SYS_RES_MEMORY,
rid, res);
res = NULL;
if (res2)
bus_release_resource(sc->ipmi_smbios_dev, SYS_RES_MEMORY,
rid2, res2);
res2 = NULL;
return 0;
}
static int
ipmi_smbios_attach(device_t dev)
{
struct ipmi_softc *sc = device_get_softc(dev);
int error;
int status, flags;
error = 0;
sc->ipmi_smbios_dev = dev;
sc->ipmi_dev = dev;
ipmi_smbios_query(dev);
if (sc->ipmi_bios_info.kcs_mode) {
if (sc->ipmi_bios_info.io_mode)
device_printf(dev, "KCS mode found at io 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
else
device_printf(dev, "KCS mode found at mem 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
sc->ipmi_kcs_status_reg = sc->ipmi_bios_info.offset;
sc->ipmi_kcs_command_reg = sc->ipmi_bios_info.offset;
sc->ipmi_kcs_data_out_reg = 0;
sc->ipmi_kcs_data_in_reg = 0;
if (sc->ipmi_bios_info.io_mode) {
sc->ipmi_io_rid = 2;
sc->ipmi_io_res = bus_alloc_resource(dev,
SYS_RES_IOPORT, &sc->ipmi_io_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 2),
sc->ipmi_bios_info.offset * 2,
RF_ACTIVE);
} else {
sc->ipmi_mem_rid = 2;
sc->ipmi_mem_res = bus_alloc_resource(dev,
SYS_RES_MEMORY, &sc->ipmi_mem_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 2),
sc->ipmi_bios_info.offset * 2,
RF_ACTIVE);
}
if (!sc->ipmi_io_res){
device_printf(dev,
"couldn't configure smbios io res\n");
goto bad;
}
status = INB(sc, sc->ipmi_kcs_status_reg);
if (status == 0xff) {
device_printf(dev, "couldn't find it\n");
error = ENXIO;
goto bad;
}
if(status & KCS_STATUS_OBF){
ipmi_read(dev, NULL, 0);
}
} else if (sc->ipmi_bios_info.smic_mode) {
if (sc->ipmi_bios_info.io_mode)
device_printf(dev, "SMIC mode found at io 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
else
device_printf(dev, "SMIC mode found at mem 0x%llx "
"alignment 0x%x on %s\n",
(long long)sc->ipmi_bios_info.address,
sc->ipmi_bios_info.offset,
device_get_name(device_get_parent(sc->ipmi_dev)));
sc->ipmi_smic_data = 0;
sc->ipmi_smic_ctl_sts = sc->ipmi_bios_info.offset;
sc->ipmi_smic_flags = sc->ipmi_bios_info.offset * 2;
if (sc->ipmi_bios_info.io_mode) {
sc->ipmi_io_rid = 2;
sc->ipmi_io_res = bus_alloc_resource(dev,
SYS_RES_IOPORT, &sc->ipmi_io_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 3),
sc->ipmi_bios_info.offset * 3,
RF_ACTIVE);
} else {
sc->ipmi_mem_res = bus_alloc_resource(dev,
SYS_RES_MEMORY, &sc->ipmi_mem_rid,
sc->ipmi_bios_info.address,
sc->ipmi_bios_info.address +
(sc->ipmi_bios_info.offset * 2),
sc->ipmi_bios_info.offset * 2,
RF_ACTIVE);
}
if (!sc->ipmi_io_res && !sc->ipmi_mem_res){
device_printf(dev, "couldn't configure smbios res\n");
error = ENXIO;
goto bad;
}
flags = INB(sc, sc->ipmi_smic_flags);
if (flags == 0xff) {
device_printf(dev, "couldn't find it\n");
error = ENXIO;
goto bad;
}
if ((flags & SMIC_STATUS_SMS_ATN)
&& (flags & SMIC_STATUS_RX_RDY)){
/* skip in smbio mode
ipmi_read(dev, NULL, 0);
*/
}
} else {
device_printf(dev, "No IPMI interface found\n");
error = ENXIO;
goto bad;
}
ipmi_attach(dev);
return 0;
bad:
/*
device_delete_child(device_get_parent(dev), dev);
*/
return error;
}
static int
smbios_cksum (struct smbios_table_entry *e)
{
u_int8_t *ptr;
u_int8_t cksum;
int i;
ptr = (u_int8_t *)e;
cksum = 0;
for (i = 0; i < e->length; i++) {
cksum += ptr[i];
}
return cksum;
}
static int
ipmi_smbios_detach (device_t dev)
{
struct ipmi_softc *sc;
sc = device_get_softc(dev);
ipmi_detach(dev);
if (sc->ipmi_ev_tag)
EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_ev_tag);
if (sc->ipmi_mem_res)
bus_release_resource(dev, SYS_RES_MEMORY, sc->ipmi_mem_rid,
sc->ipmi_mem_res);
if (sc->ipmi_io_res)
bus_release_resource(dev, SYS_RES_IOPORT, sc->ipmi_io_rid,
sc->ipmi_io_res);
return 0;
}
static device_method_t ipmi_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, ipmi_smbios_identify),
DEVMETHOD(device_probe, ipmi_smbios_probe),
DEVMETHOD(device_attach, ipmi_smbios_attach),
DEVMETHOD(device_detach, ipmi_smbios_detach),
{ 0, 0 }
};
static driver_t ipmi_smbios_driver = {
"ipmi",
ipmi_methods,
sizeof(struct ipmi_softc),
};
static int
ipmi_smbios_modevent (mod, what, arg)
module_t mod;
int what;
void * arg;
{
device_t * devs;
int count;
int i;
switch (what) {
case MOD_LOAD:
return 0;
case MOD_UNLOAD:
devclass_get_devices(ipmi_devclass, &devs, &count);
for (i = 0; i < count; i++) {
device_delete_child(device_get_parent(devs[i]),
devs[i]);
}
break;
default:
break;
}
return 0;
}
DRIVER_MODULE(ipmi, isa, ipmi_smbios_driver, ipmi_devclass,
ipmi_smbios_modevent, 0);

138
sys/dev/ipmi/ipmivars.h Normal file
View file

@ -0,0 +1,138 @@
/*-
* Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
struct ipmi_get_info {
int kcs_mode;
int smic_mode;
uint64_t address;
int offset;
int io_mode;
};
struct ipmi_softc {
device_t ipmi_dev;
device_t ipmi_smbios_dev;
struct cdev *ipmi_dev_t;
int ipmi_refcnt;
struct smbios_table_entry *ipmi_smbios;
struct ipmi_get_info ipmi_bios_info;
int ipmi_kcs_status_reg;
int ipmi_kcs_command_reg;
int ipmi_kcs_data_out_reg;
int ipmi_kcs_data_in_reg;
int ipmi_smic_data;
int ipmi_smic_ctl_sts;
int ipmi_smic_flags;
int ipmi_io_rid;
struct resource * ipmi_io_res;
int ipmi_mem_rid;
struct resource * ipmi_mem_res;
int ipmi_irq_rid;
struct resource * ipmi_irq_res;
void *ipmi_irq;
u_char ipmi_address;
u_char ipmi_lun;
int ipmi_busy;
struct selinfo ipmi_select;
int ipmi_timestamp;
int ipmi_requests;
struct callout_handle ipmi_timeout_handle;
TAILQ_HEAD(,ipmi_done_list) ipmi_done;
eventhandler_tag ipmi_ev_tag;
};
struct ipmi_ipmb {
u_char foo;
};
/* KCS status flags */
#define KCS_STATUS_OBF 0x01 /* Data Out ready from BMC */
#define KCS_STATUS_IBF 0x02 /* Data In from System */
#define KCS_STATUS_SMS_ATN 0x04 /* Ready in RX queue */
#define KCS_STATUS_C_D 0x08 /* Command/Data register write*/
#define KCS_STATUS_OEM1 0x10
#define KCS_STATUS_OEM2 0x20
#define KCS_STATUS_S0 0x40
#define KCS_STATUS_S1 0x80
#define KCS_STATUS_STATE(x) ((x)>>6)
#define KCS_STATUS_STATE_IDLE 0x0
#define KCS_STATUS_STATE_READ 0x1
#define KCS_STATUS_STATE_WRITE 0x2
#define KCS_STATUS_STATE_ERROR 0x3
#define KCS_IFACE_STATUS_ABORT 0x01
#define KCS_IFACE_STATUS_ILLEGAL 0x02
#define KCS_IFACE_STATUS_LENGTH_ERR 0x06
/* KCD control codes */
#define KCS_CONTROL_GET_STATUS_ABORT 0x60
#define KCS_CONTROL_WRITE_START 0x61
#define KCS_CONTROL_WRITE_END 0x62
#define KCS_DATA_IN_READ 0x68
/* SMIC status flags */
#define SMIC_STATUS_BUSY 0x01 /* System set and BMC clears it */
#define SMIC_STATUS_SMS_ATN 0x04 /* BMC has a message */
#define SMIC_STATUS_EVT_ATN 0x08 /* Event has been RX */
#define SMIC_STATUS_SMI 0x08 /* asserted SMI */
#define SMIC_STATUS_TX_RDY 0x40 /* Ready to accept WRITE */
#define SMIC_STATUS_RX_RDY 0x80 /* Ready to read */
/* SMIC control codes */
#define SMIC_CC_SMS_GET_STATUS 0x40
#define SMIC_CC_SMS_WR_START 0x41
#define SMIC_CC_SMS_WR_NEXT 0x42
#define SMIC_CC_SMS_WR_END 0x43
#define SMIC_CC_SMS_RD_START 0x44
#define SMIC_CC_SMS_RD_NEXT 0x45
#define SMIC_CC_SMS_RD_END 0x46
/* SMIC status codes */
#define SMIC_SC_SMS_RDY 0xc0
#define SMIC_SC_SMS_WR_START 0xc1
#define SMIC_SC_SMS_WR_NEXT 0xc2
#define SMIC_SC_SMS_WR_END 0xc3
#define SMIC_SC_SMS_RD_START 0xc4
#define SMIC_SC_SMS_RD_NEXT 0xc5
#define SMIC_SC_SMS_RD_END 0xc6
#define RES(x) (x)->ipmi_io_res ? (x)->ipmi_io_res : (x)->ipmi_mem_res
#define INB(sc, x) bus_space_read_1(rman_get_bustag(RES(sc)), \
rman_get_bushandle(RES(sc)), (x))
#define OUTB(sc, x, value) bus_space_write_1(rman_get_bustag(RES(sc)), \
rman_get_bushandle(RES(sc)), (x), value)
int ipmi_attach(device_t);
int ipmi_detach(device_t);
int ipmi_smbios_query(device_t);
int ipmi_smbios_probe(device_t);
int ipmi_read(device_t, u_char *, int);
void ipmi_intr(void *);
device_t ipmi_smbios_identify (driver_t *driver, device_t parent);
extern devclass_t ipmi_devclass;
extern int ipmi_attached;

View file

@ -0,0 +1,9 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/ipmi
KMOD= ipmi
SRCS= ipmi.c ipmi_pci.c ipmi_smbios.c
SRCS+= bus_if.h device_if.h pci_if.h vnode_if.h
.include <bsd.kmod.mk>

119
sys/sys/ipmi.h Normal file
View file

@ -0,0 +1,119 @@
/*-
* Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define IPMI_MAX_ADDR_SIZE 0x20
#define IPMI_MAX_RX 1024
#define IPMI_BMC_SLAVE_ADDR 0x20 /* Linux Default slave address */
#define IPMI_BMC_CHANNEL 0x0f /* Linux BMC channel */
#define IPMI_BMC_SMS_LUN 0x02
#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
#define IPMI_IPMB_ADDR_TYPE 0x01
#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41
#define IPMI_IOC_MAGIC 'i'
#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv)
#define IPMICTL_RECEIVE_MSG _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv)
#define IPMICTL_SEND_COMMAND _IOW(IPMI_IOC_MAGIC, 13, struct ipmi_req)
#define IPMICTL_REGISTER_FOR_CMD _IOW(IPMI_IOC_MAGIC, 14, struct ipmi_cmdspec)
#define IPMICTL_UNREGISTER_FOR_CMD _IOW(IPMI_IOC_MAGIC, 15, struct ipmi_cmdspec)
#define IPMICTL_SET_GETS_EVENTS_CMD _IOW(IPMI_IOC_MAGIC, 16, int)
#define IPMICTL_SET_MY_ADDRESS_CMD _IOW(IPMI_IOC_MAGIC, 17, unsigned int)
#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int)
#define IPMICTL_SET_MY_LUN_CMD _IOW(IPMI_IOC_MAGIC, 19, unsigned int)
#define IPMICTL_GET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 20, unsigned int)
#define IPMI_RESPONSE_RECV_TYPE 1
#define IPMI_ASYNC_EVENT_RECV_TYPE 2
#define IPMI_CMD_RECV_TYPE 3
#define IPMI_APP_REQUEST 0x06
#define IPMI_GET_DEVICE_ID 0x01
#define IPMI_CLEAR_FLAGS 0x30
#define IPMI_GET_MSG_FLAGS 0x31
# define IPMI_MSG_AVAILABLE 0x01
# define IPMI_MSG_BUFFER_FULL 0x02
# define IPMI_WDT_PRE_TIMEOUT 0x08
#define IPMI_GET_MSG 0x33
#define IPMI_SEND_MSG 0x34
#define IPMI_GET_CHANNEL_INFO 0x42
#define IPMI_RESET_WDOG 0x22
#define IPMI_SET_WDOG 0x24
#define IPMI_GET_WDOG 0x25
#define IPMI_SET_WD_TIMER_SMS_OS 0x04
#define IPMI_SET_WD_TIMER_DONT_STOP 0x40
#define IPMI_SET_WD_ACTION_RESET 0x01
struct ipmi_msg {
unsigned char netfn;
unsigned char cmd;
unsigned short data_len;
unsigned char *data;
};
struct ipmi_req {
unsigned char *addr;
unsigned int addr_len;
long msgid;
struct ipmi_msg msg;
};
struct ipmi_recv {
int recv_type;
unsigned char *addr;
unsigned int addr_len;
long msgid;
struct ipmi_msg msg;
};
struct ipmi_cmdspec {
unsigned char netfn;
unsigned char cmd;
};
struct ipmi_addr {
int addr_type;
short channel;
unsigned char data[IPMI_MAX_ADDR_SIZE];
};
struct ipmi_system_interface_addr {
int addr_type;
short channel;
unsigned char lun;
};
struct ipmi_ipmb_addr {
int addr_type;
short channel;
unsigned char slave_addr;
unsigned char lun;
};