1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
|
/*
*
* Copyright (c) 2004 by FORCE Computers
* Copyright (c) 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>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#if defined(__sun) && defined(__SVR4)
#include <unistd.h>
#include <stropts.h>
#include <sys/ioccom.h>
#endif
#include "ipmi_con_smi.h"
// This is an overlay for all the address types, so it's easy to
// determine the actual address type. This is kind of like addresses
// work for sockets.
#define IPMI_MAX_ADDR_SIZE 32
struct ipmi_addr
{
// Try to take these from the "Channel Medium Type" table
// in section 6.5 of the IPMI 1.5 manual.
int addr_type;
short channel;
char data[IPMI_MAX_ADDR_SIZE];
};
// When the address is not used, the type will be set to this value.
// The channel is the BMC's channel number for the channel (usually
// 0), or IPMC_BMC_CHANNEL if communicating directly with the BMC.
#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
struct ipmi_system_interface_addr
{
int addr_type;
short channel;
unsigned char lun;
};
// An IPMB Address.
#define IPMI_IPMB_ADDR_TYPE 0x01
// Used for broadcast get device id as described in section 17.9 of the
// IPMI 1.5 manual.
#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41
struct ipmi_ipmb_addr
{
int addr_type;
short channel;
unsigned char slave_addr;
unsigned char lun;
};
// Channel for talking directly with the BMC. When using this
// channel, This is for the system interface address type only. FIXME
// - is this right, or should we use -1?
#define IPMI_BMC_CHANNEL 0xf
#define IPMI_NUM_CHANNELS 0x10
// A raw IPMI message without any addressing. This covers both
// commands and responses. The completion code is always the first
// byte of data in the response (as the spec shows the messages laid
// out).
struct ipmi_msg
{
unsigned char netfn;
unsigned char cmd;
unsigned short data_len;
unsigned char *data;
};
// Messages sent to the interface are this format.
struct ipmi_req
{
unsigned char *addr; // Address to send the message to.
unsigned int addr_len;
long msgid; // The sequence number for the message. This
// exact value will be reported back in the
// response to this request if it is a command.
// If it is a response, this will be used as
// the sequence value for the response.
struct ipmi_msg msg;
};
// Receive types for messages coming from the receive interface. This
// is used for the receive in-kernel interface and in the receive
// IOCTL.
#define IPMI_RESPONSE_RECV_TYPE 1 // A response to a command
#define IPMI_ASYNC_EVENT_RECV_TYPE 2 // Something from the event queue
#define IPMI_CMD_RECV_TYPE 3 // A command from somewhere else
// Note that async events and received commands do not have a completion
// code as the first byte of the incoming data, unlike a response.
// Messages received from the interface are this format.
struct ipmi_recv
{
int recv_type; // Is this a command, response or an
// asyncronous event.
unsigned char *addr; // Address the message was from is put
// here. The caller must supply the
// memory.
unsigned int addr_len; // The size of the address buffer.
// The caller supplies the full buffer
// length, this value is updated to
// the actual message length when the
// message is received.
long msgid; // The sequence number specified in the request
// if this is a response. If this is a command,
// this will be the sequence number from the
// command.
struct ipmi_msg msg; // The data field must point to a buffer.
// The data_size field must be set to the
// size of the message buffer. The
// caller supplies the full buffer
// length, this value is updated to the
// actual message length when the message
// is received.
};
// Get/set the default timing values for an interface. You shouldn't
// generally mess with these.
struct ipmi_timing_parms
{
int retries;
unsigned int retry_time_ms;
};
// The magic IOCTL value for this interface.
#define IPMI_IOC_MAGIC 'i'
// Send a message to the interfaces. error values are:
// - EFAULT - an address supplied was invalid.
// - EINVAL - The address supplied was not valid, or the command
// was not allowed.
// - EMSGSIZE - The message to was too large.
// - ENOMEM - Buffers could not be allocated for the command.
#define IPMICTL_SEND_COMMAND _IOR(IPMI_IOC_MAGIC, 13, \
struct ipmi_req)
// Like RECEIVE_MSG, but if the message won't fit in the buffer, it
// will truncate the contents instead of leaving the data in the
// buffer.
#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR(IPMI_IOC_MAGIC, 11, \
struct ipmi_recv)
// Set whether this interface receives events. Note that the first
// user registered for events will get all pending events for the
// interface. error values:
// - EFAULT - an address supplied was invalid.
#define IPMICTL_SET_GETS_EVENTS_CMD _IOR(IPMI_IOC_MAGIC, 16, int)
#define IPMICTL_SET_TIMING_PARMS_CMD _IOR(IPMI_IOC_MAGIC, 22, \
struct ipmi_timing_parms)
cIpmiConSmi::cIpmiConSmi( unsigned int timeout, int log_level, int if_num )
: cIpmiCon( timeout, log_level ),
m_if_num( if_num )
{
}
cIpmiConSmi::~cIpmiConSmi()
{
if ( IsOpen() )
Close();
}
int
cIpmiConSmi::OpenSmiFd( int if_num )
{
int fd;
char devname[30];
snprintf( devname, sizeof(devname), "/dev/ipmidev/%d", if_num );
fd = open( devname, O_RDWR );
if ( fd >= 0 )
return fd;
snprintf( devname, sizeof(devname), "/dev/ipmi/%d", if_num );
fd = open( devname, O_RDWR );
if ( fd >= 0 )
return fd;
snprintf( devname, sizeof(devname), "/dev/ipmi%d", if_num );
fd = open( devname, O_RDWR );
return fd;
}
int
cIpmiConSmi::IfGetMaxSeq()
{
return dMaxSeq;
}
int
cIpmiConSmi::IfOpen()
{
int fd = OpenSmiFd( m_if_num );
if ( fd < 0 )
return fd;
// struct ipmi_timing_parms parms;
int rv = 0;
// parms.retries = 0;
// parms.retry_time_ms = 1000;
/* Some sensors take longer than 1 sec, use driver default. ARCress */
// rv = ioctl( fd, IPMICTL_SET_TIMING_PARMS_CMD, &parms );
if ( rv == -1 )
stdlog << "Warning: Could not set timing parms !\n";
// we want async events
int val = 1;
rv = ioctl( fd, IPMICTL_SET_GETS_EVENTS_CMD, &val );
if ( rv == -1 )
stdlog << "Warning: Could not set gets events !\n";
return fd;
}
void
cIpmiConSmi::IfClose()
{
}
SaErrorT
cIpmiConSmi::IfSendCmd( cIpmiRequest *r )
{
cIpmiAddr send_addr = r->m_send_addr;
ipmi_addr addr;
unsigned int addr_len = 0;
addr.addr_type = (int)send_addr.m_type;
// convert addr
switch( send_addr.m_type )
{
case eIpmiAddrTypeSystemInterface:
{
ipmi_system_interface_addr *si = (ipmi_system_interface_addr *)&addr;
si->channel = send_addr.m_channel;
si->lun = send_addr.m_lun;
addr_len = sizeof( ipmi_system_interface_addr );
}
break;
case eIpmiAddrTypeIpmb:
case eIpmiAddrTypeIpmbBroadcast:
{
ipmi_ipmb_addr *ipmb = (ipmi_ipmb_addr *)&addr;
ipmb->channel = send_addr.m_channel;
ipmb->slave_addr = send_addr.m_slave_addr;
ipmb->lun = send_addr.m_lun;
addr_len = sizeof( ipmi_ipmb_addr );
}
break;
default:
return SA_ERR_HPI_INVALID_PARAMS;
}
struct ipmi_req req;
req.addr = (unsigned char *)&addr;
req.addr_len = addr_len;
req.msg.netfn = r->m_msg.m_netfn;
req.msg.cmd = r->m_msg.m_cmd;
req.msg.data_len = r->m_msg.m_data_len;
req.msg.data = r->m_msg.m_data;
req.msgid = r->m_seq;
int rv = ioctl( m_fd, IPMICTL_SEND_COMMAND, &req );
if ( rv )
return SA_ERR_HPI_INVALID_REQUEST;
return SA_OK;
}
void
cIpmiConSmi::IfReadResponse()
{
unsigned char data[dIpmiMaxMsgLength];
ipmi_addr addr;
ipmi_recv recv;
recv.msg.data = data;
recv.msg.data_len = dIpmiMaxMsgLength;
recv.addr = (unsigned char *)&addr;
recv.addr_len = sizeof( ipmi_addr );
int rv = ioctl( m_fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv );
if ( rv == -1 )
{
if ( errno == EMSGSIZE )
// The message was truncated, handle it as such.
data[0] = eIpmiCcRequestedDataLengthExceeded;
else
return;
}
// convert addr
cIpmiAddr rsp_addr;
rsp_addr.m_type = (tIpmiAddrType)addr.addr_type;
switch( rsp_addr.m_type )
{
case eIpmiAddrTypeSystemInterface:
{
ipmi_system_interface_addr *si = (ipmi_system_interface_addr *)&addr;
rsp_addr.m_channel = si->channel;
rsp_addr.m_lun = si->lun;
}
break;
case eIpmiAddrTypeIpmb:
case eIpmiAddrTypeIpmbBroadcast:
{
ipmi_ipmb_addr *ipmb = (ipmi_ipmb_addr *)&addr;
rsp_addr.m_channel = ipmb->channel;
rsp_addr.m_slave_addr = ipmb->slave_addr;
rsp_addr.m_lun = ipmb->lun;
}
break;
default:
return;
}
// convert msg
cIpmiMsg rsp;
rsp.m_netfn = (tIpmiNetfn)recv.msg.netfn;
rsp.m_cmd = (tIpmiCmd)recv.msg.cmd;
rsp.m_data_len = recv.msg.data_len;
if ( rsp.m_data_len )
memcpy( rsp.m_data, recv.msg.data, rsp.m_data_len );
int seq = (int)recv.msgid;
switch( recv.recv_type )
{
case IPMI_RESPONSE_RECV_TYPE:
HandleResponse( seq, rsp_addr, rsp );
break;
case IPMI_ASYNC_EVENT_RECV_TYPE:
HandleEvent( rsp_addr, rsp );
break;
case IPMI_CMD_RECV_TYPE:
// incoming command
stdlog << "SMI: incoming ipmi command "
<< IpmiCmdToString( rsp.m_netfn, rsp.m_cmd ) << ".\n";
break;
default:
break;
}
}
|