[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Freeipmi-devel] Get IPMI device info code - 1st cut, RFC
From: |
Ian Zimmerman |
Subject: |
[Freeipmi-devel] Get IPMI device info code - 1st cut, RFC |
Date: |
11 Dec 2003 16:05:01 -0800 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.3 |
/* This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#if HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
/* SMBIOS Reference Specification: map area between 000f0000 and
000fffff. The IPMI Entry Structure begins on a 16-byte boundary,
with a 4 byte "_SM_" signature. */
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <limits.h>
enum ipmi_interface
{
ipmi_interface_kcs = 1,
ipmi_interface_smic = 2,
ipmi_interface_bt = 3,
ipmi_interface_last
};
typedef enum ipmi_interface ipmi_interface_t;
enum ipmi_reg_spacing
{
ipmi_reg_spacing_1 = 0,
ipmi_reg_spacing_2 = 1,
ipmi_reg_spacing_4 = 2,
ipmi_reg_spacing_last
};
typedef enum ipmi_reg_spacing ipmi_reg_spacing_t;
struct ipmi_device_info
{
ipmi_interface_t type;
struct
{
int8_t minor;
int8_t major;
}
version;
u_int8_t i2c_slave_address;
u_int8_t nvstor_device_address;
int bmc_io_mapped;
union
{
u_int64_t bmc_iobase_address;
u_int64_t bmc_membase_address;
}
base;
ipmi_reg_spacing_t reg_spacing;
struct
{
int intinfo_specified;
int intinfo_polarity_high;
int intinfo_trigger_level;
}
intr;
u_int8_t intr_num;
};
#define ipmi_minor version.minor
#define ipmi_major version.major
#define ipmi_membase base.bmc_membase_address
#define ipmi_iobase base.bmc_iobase_address
#define ipmi_int_specified intr.intinfo_specified
#define ipmi_int_polarity intr.intinfo_polarity_high
#define ipmi_int_trigger intr.intinfo_trigger_level
typedef struct ipmi_device_info ipmi_device_info_t;
/* is_ipmi_entry */
/* arguments: */
/* sigp = points to start of purported SMBIOS entry structure */
/* returns: */
/* 0 = not really a SMBIOS entry structure */
/* 1 = yes, a real SMBIOS entry structure */
#define SMBIOS_ENTRY_CSUM_OFFSET 0x4
#define SMBIOS_ENTRY_LEN_OFFSET 0x5
#define SMBIOS_ENTRY_ANCHOR_OFFSET 0x10
#define SMBIOS_ENTRY_ANCHOR_CSUM_OFFSET 0x15
static int
is_ipmi_entry (u_int8_t* sigp)
{
static const char smbios_entry_sig[4] = { '_', 'S', 'M', '_' };
static const char smbios_entry_anchor[5] = { '_', 'D', 'M', 'I', '_' };
u_int32_t csum;
u_int8_t entry_len;
u_int8_t* bp;
if (memcmp (sigp, smbios_entry_sig, sizeof (smbios_entry_sig)) != 0)
return 0;
csum = sigp[SMBIOS_ENTRY_CSUM_OFFSET];
entry_len = sigp[SMBIOS_ENTRY_LEN_OFFSET];
for (bp = sigp; bp < sigp + entry_len; bp++)
csum = (csum + (*bp)) % (1 << CHAR_BIT);
if (csum != 0)
return 0;
if (memcmp (sigp + SMBIOS_ENTRY_ANCHOR_OFFSET, smbios_entry_anchor,
sizeof (smbios_entry_anchor)) != 0)
return 0;
csum = sigp[SMBIOS_ENTRY_ANCHOR_CSUM_OFFSET];
for (bp = sigp + SMBIOS_ENTRY_ANCHOR_CSUM_OFFSET; bp < sigp + entry_len; bp++)
csum = (csum + (*bp)) % (1 << CHAR_BIT);
if (csum != 0)
return 0;
return 1;
}
/* is_ipmi_dev_info */
/* arguments: */
/* type = which interface (KCS, SMIC, BT) */
/* dev_info_p = points to start of purported IPMI device info structure */
/* returns: */
/* 0 = not a IPMI device info structure for TYPE */
/* 1 = yes, IPMI device info structure for TYPE */
#define SMBIOS_IPMI_DEV_INFO_SIG 38
#define SMBIOS_IPMI_DEV_INFO_TYPE_OFFSET 0x4
static int
is_ipmi_dev_info (ipmi_interface_t type, u_int8_t* dev_info_p)
{
if (*dev_info_p != SMBIOS_IPMI_DEV_INFO_SIG)
return 0;
if (dev_info_p[SMBIOS_IPMI_DEV_INFO_TYPE_OFFSET] != type)
return 0;
return 1;
}
/* copy_impi_device_info */
/* arguments: */
/* type = which interface (KCS, SMIC, BT) */
/* statusp = optional (NULL allowed) pointer to store status
information: 1 - structure not found, -1 - error, 0 - success */
/* returns: */
/* pointer to the device info structure in heap (caller responsible
for freeing */
#define SMBIOS_AREA_START 0x000f0000
#define SMBIOS_AREA_END 0x000fffff
#define SMBIOS_AREA_LEN ((SMBIOS_AREA_END - SMBIOS_AREA_START)
+ 1)
#define SMBIOS_AREA_ALIGN 16
#define SMBIOS_ENTRY_TLEN_OFFSET 0x16
#define SMBIOS_ENTRY_PTR_OFFSET 0x18
#define SMBIOS_DEV_INFO_LEN_OFFSET 0x1
static u_int8_t*
copy_impi_device_info (ipmi_interface_t type, int* statusp)
{
int mem_fd;
int status;
u_int8_t* result;
status = 1;
mem_fd = open ("/dev/mem", O_RDONLY);
if (mem_fd != -1)
{
u_int8_t* pmem;
pmem = mmap (NULL, SMBIOS_AREA_LEN, PROT_READ, MAP_PRIVATE,
mem_fd, SMBIOS_AREA_START);
if (pmem != NULL)
{
u_int8_t* sigp;
for (sigp = pmem; sigp - pmem < SMBIOS_AREA_LEN; sigp +=
SMBIOS_AREA_ALIGN)
{
if (is_ipmi_entry (sigp))
{
u_int16_t s_table_len;
u_int8_t* s_table_p;
u_int8_t* dev_info_p;
size_t size;
s_table_len = *(u_int16_t*)(sigp + SMBIOS_ENTRY_TLEN_OFFSET);
s_table_p = (u_int8_t*)(*(u_int32_t*)(sigp +
SMBIOS_ENTRY_PTR_OFFSET));
dev_info_p = s_table_p;
size = dev_info_p[SMBIOS_DEV_INFO_LEN_OFFSET];
while (dev_info_p - s_table_p < s_table_len)
{
if (is_ipmi_dev_info (type, dev_info_p))
{
result = malloc (size);
if (result != NULL)
status = 0;
else
{
errno = ENOMEM;
status = -1;
}
break;
}
dev_info_p += size;
size = dev_info_p[SMBIOS_DEV_INFO_LEN_OFFSET];
}
}
if (status <= 0)
break;
}
munmap (pmem, SMBIOS_AREA_LEN);
}
close (mem_fd);
}
if (statusp != NULL)
*statusp = status;
return (status == 0 ? result : NULL);
}
/* get_ipmi_device_info */
/* arguments: */
/* type = which interface (KCS, SMIC, BT) */
/* pinfo = pointer to information structure filled in by this function */
/* statusp = optional (NULL allowed) pointer to store status
information: 1 - structure not found, -1 - error, 0 - success */
/* returns: */
/* pinfo if successful, NULL otherwise */
#define SMBIOS_IPMI_DEV_INFO_VER_OFFSET 0x5
#define SMBIOS_IPMI_DEV_INFO_I2C_OFFSET 0x6
#define SMBIOS_IPMI_DEV_INFO_NVSTOR_OFFSET 0x7
#define SMBIOS_IPMI_DEV_INFO_ADDRESS_OFFSET 0x8
#define SMBIOS_IPMI_DEV_INFO_MODIFIER_OFFSET 0x10
#define SMBIOS_LSB_BIT 4
#define SMBIOS_REGSPACING_SHIFT 6
#define SMBIOS_REGSPACING_MASK 0x3
#define SMBIOS_INTINFO_PRESENT_BIT 3
#define SMBIOS_INTINFO_POLARITY_BIT 1
#define SMBIOS_INTINFO_TRIGGER_BIT 0
#define SMBIOS_DEV_INFO_INTNUM_OFFSET 0x11
ipmi_device_info_t*
get_ipmi_device_info (ipmi_interface_t type, ipmi_device_info_t* pinfo, int*
statusp)
{
u_int8_t* bufp;
u_int8_t version;
u_int64_t address;
u_int8_t modifier;
u_int8_t lsb;
bufp = copy_impi_device_info (type, statusp);
if (bufp == NULL)
return NULL;
pinfo->type = bufp[SMBIOS_IPMI_DEV_INFO_TYPE_OFFSET];
version = bufp[SMBIOS_IPMI_DEV_INFO_VER_OFFSET];
pinfo->ipmi_major = (version >> 4) & 0xf;
pinfo->ipmi_minor = version & 0xf;
pinfo->i2c_slave_address = bufp[SMBIOS_IPMI_DEV_INFO_I2C_OFFSET];
pinfo->nvstor_device_address = bufp[SMBIOS_IPMI_DEV_INFO_NVSTOR_OFFSET];
address = bufp[SMBIOS_IPMI_DEV_INFO_ADDRESS_OFFSET];
modifier = bufp[SMBIOS_IPMI_DEV_INFO_MODIFIER_OFFSET];
lsb = (modifier >> SMBIOS_LSB_BIT) & 1;
if ((address & 1) != 0)
{
pinfo->bmc_io_mapped = 0;
pinfo->ipmi_iobase = address | lsb;
}
else
{
pinfo->bmc_io_mapped = 1;
pinfo->ipmi_membase = address | lsb;
}
pinfo->reg_spacing = (modifier >> SMBIOS_REGSPACING_SHIFT) &
SMBIOS_REGSPACING_MASK;
if ((modifier >> SMBIOS_INTINFO_PRESENT_BIT) & 1 != 0)
{
pinfo->ipmi_int_specified = 1;
pinfo->ipmi_int_polarity = (modifier >> SMBIOS_INTINFO_POLARITY_BIT) & 1;
pinfo->ipmi_int_trigger = (modifier >> SMBIOS_INTINFO_TRIGGER_BIT) & 1;
}
else
pinfo->ipmi_int_specified = 0;
pinfo->intr_num = bufp[SMBIOS_DEV_INFO_INTNUM_OFFSET];
free (bufp);
return pinfo;
}
- [Freeipmi-devel] kcs byte array model - validation, Anand Babu, 2003/12/09
- Re: [Freeipmi-devel] kcs byte array model - validation, Albert Chu, 2003/12/09
- Re: [Freeipmi-devel] kcs byte array model - validation, Albert Chu, 2003/12/09
- Re: [Freeipmi-devel] kcs byte array model - validation, Anand Babu, 2003/12/09
- [Freeipmi-devel] Get IPMI device info code - 1st cut, RFC,
Ian Zimmerman <=
- Re: [Freeipmi-devel] Get IPMI device info code - 1st cut, RFC, Anand Babu, 2003/12/11
- Re: [Freeipmi-devel] Get IPMI device info code - 1st cut, RFC, Ian Zimmerman, 2003/12/11
- Re: [Freeipmi-devel] Get IPMI device info code - 1st cut, RFC, Anand Babu, 2003/12/12
Re: [Freeipmi-devel] kcs byte array model - validation, Albert Chu, 2003/12/10