/*
* ipmi_sdr.cpp
*
* Copyright (c) 2003,2004 by FORCE Computers
* Copyright (c) 2005-2007 by ESO Technologies.
*
* Note that this file is based on parts of OpenIPMI
* written by Corey Minyard <minyard@mvista.com>
* of MontaVista Software. Corey's code was helpful
* and many thanks go to him. He gave the permission
* to use this code in OpenHPI under BSD license.
*
* 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. This
* file and program are licensed under a BSD style license. See
* the Copying file included with the OpenHPI distribution for
* full licensing terms.
*
* Authors:
* Thomas Kanngieser <thomas.kanngieser@fci.com>
* Pierre Sangouard <psangouard@eso-tech.com>
* Andy Cress <arcress@user.sourceforge.net>
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include "ipmi_mc.h"
#include "ipmi_cmd.h"
#include "ipmi_log.h"
#include "ipmi_utils.h"
#include "ipmi_text_buffer.h"
#include "ipmi_sensor_threshold.h"
static const char *repository_sdr_update_map[] =
{
"Unspecified",
"NonModal",
"Modal",
"Both"
};
static int repository_sdr_update_num = sizeof( repository_sdr_update_map )
/ sizeof( char * );
const char *
IpmiRepositorySdrUpdateToString( tIpmiRepositorySdrUpdate val )
{
if ( (int)val >= repository_sdr_update_num )
return "Invalid";
return repository_sdr_update_map[val];
}
struct cIpmiSdrTypeToName
{
tIpmiSdrType m_type;
const char *m_name;
};
static cIpmiSdrTypeToName type_to_name[] =
{
{ eSdrTypeFullSensorRecord , "FullSensor" },
{ eSdrTypeCompactSensorRecord , "CompactSensor" },
{ eSdrTypeEventOnlySensorRecord , "EventOnlySensor" },
{ eSdrTypeEntityAssociationRecord , "EntityAssociation" },
{ eSdrTypeDeviceRelativeEntityAssociationRecord, "DeviceRelativeEntityAssociation" },
{ eSdrTypeGenericDeviceLocatorRecord , "GenericDeviceLocator" },
{ eSdrTypeFruDeviceLocatorRecord , "FruDeviceLocator" },
{ eSdrTypeMcDeviceLocatorRecord , "McDeviceLocator" },
{ eSdrTypeMcConfirmationRecord , "McConfirmation" },
{ eSdrTypeBmcMessageChannelInfoRecord , "BmcMessageChannelInfo" },
{ eSdrTypeOemRecord , "Oem" },
{ eSdrTypeUnknown, 0 }
};
const char *
IpmiSdrTypeToName( tIpmiSdrType type )
{
if ( type == eSdrTypeUnknown )
return "Unknown";
for( cIpmiSdrTypeToName *t = type_to_name; t->m_name; t++ )
if ( t->m_type == type )
return t->m_name;
return "Invalid";
}
static bool
Bit( unsigned char v, int bit )
{
return v & (1<<bit);
}
void
cIpmiSdr::DumpFullSensor( cIpmiLog &dump ) const
{
char str[256];
dump.Entry( "SlaveAddress" ) << m_data[5] << ";\n";
dump.Entry( "Channel" ) << (int)(m_data[6] >> 4) << ";\n";
dump.Entry( "Lun" ) << (int)(m_data[6] & 0x3) << ";\n";
dump.Entry( "SensorNum" ) << m_data[7] << ";\n";
tIpmiEntityId id = (tIpmiEntityId)m_data[8];
if ( !strcmp( IpmiEntityIdToString( id ), "Invalid" ) )
snprintf( str, sizeof(str), "0x%02x", id );
else
snprintf( str, sizeof(str), "%s", IpmiEntityIdToString( id ) );
dump.Entry( "EntityId" ) << str << ";\n";
dump.Entry( "EntityInstance" ) << (int)m_data[9] << ";\n";
dump.Entry( "InitScanning" ) << Bit( m_data[10], 6 ) << ";\n";
dump.Entry( "InitEvents" ) << Bit( m_data[10], 5 ) << ";\n";
dump.Entry( "InitThresholds" ) << Bit( m_data[10], 4 ) << ";\n";
dump.Entry( "InitHysteresis" ) << Bit( m_data[10], 3 ) << ";\n";
dump.Entry( "InitSensorType" ) << Bit( m_data[10], 2 ) << ";\n";
dump.Entry( "SensorInitPuEvents" ) << Bit( m_data[10], 1 ) << ";\n";
dump.Entry( "SensorInitPuScanning" ) << Bit( m_data[10], 0 ) << ";\n";
dump.Entry( "IgnoreIfNoEntity" ) << Bit( m_data[11], 7 ) << ";\n";
dump.Entry( "SupportsAutoRearm" ) << Bit( m_data[11], 6 ) << ";\n";
tIpmiHysteresisSupport hs = (tIpmiHysteresisSupport)((m_data[11] >> 4) & 3);
dump.Entry( "HysteresisSupport" ) << IpmiHysteresisSupportToString( hs ) << ";\n";
tIpmiThresholdAccessSuport ts = (tIpmiThresholdAccessSuport)((m_data[11] >> 2) & 3);
dump.Entry( "ThresholdAccess" ) << IpmiThresholdAccessSupportToString( ts ) << ";\n";
tIpmiEventSupport es = (tIpmiEventSupport)(m_data[11] & 3);
dump.Entry( "EventSupport" ) << IpmiEventSupportToString( es ) << ";\n";
tIpmiSensorType sensor_type = (tIpmiSensorType)m_data[12];
if ( !strcmp( IpmiSensorTypeToString( sensor_type ), "Invalid" ) )
snprintf( str, sizeof(str), "0x%02x", sensor_type );
else
snprintf( str, sizeof(str), "%s", IpmiSensorTypeToString( sensor_type ) );
dump.Entry( "SensorType" ) << str << ";\n";
tIpmiEventReadingType reading_type = (tIpmiEventReadingType)m_data[13];
if ( !strcmp( IpmiEventReadingTypeToString( reading_type ), "Invalid" ) )
snprintf( str, sizeof(str), "0x%02x", reading_type );
else
snprintf( str, sizeof(str), "%s", IpmiEventReadingTypeToString( reading_type ) );
dump.Entry( "EventReadingType" ) << str << ";\n";
if ( reading_type == eIpmiEventReadingTypeThreshold )
{
// assertion
unsigned short em = IpmiGetUint16( m_data + 14 );
IpmiThresholdEventMaskToString( em, str );
if ( str[0] == 0 )
strcat( str, "0" );
dump.Entry( "AssertionEventMask" ) << str << ";\n";
snprintf( str, sizeof(str), "0x%04x", em >> 12 );
dump.Entry( "LowerThresholdReadingMask" ) << str << ";\n";
// deassertion
em = IpmiGetUint16( m_data + 16 );
IpmiThresholdEventMaskToString( em, str );
if ( str[0] == 0 )
strcat( str, "0" );
dump.Entry( "DeassertionEventMask" ) << str << ";\n";
snprintf( str, sizeof(str), "0x%04x", em >> 12 );
dump.Entry( "UpperThresholdReadingMask" ) << str << ";\n";
// settable threshold
em = IpmiGetUint16( m_data + 18 );
IpmiThresholdMaskToString( em >> 8, str );
if ( str[0] == 0 )
strcat( str, "0" );
dump.Entry( "SettableThresholdsMask" ) << str << ";\n";
IpmiThresholdMaskToString( em & 0xff, str );
if ( str[0] == 0 )
strcat( str, "0" );
dump.Entry( "ReadableThresholdsMask" ) << str << ";\n";
tIpmiRateUnit ru = (tIpmiRateUnit)((m_data[20] >> 3) & 7);
dump.Entry( "RateUnit" ) << IpmiRateUnitToString( ru ) << ";\n";
tIpmiModifierUnit mu = (tIpmiModifierUnit)( (m_data[20] >> 1) & 3);
dump.Entry( "ModifierUnit" ) << IpmiModifierUnitToString( mu ) << ";\n";
dump.Entry( "Percentage" ) << ((m_data[20] & 1) == 1) << ";\n";
dump.Entry( "BaseUnit" ) << IpmiUnitTypeToString( (tIpmiUnitType)m_data[21] ) << ";\n";
dump.Entry( "ModifierUnit2" ) << IpmiUnitTypeToString( (tIpmiUnitType)m_data[22] ) << ";\n";
cIpmiSensorFactors sf;
sf.GetDataFromSdr( this );
dump.Entry( "AnalogDataFormat" ) << IpmiAnalogeDataFormatToString( sf.AnalogDataFormat() ) << ";\n";
dump.Entry( "Linearization" ) << IpmiLinearizationToString( sf.Linearization() ) << ";\n";
dump.Entry( "M" ) << sf.M() << ";\n";
dump.Entry( "Tolerance" ) << sf.Tolerance() << ";\n";
dump.Entry( "B" ) << sf.B() << ";\n";
dump.Entry( "Accuracy" ) << sf.Accuracy() << ";\n";
dump.Entry( "AccuracyExp" ) << sf.AccuracyExp() << ";\n";
dump.Entry( "RExp" ) << sf.RExp() << ";\n";
dump.Entry( "BExp" ) << sf.BExp() << ";\n";
bool v = m_data[30] & 1;
dump.Entry( "NominalReadingSpecified" ) << v << ";\n";
if ( v )
dump.Entry( "NominalReading" ) << m_data[31] << ";\n";
v = m_data[30] & 2;
dump.Entry( "NormalMaxSpecified" ) << v << ";\n";
if ( v )
dump.Entry( "NormalMax" ) << m_data[32] << ";\n";
v = m_data[30] & 4;
dump.Entry( "NormalMinSpecified" ) << v << ";\n";
if ( v )
dump.Entry( "NormalMin" ) << m_data[33] << ";\n";
dump.Entry( "SensorMax" ) << m_data[34] << ";\n";
dump.Entry( "SensorMin" ) << m_data[35] << ";\n";
dump.Entry( "UpperNonRecoverableThreshold" ) << m_data[36] << ";\n";
dump.Entry( "UpperCriticalThreshold" ) << m_data[37] << ";\n";
dump.Entry( "UpperNonCriticalThreshold" ) << m_data[38] << ";\n";
dump.Entry( "LowerNonRecoverableThreshold" ) << m_data[39] << ";\n";
dump.Entry( "LowerCriticalThreshold" ) << m_data[40] << ";\n";
dump.Entry( "LowerNonCriticalThreshold" ) << m_data[41] << ";\n";
dump.Entry( "PositiveGoingThresholdHysteresis" ) << m_data[42] << ";\n";
dump.Entry( "NegativeGoingThresholdHysteresis" ) << m_data[43] << ";\n";
}
else
{
// assertion
unsigned short em = IpmiGetUint16( m_data + 14 );
dump.Hex( true );
dump.Entry( "AssertionEventMask" ) << em << ";\n";
// deassertion
em = IpmiGetUint16( m_data + 16 );
dump.Entry( "DeassertionEventMask" ) << em << ";\n";
// event mask
em = IpmiGetUint16( m_data + 18 );
dump.Entry( "DiscreteReadingMask" ) << em << ";\n";
dump.Hex( false );
}
dump.Entry( "Oem" ) << m_data[46] << ";\n";
cIpmiTextBuffer tb;
tb.SetIpmi( m_data + 47 );
tb.GetAscii( str, 80 );
dump.Entry( "Id" ) << "\"" << str << "\";\n";
}
void
cIpmiSdr::DumpFruDeviceLocator( cIpmiLog &dump ) const
{
dump.Entry( "DeviceAccessAddress" ) << m_data[5] << ";\n";
if ( m_data[7] & 0x80 )
{
// logical FRU device
dump.Entry( "FruDeviceId" ) << (int)m_data[6] << ";\n";
}
else
{
// device is directly on IPMB
dump.Entry( "SlaveAddress" ) << m_data[6] << ";\n";
dump.Entry( "Lun" ) << (int)((m_data[7] >> 3) & 3) << ";\n";
}
dump.Entry( "LogicalDevice" ) << Bit(m_data[7], 7 ) << ";\n";
dump.Entry( "Channel" ) << (int)(m_data[8] >> 4) << ";\n";
dump.Entry( "DeviceType" ) << m_data[10] << ";\n";
dump.Entry( "DeviceTypeModifier" ) << m_data[11] << ";\n";
tIpmiEntityId id = (tIpmiEntityId)m_data[12];
char str[80];
if ( !strcmp( IpmiEntityIdToString( id ), "Invalid" ) )
snprintf( str, sizeof(str), "0x%02x", id );
else
snprintf( str, sizeof(str), "%s", IpmiEntityIdToString( id ) );
dump.Entry( "EntityId" ) << str << ";\n";
dump.Entry( "EntityInstance" ) << (int)m_data[13] << ";\n";
dump.Entry( "Oem" ) << m_data[14] << ";\n";
cIpmiTextBuffer tb;
tb.SetIpmi( m_data + 15 );
tb.GetAscii( str, 80 );
dump.Entry( "Id" ) << "\"" << str << "\";\n";
}
void
cIpmiSdr::DumpMcDeviceLocator( cIpmiLog &dump ) const
{
dump.Entry( "SlaveAddress" ) << m_data[5] << ";\n";
dump.Entry( "Channel" ) << (int)(m_data[6] & 0x0f) << ";\n";
dump.Entry( "AcpiSystemPower" ) << Bit( m_data[7], 7 ) << ";\n";
dump.Entry( "AcpiDevicePower" ) << Bit( m_data[7], 6 ) << ";\n";
dump.Entry( "ControllerLogInitAgentErrors" ) << Bit( m_data[7], 3 ) << ";\n";
dump.Entry( "LogInitializationAgentError" ) << Bit( m_data[7], 2 ) << ";\n";
dump.Entry( "EventMessageGeneration" ) << ( m_data[7] & 3 ) << ";\n";
dump.Entry( "ChassisSupport" ) << Bit( m_data[8], 7 ) << ";\n";
dump.Entry( "BridgeSupport" ) << Bit( m_data[8], 6 ) << ";\n";
dump.Entry( "IpmbEventGeneratorSupport" ) << Bit( m_data[8], 5 ) << ";\n";
dump.Entry( "IpmbEventReceiverSupport" ) << Bit( m_data[8], 4 ) << ";\n";
dump.Entry( "FruInventorySupport" ) << Bit( m_data[8], 3 ) << ";\n";
dump.Entry( "SelDeviceSupport" ) << Bit( m_data[8], 2 ) << ";\n";
dump.Entry( "SdrRepositorySupport" ) << Bit( m_data[8], 1 ) << ";\n";
dump.Entry( "SensorDeviceSupport" ) << Bit( m_data[8], 0 ) << ";\n";
tIpmiEntityId id = (tIpmiEntityId)m_data[12];
char str[80];
if ( !strcmp( IpmiEntityIdToString( id ), "Invalid" ) )
snprintf( str, sizeof(str), "0x%02x", id );
else
snprintf( str, sizeof(str), "%s", IpmiEntityIdToString( id ) );
dump.Entry( "EntityId" ) << str << ";\n";
dump.Entry( "EntityInstance" ) << (int)m_data[13] << ";\n";
dump.Entry( "Oem" ) << m_data[14] << ";\n";
cIpmiTextBuffer tb;
tb.SetIpmi( m_data + 15 );
tb.GetAscii( str, 80 );
dump.Entry( "Id" ) << "\"" << str << "\";\n";
}
void
cIpmiSdr::Dump( cIpmiLog &dump, const char *name ) const
{
char str[80];
snprintf( str, sizeof(str), "%sRecord", IpmiSdrTypeToName( m_type ) );
dump.Begin( str, name );
dump.Entry( "Type" ) << IpmiSdrTypeToName( m_type ) << "\n";
dump.Entry( "RecordId" ) << m_record_id << ";\n";
dump.Entry( "Version" ) << (int)m_major_version << ", "
<< (int)m_minor_version << ";\n";
switch( m_type )
{
case eSdrTypeFullSensorRecord:
DumpFullSensor( dump );
break;
case eSdrTypeFruDeviceLocatorRecord:
DumpFruDeviceLocator( dump );
break;
case eSdrTypeMcDeviceLocatorRecord:
DumpMcDeviceLocator( dump );
break;
default:
dump.Entry( "SDR Type " ) << m_type << ";\n";
break;
}
dump.End();
}
static void
IpmiSdrDestroyRecords( cIpmiSdr **&sdr, unsigned int &n )
{
if ( sdr == 0 )
return;
for( unsigned int i = 0; i < n; i++ )
{
assert( sdr[i] );
delete sdr[i];
}
delete [] sdr;
n = 0;
sdr = 0;
}
cIpmiSdrs::cIpmiSdrs( cIpmiMc *mc, bool device_sdr )
: m_mc( mc ), m_device_sdr( device_sdr ),
m_fetched( false ), m_major_version( 0 ), m_minor_version( 0 ),
m_last_addition_timestamp( 0 ), m_last_erase_timestamp( 0 ),
m_overflow( 0 ), m_update_mode( eIpmiRepositorySdrUpdateUnspecified ),
m_supports_delete_sdr( false ), m_supports_partial_add_sdr( false ),
m_supports_reserve_sdr( false ), m_supports_get_sdr_repository_allocation( false ),
m_reservation( 0 ), m_sdr_changed( false ),
m_num_sdrs( 0 ), m_sdrs( 0 )
{
for( int i = 0; i < 4; i++ )
m_lun_has_sensors[i] = false;
}
cIpmiSdrs::~cIpmiSdrs()
{
if ( m_sdrs )
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
}
cIpmiSdr *
cIpmiSdrs::ReadRecord( unsigned short record_id,
unsigned short &next_record_id,
tReadRecord &err, unsigned int lun )
{
cIpmiMsg msg;
cIpmiMsg rsp;
SaErrorT rv;
int offset = 0;
unsigned char data[dMaxSdrData];
int record_size = 0;
int read_len = 0;
cIpmiSdr *sdr;
memset( data, 0xaa, dMaxSdrData );
do
{
if ( m_device_sdr )
{
msg.m_netfn = eIpmiNetfnSensorEvent;
msg.m_cmd = eIpmiCmdGetDeviceSdr;
}
else
{
msg.m_netfn = eIpmiNetfnStorage;
msg.m_cmd = eIpmiCmdGetSdr;
}
msg.m_data_len = 6;
IpmiSetUint16( msg.m_data, m_reservation );
IpmiSetUint16( msg.m_data + 2, record_id );
msg.m_data[4] = offset;
if ( offset == 0 )
read_len = dSdrHeaderSize;
else
{
read_len = record_size - offset;
if ( read_len > dMaxSdrFetch )
read_len = dMaxSdrFetch;
}
msg.m_data[5] = read_len;
rv = m_mc->SendCommand( msg, rsp, lun );
if ( rv != SA_OK )
{
stdlog << "initial_sdr_fetch: Couldn't send GetSdr or GetDeviveSdr fetch: " << rv << " !\n";
err = eReadError;
return 0;
}
if ( rsp.m_data[0] == 0x80 )
{
// Data changed during fetch, retry. Only do this so many
// times before giving up.
stdlog << "SDR reservation lost 1.\n";
err = eReadReservationLost;
return 0;
}
if ( rsp.m_data[0] == eIpmiCcInvalidReservation )
{
stdlog << "SDR reservation lost 2.\n";
err = eReadReservationLost;
return 0;
}
if ( record_id == 0
&& ( (rsp.m_data[0] == eIpmiCcUnknownErr )
|| (rsp.m_data[0] == eIpmiCcNotPresent ) ) )
{
// We got an error fetching the first SDR, so the repository is
// probably empty. Just go on.
stdlog << "SDR reservation lost 3.\n";
err = eReadEndOfSdr;
return 0;
}
if ( rsp.m_data[0] != eIpmiCcOk )
{
stdlog << "SDR fetch error getting sdr " << record_id << ": "
<< rsp.m_data[0] << " !\n";
err = eReadError;
return 0;
}
if ( rsp.m_data_len != read_len + 3 )
{
stdlog << "Got an invalid amount of SDR data: " << rsp.m_data_len
<< ", expected " << read_len + 3 << " !\n";
err = eReadError;
return 0;
}
// copy the data
memcpy( data + offset, rsp.m_data + 3, read_len );
// header => get record size
if ( offset == 0 )
{
record_size = rsp.m_data[7] + dSdrHeaderSize;
next_record_id = IpmiGetUint16( rsp.m_data + 1 );
}
offset += read_len;
}
while( offset < record_size );
// create sdr
sdr = new cIpmiSdr;
memset( sdr, 0, sizeof( cIpmiSdr ));
sdr->m_record_id = IpmiGetUint16( data );
sdr->m_major_version = data[2] & 0xf;
sdr->m_minor_version = (data[2] >> 4) & 0xf;
sdr->m_type = (tIpmiSdrType)data[3];
// Hack to support 1.0 MCs
if ( (sdr->m_major_version == 1)
&& (sdr->m_minor_version == 0)
&& (sdr->m_type == eSdrTypeMcDeviceLocatorRecord))
{
data[8] = data[7];
data[7] = data[6];
data[6] = 0;
}
sdr->m_length = record_size;
memcpy( sdr->m_data, data, record_size );
err = eReadOk;
return sdr;
}
SaErrorT
cIpmiSdrs::Reserve(unsigned int lun)
{
cIpmiMsg msg;
cIpmiMsg rsp;
SaErrorT rv;
if ( !m_supports_reserve_sdr )
{
stdlog << "cIpmiSdrs::Reserve: Reserve SDR not supported\n";
return SA_ERR_HPI_INTERNAL_ERROR;
}
// Now get the reservation.
if ( m_device_sdr )
{
msg.m_netfn = eIpmiNetfnSensorEvent;
msg.m_cmd = eIpmiCmdReserveDeviceSdrRepository;
}
else
{
msg.m_netfn = eIpmiNetfnStorage;
msg.m_cmd = eIpmiCmdReserveSdrRepository;
}
msg.m_data_len = 0;
rv = m_mc->SendCommand( msg, rsp, lun );
if ( rv != SA_OK )
{
stdlog << "Couldn't send SDR reservation: " << rv << " !\n";
return rv;
}
if ( rsp.m_data[0] != 0)
{
if ( m_device_sdr
&& rsp.m_data[0] == eIpmiCcInvalidCmd )
{
// This is a special case. We always attempt a
// reservation with a device SDR (since there is nothing
// telling us if this is supported), if it fails then we
// just go on without the reservation.
m_supports_reserve_sdr = false;
m_reservation = 0;
return SA_OK;
}
stdlog << "Error getting SDR fetch reservation: " << rsp.m_data[0] << " !\n";
return SA_ERR_HPI_INVALID_PARAMS;
}
if ( rsp.m_data_len < 3 )
{
stdlog << "SDR Reservation data not long enough: " << rsp.m_data_len << " bytes!\n";
return SA_ERR_HPI_INVALID_DATA;
}
m_reservation = IpmiGetUint16( rsp.m_data + 1 );
return SA_OK;
}
SaErrorT
cIpmiSdrs::GetInfo( unsigned short &working_num_sdrs )
{
SaErrorT rv;
cIpmiMsg msg;
cIpmiMsg rsp;
unsigned int add_timestamp;
unsigned int erase_timestamp;
// sdr info
if ( m_device_sdr )
{
msg.m_netfn = eIpmiNetfnSensorEvent;
msg.m_cmd = eIpmiCmdGetDeviceSdrInfo;
}
else
{
msg.m_netfn = eIpmiNetfnStorage;
msg.m_cmd = eIpmiCmdGetSdrRepositoryInfo;
}
msg.m_data_len = 0;
rv = m_mc->SendCommand( msg, rsp );
if ( rv != SA_OK )
{
stdlog << "IpmiSdrsFetch: GetDeviceSdrInfoCmd or GetSdrRepositoryInfoCmd "
<< rv << ", " << strerror( rv ) << " !\n";
m_sdr_changed = true;
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
return rv;
}
if ( rsp.m_data[0] != 0 )
{
if ( m_device_sdr == false )
{
// The device doesn't support the get device SDR info
// command, so just assume some defaults.
working_num_sdrs = 0xfffe;
m_dynamic_population = false;
// Assume it uses reservations, if the reservation returns
// an error, then say that it doesn't.
m_supports_reserve_sdr = true;
m_lun_has_sensors[0] = true;
m_lun_has_sensors[1] = false;
m_lun_has_sensors[2] = false;
m_lun_has_sensors[3] = false;
add_timestamp = 0;
erase_timestamp = 0;
}
else
{
stdlog << "IPMI Error getting SDR info: " << rsp.m_data[0] << " !\n";
m_sdr_changed = true;
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
return SA_ERR_HPI_INVALID_PARAMS;
}
}
else if ( m_device_sdr )
{
// device SDR
if ( rsp.m_data_len < 3 )
{
stdlog << "SDR info is not long enough !\n";
m_sdr_changed = true;
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
return SA_ERR_HPI_INVALID_DATA;
}
working_num_sdrs = rsp.m_data[1];
m_dynamic_population = (rsp.m_data[2] & 0x80) == 0x80;
// Assume it uses reservations, if the reservation returns
// an error, then say that it doesn't.
m_supports_reserve_sdr = true;
m_lun_has_sensors[0] = (rsp.m_data[2] & 0x01) == 0x01;
m_lun_has_sensors[1] = (rsp.m_data[2] & 0x02) == 0x02;
m_lun_has_sensors[2] = (rsp.m_data[2] & 0x04) == 0x04;
m_lun_has_sensors[3] = (rsp.m_data[2] & 0x08) == 0x08;
if ( m_dynamic_population )
{
if ( rsp.m_data_len < 7 )
{
stdlog << "SDR info is not long enough !\n";
m_sdr_changed = 1;
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
return SA_ERR_HPI_INVALID_DATA;
}
add_timestamp = IpmiGetUint32( rsp.m_data + 3 );
}
else
add_timestamp = 0;
erase_timestamp = 0;
}
else
{
// repository SDR
if ( rsp.m_data_len < 15 )
{
stdlog << "SDR info is not long enough\n";
m_sdr_changed = true;
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
return SA_ERR_HPI_INVALID_DATA;
}
/* Pull pertinant info from the response. */
m_major_version = rsp.m_data[1] & 0xf;
m_minor_version = (rsp.m_data[1] >> 4) & 0xf;
working_num_sdrs = IpmiGetUint16( rsp.m_data + 2 );
m_overflow = (rsp.m_data[14] & 0x80) == 0x80;
m_update_mode = (tIpmiRepositorySdrUpdate)((rsp.m_data[14] >> 5) & 0x3);
m_supports_delete_sdr = (rsp.m_data[14] & 0x08) == 0x08;
m_supports_partial_add_sdr = (rsp.m_data[14] & 0x04) == 0x04;
m_supports_reserve_sdr = (rsp.m_data[14] & 0x02) == 0x02;
m_supports_get_sdr_repository_allocation
= (rsp.m_data[14] & 0x01) == 0x01;
add_timestamp = IpmiGetUint32( rsp.m_data + 6 );
erase_timestamp = IpmiGetUint32( rsp.m_data + 10 );
}
// If the timestamps still match, no need to re-fetch the repository
if ( m_fetched
&& ( add_timestamp == m_last_addition_timestamp )
&& ( erase_timestamp == m_last_erase_timestamp ) )
return -1;
m_last_addition_timestamp = add_timestamp;
m_last_erase_timestamp = erase_timestamp;
return SA_OK;
}
SaErrorT
cIpmiSdrs::ReadRecords( cIpmiSdr **&records, unsigned short &working_num_sdrs,
unsigned int &num, unsigned int lun )
{
int retry_count = 0;
bool loop = true;
unsigned short save_working = working_num_sdrs;
unsigned int save_num = num;
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
while( loop )
{
unsigned short next_record_id = 0;
working_num_sdrs = save_working;
num = save_num;
if ( retry_count++ == dMaxSdrFetchRetries )
{
stdlog << "Too many retries trying to fetch SDRs\n";
return SA_ERR_HPI_BUSY;
}
SaErrorT rv = Reserve(lun);
if ( rv )
return rv;
// read sdr records
while( 1 )
{
tReadRecord err;
unsigned short record_id = next_record_id;
cIpmiSdr *sdr = ReadRecord( record_id, next_record_id, err, lun );
if ( sdr == 0 )
{
if ( err == eReadReservationLost )
{
stdlog << "MC " << (unsigned char)m_mc->GetAddress() << " Lost SDR reservation " << retry_count << " - sleeping\n";
// Most likely the Shelf Manager is trying to access the device SDR too
// Give him a break and wait till it's done
ts.tv_sec = 5+2*retry_count;
nanosleep(&ts, NULL);
break;
}
if ( err != eReadEndOfSdr )
return SA_ERR_HPI_BUSY;
// SDR is empty
loop = false;
break;
}
GList *list = 0;
if (( sdr->m_type == eSdrTypeCompactSensorRecord ) ||
( sdr->m_type == eSdrTypeEventOnlySensorRecord ))
{
// convert compact sensor record to full sensor records
list = CreateFullSensorRecords( sdr );
delete sdr;
}
else
list = g_list_append( 0, sdr );
while( list )
{
sdr = (cIpmiSdr *)list->data;
list = g_list_remove( list, sdr );
sdr->Dump( stdlog, "sdr" );
if ( num >= working_num_sdrs )
{
// resize records
cIpmiSdr **rec = new cIpmiSdr*[ working_num_sdrs + 10 ];
memcpy( rec, records, sizeof( cIpmiSdr * ) * working_num_sdrs );
delete [] records;
records = rec;
working_num_sdrs += 10;
}
records[num++] = sdr;
}
if ( next_record_id == 0xffff )
{
// finish
loop = false;
break;
}
}
}
return SA_OK;
}
GList *
cIpmiSdrs::CreateFullSensorRecords( cIpmiSdr *sdr )
{
int n = 1;
int itag, len;
if (sdr->m_data[3] == eSdrTypeEventOnlySensorRecord ) n = 1;
else if ( sdr->m_data[23] & 0x0f )
n = sdr->m_data[23] & 0x0f;
GList *list = 0;
for( int i = 0; i < n; i++ )
{
cIpmiSdr *s = new cIpmiSdr;
*s = *sdr;
s->m_type = eSdrTypeFullSensorRecord;
memset( s->m_data + 23, 0, dMaxSdrData - 23 );
// sensor num
s->m_data[7] = sdr->m_data[7] + i;
// entity instance
if ( sdr->m_data[24] & 0x80 )
s->m_data[9] = sdr->m_data[9] + i;
if (sdr->m_data[3] == eSdrTypeEventOnlySensorRecord )
{
itag = 16; /* sdr[17] = tag*/
len = sdr->m_data[itag] & 0x3f;
memcpy( s->m_data + 47, sdr->m_data + itag, len + 1 );
}
else /*Compact SDRs*/
{
itag = 31; /*Compact: sdr[32] = tag*/
// positive-going threshold hysteresis value
s->m_data[42] = sdr->m_data[25];
// negativ-going threshold hysteresis value
s->m_data[43] = sdr->m_data[26];
// oem
s->m_data[46] = sdr->m_data[30];
// id (tag)
int val = (sdr->m_data[24] & 0x7f) + i;
len = sdr->m_data[itag] & 0x3f;
memcpy( s->m_data + 47, sdr->m_data + itag, len + 1 );
if (n > 1)
{
int base = 0;
int start = 0;
if (( sdr->m_data[23] & 0x30 ) == 0 )
{
// numeric
base = 10;
start = '0';
}
else if (( sdr->m_data[23] & 0x30 ) == 0x10 )
{
// alpha
base = 26;
start = 'A';
}
if ( base )
{
// add id string postfix
if ( val / base > 0 )
{
s->m_data[48+len] = (val / base) + start;
len++;
}
s->m_data[48+len] = (val % base) + start;
len++;
s->m_data[48+len] = 0;
s->m_data[47] = (sdr->m_data[31] & 0xc0) | len;
}
}
} /*end-else compact*/
list = g_list_append( list, s );
}
return list;
}
SaErrorT
cIpmiSdrs::Fetch()
{
SaErrorT rv;
cIpmiSdr **records;
unsigned short working_num_sdrs;
m_sdr_changed = false;
assert( m_mc );
if ( m_device_sdr )
{
m_device_sdr = m_mc->ProvidesDeviceSdrs(); /* added ARCress 09/21/06 */
// if ( !m_mc->ProvidesDeviceSdrs() ) return SA_ERR_HPI_NOT_PRESENT;
}
else if ( !m_mc->SdrRepositorySupport() )
return SA_ERR_HPI_NOT_PRESENT;
// working num sdrs is just an estimation
rv = GetInfo( working_num_sdrs );
// sdr records are up to date
if ( rv == -1 )
return SA_OK;
if ( rv )
return rv;
m_sdr_changed = true;
IpmiSdrDestroyRecords( m_sdrs, m_num_sdrs );
// because working_num_sdrs is an estimation
// read the sdr to get the real number
if ( working_num_sdrs == 0 )
working_num_sdrs = 1;
// read sdr
unsigned int num = 0;
records = new cIpmiSdr *[working_num_sdrs];
rv = SA_OK;
if ( m_device_sdr )
{
for( unsigned int i = 0; rv == SA_OK && i < 4; i++ )
if ( m_lun_has_sensors[i] )
rv = ReadRecords( records, working_num_sdrs, num, i );
}
else
rv = ReadRecords( records, working_num_sdrs, num, 0 );
if ( rv != SA_OK )
{
IpmiSdrDestroyRecords( records, num );
return rv;
}
if ( num == 0 )
{
delete [] records;
m_sdrs = 0;
m_num_sdrs = 0;
return SA_OK;
}
if ( num == working_num_sdrs )
{
m_sdrs = records;
m_num_sdrs = working_num_sdrs;
return SA_OK;
}
m_sdrs = new cIpmiSdr *[num];
memcpy( m_sdrs, records, num * sizeof( cIpmiSdr * ) );
m_num_sdrs = num;
delete [] records;
return SA_OK;
}
void
cIpmiSdrs::Dump( cIpmiLog &dump, const char *name ) const
{
unsigned int i;
char str[80];
if ( dump.IsRecursive() )
{
for( i = 0; i < m_num_sdrs; i++ )
{
snprintf( str, sizeof(str), "Sdr%02x_%d", m_mc->GetAddress(), i );
m_sdrs[i]->Dump( dump, str );
}
}
dump.Begin( "Sdr", name );
if ( m_device_sdr )
{
dump.Entry( "DynamicPopulation" ) << m_dynamic_population << ";\n";
dump.Entry( "LunHasSensors" )
<< m_lun_has_sensors[0] << ", "
<< m_lun_has_sensors[1] << ", "
<< m_lun_has_sensors[2] << ", "
<< m_lun_has_sensors[3] << ";\n";
}
else
{
dump.Entry( "Version" ) << m_major_version << ", "
<< m_minor_version << ";\n";
dump.Entry( "Overflow" ) << m_overflow << ";\n";
dump.Entry( "UpdateMode" ) << "dMainSdrUpdate"
<< IpmiRepositorySdrUpdateToString( m_update_mode ) << ";\n";
dump.Entry( "SupportsDeleteSdr" ) << m_supports_delete_sdr << ";\n";
dump.Entry( "SupportsPartialAddSdr" ) << m_supports_partial_add_sdr << ";\n";
dump.Entry( "SupportsReserveSdr" ) << m_supports_reserve_sdr << ";\n";
dump.Entry( "SupportsGetSdrRepositoryAllocation" ) << m_supports_get_sdr_repository_allocation << ";\n";
}
if ( dump.IsRecursive() && m_num_sdrs )
{
dump.Entry( "Sdr" );
for( i = 0; i < m_num_sdrs; i++ )
{
if ( i != 0 )
dump << ", ";
snprintf( str, sizeof(str), "Sdr%02x_%d", m_mc->GetAddress(), i );
dump << str;
}
dump << ";\n";
}
dump.End();
}
cIpmiSdr *
cIpmiSdrs::FindSdr( cIpmiMc *mc )
{
for( unsigned int i = 0; i < NumSdrs(); i++ )
{
cIpmiSdr *sdr = Sdr( i );
if ( sdr->m_type != eSdrTypeMcDeviceLocatorRecord )
continue;
if ( mc->GetAddress() == (unsigned int)sdr->m_data[5]
&& mc->GetChannel() == (unsigned int)(sdr->m_data[6] & 0x0f) )
return sdr;
}
return 0;
}
// Here we try to find the FRU that is the "parent"
// of the entity this SDR is attached to
// The algorithm here is *not* sophisticated at all
// The assumption is that most of the SDR will be attached
// directly to a FRU so it was optimized for this case
// Also only one level of parenthood is assumed - sorry Grand Pa !
unsigned int
cIpmiSdrs::FindParentFru( SaHpiEntityTypeT type,
SaHpiEntityLocationT instance,
SaHpiEntityTypeT & parent_type,
SaHpiEntityLocationT & parent_instance
)
{
SaHpiEntityTypeT mc_type = SAHPI_ENT_UNSPECIFIED;
SaHpiEntityLocationT mc_instance = 0;
parent_type = SAHPI_ENT_UNSPECIFIED;
parent_instance = 0;
// First look for FRUs themselves
for( unsigned int i = 0; i < NumSdrs(); i++ )
{
cIpmiSdr *sdr = Sdr( i );
if ( sdr->m_type == eSdrTypeMcDeviceLocatorRecord )
{
mc_type = (SaHpiEntityTypeT)sdr->m_data[12];
mc_instance = (SaHpiEntityLocationT)sdr->m_data[13];
if ( ( type != (SaHpiEntityTypeT)sdr->m_data[12] )
|| ( instance != (SaHpiEntityLocationT)sdr->m_data[13] ) )
continue;
parent_type = type;
parent_instance = instance;
return 0;
}
else if ( sdr->m_type == eSdrTypeFruDeviceLocatorRecord )
{
if ( (( sdr->m_data[7] & 0x80) == 0 )
|| ( type != (SaHpiEntityTypeT)sdr->m_data[12] )
|| ( instance != (SaHpiEntityLocationT)sdr->m_data[13] ) )
continue;
parent_type = type;
parent_instance = instance;
return sdr->m_data[6];
}
}
stdlog << "Entity ID " << type << ", Instance " << instance << " is not a FRU\n";
// SDR entity is not a FRU: look for association records
for( unsigned int i = 0; i < NumSdrs(); i++ )
{
cIpmiSdr *sdr = Sdr( i );
if ( sdr->m_type == eSdrTypeEntityAssociationRecord )
{
// Entity range
if ( sdr->m_data[7] & 0x80 )
{
if (( type == (SaHpiEntityTypeT)sdr->m_data[8] )
&& ( type == (SaHpiEntityTypeT)sdr->m_data[10] )
&& ( ( instance >= (SaHpiEntityLocationT)sdr->m_data[9] )
&& ( instance <= (SaHpiEntityLocationT)sdr->m_data[11] )))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[12] )
&& ( type == (SaHpiEntityTypeT)sdr->m_data[14] )
&& ( ( instance >= (SaHpiEntityLocationT)sdr->m_data[13] )
&& ( instance <= (SaHpiEntityLocationT)sdr->m_data[15] )))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
}
// Entity list
else
{
if (( type == (SaHpiEntityTypeT)sdr->m_data[8] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[9] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[10] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[11] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[12] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[13] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[14] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[15] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
}
}
else if ( sdr->m_type == eSdrTypeDeviceRelativeEntityAssociationRecord )
{
// Entity range
if ( sdr->m_data[9] & 0x80 )
{
if (( type == (SaHpiEntityTypeT)sdr->m_data[12] )
&& ( type == (SaHpiEntityTypeT)sdr->m_data[16] )
&& ( ( instance >= (SaHpiEntityLocationT)sdr->m_data[13] )
&& ( instance <= (SaHpiEntityLocationT)sdr->m_data[17] )))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[20] )
&& ( type == (SaHpiEntityTypeT)sdr->m_data[24] )
&& ( ( instance >= (SaHpiEntityLocationT)sdr->m_data[21] )
&& ( instance <= (SaHpiEntityLocationT)sdr->m_data[25] )))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
}
// Entity list
else
{
if (( type == (SaHpiEntityTypeT)sdr->m_data[12] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[13] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[16] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[17] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[20] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[21] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
if (( type == (SaHpiEntityTypeT)sdr->m_data[24] )
&& ( instance == (SaHpiEntityLocationT)sdr->m_data[25] ))
{
parent_type = (SaHpiEntityTypeT)sdr->m_data[5];
parent_instance = (SaHpiEntityLocationT)sdr->m_data[6];
break;
}
}
}
}
// Didn't find proper association record
if ( parent_type == SAHPI_ENT_UNSPECIFIED )
{
stdlog << "WARNING : Entity ID " << type << ", Instance " << instance << " did not find parent FRU\n";
stdlog << "WARNING : Defaulting to FRU 0, Entity ID " << mc_type << ", Instance " << mc_instance << "\n";
// We didn't find an exact match
// Since a lot of ATCA boards have wrong SDRs
// we default the parent to the MC itself
parent_type = mc_type;
parent_instance = mc_instance;
return 0;
}
stdlog << "Entity ID " << type << ", Instance " << instance << " parent ID " << parent_type << ", Instance " << parent_instance << "\n";
// We found the parent now we want its FRU number
// We already have MC == FRU #0 data
if (( parent_type == mc_type )
&& ( parent_instance == mc_instance ))
return 0;
// Now look for FRUs other than #0
for( unsigned int i = 0; i < NumSdrs(); i++ )
{
cIpmiSdr *sdr = Sdr( i );
if ( sdr->m_type == eSdrTypeFruDeviceLocatorRecord )
{
if ( (( sdr->m_data[7] & 0x80) == 0 )
|| ( parent_type != (SaHpiEntityTypeT)sdr->m_data[12] )
|| ( parent_instance != (SaHpiEntityLocationT)sdr->m_data[13] ) )
continue;
return sdr->m_data[6];
}
}
stdlog << "WARNING : Entity ID " << type << ", Instance " << instance << " did not find parent FRU\n";
stdlog << "WARNING : Defaulting to FRU 0, Entity ID " << mc_type << ", Instance " << mc_instance << "\n";
// We didn't find an exact match
// Since a lot of ATCA boards have wrong SDRs
// we default the parent to the MC itself
parent_type = mc_type;
parent_instance = mc_instance;
return 0;
}