\documentclass{book}
\usepackage{graphicx,moreverb,tabularx,acronym,longtable,alltt,varioref}
%
% Don't do any of the formatting when doing html conversion.
%begin{latexonly}
%
% Eliminate the margin notes
%
\addtolength{\textwidth}{\marginparwidth}
%\addtolength{\textwidth}{\marginparsep}
%\addtolength{\textwidth}{\oddsidemargin}
\setlength{\marginparwidth}{0pt}
\setlength{\marginparsep}{0pt}
\setlength{\evensidemargin}{0pt}
\setlength{\oddsidemargin}{0pt}
%end{latexonly}

\title{IPMI -- A Gentle Introduction\\with OpenIPMI}
\author{Corey Minyard $<$minyard@acm.org$>$\\
        Montavista Software}
\date{\today}
%
\newcommand{\msgitem}[2]{#1&\parbox{0.8\textwidth}{\vspace{.15em}#2\vspace{.15em}} \\ \hline}
\newcommand{\msgtag}[1]{\multicolumn{2}{l}{#1}\\ \hline}
\newcommand{\msgcaption}[1]{\caption{#1}}
\newenvironment{showmsg}{\noindent\begin{longtable}{|p{.5in}|l|}}{\end{longtable}}
\newenvironment{tightdefs}
  {\begin{list}{}%
      {\renewcommand{\makelabel}{\descriptionlabel}%
       \setlength{\partopsep}{0pt}%
       \setlength{\topsep}{0pt}%
       \setlength{\parskip}{0pt}%
       \setlength{\parsep}{0pt}%
       \setlength{\itemsep}{0pt}%
      }%
  }%
  {\end{list}}
%\begin{showmsg}
%\msgtag{Request}
%\msgitem{}{}
%\msgtag{Response}
%\msgitem{}{}
%\msgcaption{\label{}, NetFN x (xxh), Cmd xxh}
%\end{showmsg}
%
\begin{document}
\hbadness=10001
\vbadness=10001
\maketitle

\frontmatter

\chapter{Preface}
This document describes \acs{IPMI} in great detail; how it works and
what it does and does not do.  It starts from the basics and moves
into details.  If you've heard about IPMI and want to find out more,
this is the document for you.  If you know something about IPMI but
wish to find out more, you can gloss over the introductory text and
dive more into the details.

This document also describes OpenIPMI and how to use that library.  A
basic understanding of \acs{IPMI} is required to use OpenIPMI.
However, OpenIPMI hides the details of \acs{IPMI} like messages and
data formats; if you do not care about those things you can skip those
sections.

\acs{IPMI} stands for Intelligent Platform Management Interface.  Not
a great name, but not too bad.  It is intelligent (in a manner of
speaking, anyway) because it requires a processor besides the main
processor that is always on and maintaining the system.  In most
systems with \acs{IPMI}, you can monitor and maintain the system even when
the main processor is turned off (though the system must generally be
plugged in).

Platform means that \acs{IPMI} deals with the platform, not the software
running on the platform.  Software management is mostly out of the
scope of \acs{IPMI}

Management Interface means that the management system uses \acs{IPMI} to
talk to the system to monitor and perform maintenance on the
platform.  \acs{IPMI} is mostly about monitoring, though it does have a few
minor management functions.  However, many companies and organizations
have built more extensive management control using \acs{OEM} extensions to
\acs{IPMI}.

The \acs{IPMI} specification\cite{ipmi-spec}, of course, has the
details, but they can be obscure.  This document hopefully provides
an easier to understand introduction to IPMI.

\tableofcontents

\chapter{Acronyms}
\begin{acronym}
\acro{ATCA}{AdvancedTCA}
\acro{AMC}{AdvancedMC}
\acro{IPMI}{Intelligent Platform Management Interface}
\acro{IPMC}{Intelligent Platform Management Controller (FIXME - wrong)}
\acro{OEM}{Original Equipment Manufacturer}
\acro{SDR}{Sensor Device Record}
\acro{FRU}{Field Replacable Unit}
\acro{KCS}{Keyboard Style Controller}
\acro{BT}{Block Transfer}
\acro{SMIC}{Server Management Interface Chip}
\acro{SSIF}{SMBus System InterFace}
\acro{MC}{Management Controller}
\acro{BMC}{Baseboard Management Controller}
\acro{I$^2$C}{Inter Integrated Circuit}
\acro{SNMP}{Simple Network Management Protocol}
\acro{SPD}{Serial Presence Detect}
\acro{HPI}{Hardware Platform Interface}
\acro{LUN}{Logical Unit Number}
\acro{NetFN}{Network FuNction}
\acro{IPMB}{Intelligent Platform Management Bus}
\acro{EEPROM}{Electronically Erasable Programmable Read Only Memory}
\acro{LAN}{Local Area Network}
\acro{SEL}{System Event Log}
\acro{PPP}{Point to Point Protocol}
\acro{RMCP}{Remote Management Control Protocol}
\acro{IP}{Internet Protocol}
\acro{UDP}{User Datagram Protocol}
\acro{MD2}{Message Digest 2}
\acro{MD5}{Message Digest 5}
\acro{PDU}{Protocol Data Unit}
  In SNMP, this is a packet holding an SNMP operation.
\acro{PEF}{Platform Event Filter}
\acro{MAC}{Media Access Code?}
\acro{ARP}{Address Resolution Protocol}
\acro{GUID}{Globally Unique IDentifier}
\acro{NMI}{Non Maskable Interrupt}
\acro{EAR}{Entity Association Record}
\acro{DREAR}{Device Relative Entity Association Record}
\acro{DLR}{Device Locator Record}
\acro{MCDLR}{Management Controller Device Locator Record}
\acro{FRUDLR}{Field Replacable Unit Device Locator Record}
\acro{GDLR}{Generic Device Locator Record}
\acro{ICMB}{Intelligent Chassis Management Bus}
\acro{PET}{Platform Event Trap}
\acro{DMI}{?}
\end{acronym}

\mainmatter

\chapter{Management, Systems, and \acs{IPMI}}
Management will mean different things to different industries.  In
simple server systems, a management system may only deal with
controlling power on a few servers and making sure they don't get too
hot.  In a telecom system, management systems generally control every
aspect of the system, including startup of all parts of the system,
full monitoring of all components of the system, detection and
recovery from software and hardware errors, basic configuration of the
system, and a host of other things.  \acs{IPMI} obviously only plays one
role in this, but it is a role that must be played.  In the past, the
monitoring and management of hardware has been done with lots of
proprietary interfaces.  \acs{IPMI} standardizes this interface.

\begin{figure}
\includegraphics[width=\textwidth]{MgmtIF.eps}
\caption{\label{mgmtif}Management Interfaces}
\end{figure}

Figure \ref{mgmtif} shows a management system and the things it
manages.  \acs{IPMI} fits mostly within the ``Hardware'' box, although
there may be other hardware interfaces the management system must
manage.  The management system ties into all elements of the system
and makes global decisions based upon inputs from all parts of the
systems.  For instance, a server may be overheating or have a low
voltage.  The management system will be informed of this through the
hardware interfaces.  It may choose to move the function of that
server to another server and bring that server down so it may be
repaired.  If no other server is available to take over the operation,
the management system may look at the severity of the problem, predict
how long the system may survive, and let it continue.  These types of
decisions are called ``policy''.

In all cases these events are logged to permanent storage.  An
operator is informed of things that need human attention.  The
operator may also issue manual operations to configure and override
the management system as necessary.

The operations the management system performs on the system are called
``Commands'' in this picture.  Commands have ``Responses'' from the
system.  Asynchronous notifications from the system to the management
system are called ``Events''.  The system never sends commands to the
management system, and the system may perform local operations on its
own (such as controlling fan speed) but never perform global
operations unless pre-configured by the management system to do so.
So the system may perform limited policy decisions, but the management
system is firmly in control of policy.

\section{\acs{IPMI} Implementation}

The \ac{MC} sits at the center of an \acs{IPMI} system, providing the
``intelligence'' of \acs{IPMI}.  It is suppose to be always on when the
system is plugged in, even if the system is off.  The management
system communicates with the management controller; the management
controller provides a normalized interface to all the sensors, events,
and \ac{FRU} data in the system.

\begin{figure}
\includegraphics[width=\textwidth]{ManagementController.eps}
\caption{\label{managementcontroller}Parts of a Management Controller}
\end{figure}

Figure \ref{managementcontroller} shows the various parts of the
management controller.  Note that most everything is optional;
depending on what a management controller does it may only need some
things.  The \ac{BMC} is required to have a lot of the items.

The \ac{MC} Processor is generally a small, inexpensive, but reliable
microcontroller.  Several companies sell processors that have a lot of
the \acs{IPMI} components already implemented and software to help a company
implement \acs{IPMI} on their system.

The system interface provides a way for the main processor to
communicate with the management controller.  Some systems do not have
this connection and only use external interfaces and/or \ac{IPMB}
interfaces.  System interfaces include \ac{SMIC}, \ac{KCS}, and
\ac{BT} interfaces.

An \ac{MC} (generally the \ac{BMC}) may have other interfaces to an external
management system through serial ports or Ethernet.

Generally, sensors sit on an \acs{I$^2$C} bus since many off-the-shelf
sensors can sit directly on the bus with no extra logic.  Wherever the
sensors sit, the \ac{MC} provides a more abstract interface to the sensors
so that the management system does not have to know the details of how
to talk to the sensor.  Sensors may be traditional analog sensors like
temperature and voltage.  But they may report other things, too, like
the current BIOS state, whether a device is present or not, or other
things like that.

\ac{FRU} data is often stored in \acs{I$^2$C} \acs{EEPROM}s on the
\acs{I$^2$C} bus.  \ac{FRU} data is information about a Field
Replacable Unit.  This includes things like the manufacturer, the
serial number, date of manufacture, etc.  A system generally has
information about the chassis and information about each field
replaceable unit it has.  Field replaceable units may include power
supplies, DIMMs (memory devices), plug-in-boards, or a host of other
things.

Connections to other \ac{MC}s may be done through an \ac{IPMB}.  On an
\ac{IPMB}, each MC is a peer and they communicate directly through
messages.

In addition to \ac{IPMB}, \acs{IPMI} systems can be interconnected through an
Intelligent Chassis Management Bus.  This is a serial bus that runs
between chassis.

A management controller may be able to control various aspects of the
chassis, such as power and reset.  It may also have a watchdog timer
for the main processor.

The \ac{SDR} repositories store information about the sensors and
components of the system.  The \ac{BMC} must have a main \ac{SDR}
repository; this repository is writable.  There may only be one main
\ac{SDR} repository in the system.  Any MC may have a device \ac{SDR}
repository; these are a read-only repositories.

When a problem or change in the system is detected, the MC handling that
sensor may issue an event.  This allows management software to detect
these problems or changes without having to poll every sensor
constantly.  The events are stored in an event log.  Events may be forwarded
through the system interface or other interfaces, but they are always
stored in the event log.  The \ac{BMC} must have an event log;
generally the other management controllers forward their events to the
\ac{BMC}.

\section{System Types}
\label{system-types}

Although any arbitrary type of system may use \acs{IPMI} for platform
management, systems generally fall into two categories: server systems
and bus systems.

\begin{figure}
\includegraphics[width=\textwidth]{ServerSystem.eps}
\caption{\label{typicalserver}A typical server system}
\end{figure}

Figure \ref{typicalserver} shows a typical server system.  It is a
single stand-alone box that is a single computer.  It has a \ac{BMC}
that is the main management controller in the system.  It controls a
number of sensors.  In this example, the power supply also has a
\ac{MC} with it's own sensors.

A \ac{BMC} can have several connections to managing systems.  It may
have a system interface connection to the main processor.  It may
share an interface to the ethernet chip so the system may be managed
through the \acs{LAN} when the main processor is not working.  Systems
can have serial port connections.  They can even have connections to
modems where they can dial up a management system or page an operator
when they detect a problem, or be dialed into by a management system.

\begin{figure}
\includegraphics[width=\textwidth]{BusSystem.eps}
\caption{\label{typicalbus}A typical bus system}
\end{figure}

Figure \ref{typicalbus} shows a typical bus system.  The word ``bus''
is perhaps a bit misleading; these types of systems used to have
busses (like CPCI and VME) but recently have tended to not have big
busses and use networking for interconnect (like PICMG 2.16 and \acs{ATCA}).
These systems generally contain a number of processors on pluggable
boards often called Single Board Computers (SBCs) or blades.  One or
more power supplies power the whole system.  The boards and power
supplies can be hot-pluggable.

These systems generally have one or two boards that manage the system;
this can be on a standard SBC, on another special purpose blade (like
a blade used as a network switch), or on a standalone board with this
purpose.  The shelf management controller(s) generally act as the \ac{BMC}
in the system; they will have the event log and the main \ac{SDR}s in the
system.  A system with two shelf controllers will generally allow the
system to be managed even if one of the shelf controllers fails.

Bus systems generally use one or more \ac{IPMB}s (a sister standard to
\acs{IPMI}) to interconnect the various components for management.
\ac{IPMB} is a modified \acs{I$^2$C} interface; it provides for a somewhat
slow but simple communication bus.

The boards can generally be individually power controlled, so even
though a board is plugged into the system it may be turned off.  The
shelf managment controller may implement some policy, such as fan
controls or auto-powering up boards, but is generally used as a
conduit for an external management system to control the parts of the
system.

Individal SBCs vary on whether the local Management Controller is
connected to the microprocessor on an SBC.  Some are, and some aren't.
This connection has some limited usefulness if the software on the SBC
wishes to obtain local information from the \acs{IPMI} system or store
logs in the \acs{IPMI} event log.

These types of systems are used to achieve high density in places with
expensive real-estate, like a telco central office.  As you might
imagine, you can pack a lot of processing power into a small space
with a system like this.  Since they are generally designed for
hot-swap, and can have I/O come out the back of the system on separate
cards; it makes mainenance easier.

%---------------------------------------------------------------------
\chapter{OpenIPMI}

So now we've got a \ac{BMC}, \ac{MC}s, and things like that.  But how are you
expected to use raw \acs{IPMI}?

The first things you must do, of course, is connect to the \ac{BMC}.
If it's a direct SMI connection (A \ac{SMIC}, \ac{KCS}, or \ac{BT}
interface, or perhaps a non-standard serial interface), you just open
the driver on the operating system and start messaging.  If it's a
\acs{LAN}-type connection, you have to go through an authentication
sequence.  One you have a connection to the \ac{BMC}, things are
pretty much the same no matter what interface you have.  There are a
few messaging for doing special controls on a \acs{LAN} interface, but
they don't generally matter to the user.

Once the connection to the \ac{BMC} is up, the user should query to see what
channels the \ac{BMC} supports.  For 1.5 and later, it gets this from a
command.  For 1.0, it gets it from the main \ac{SDR} repository.

Once you are connected, you should scan the \ac{SDR}s in the main \ac{SDR}
repository for any entities and sensors.  Sensors and entities may
also be in the device \ac{SDR} repository, which should be scanned next.
This allows the user to discover the sensors in the system.  Note that
the sensors may point to entities that don't have a entry in the \ac{SDR}
that defines them, those entities need to be handled when they are
detected.

After this point in time, the interface could be deemed to be ``up''.
However, there's still more to do.

If the interface supports an event queue, the user will have to poll it
(if the driver doesn't deliver them asynchronously, that is).  If the
interface doesn't support an event queue the user should periodically
scan the system event log for new events.  (Note that even if it does
support an event queue, the user should still poll the system event log
in case the event queue missed any events coming in.)

Also, the user should start scanning the \ac{IPMB} bus with broadcast get
device id commands to detect any \ac{MC}s on the bus.

This is what the OpenIPMI library does for you.  Beyond this, it also
represents the sensors, controls, and entities in a nice OO fashion,
and it handles the details of addressing, message routing, and other
things you don't really care about.  It lets you get right at the
sensors and entities.

\section{The User View}

A bunch of acronyms have just been introduced, along with a lot of
vague concepts, and some description about how to use \acs{IPMI}.  The nice
thing is that the user of OpenIPMI doesn't really have to know about
all these things.

From the user's point of view, the entity provides the central
framework for sensors and controls.  Sensors monitor entities.
Entities may be present or absent.  When you connect to an interface,
OpenIPMI takes care of detecting the entities in the system and
reporting them to you.  You may register to be told when entities are
added or removed from the local database.  Note that an entity may be
in the \acs{SDR}s but not physically present in the system; the
reporting from OpenIPMI only gives the existance in the \acs{SDR}s, not
physical presence in the system.  Physical presence it handled through
a separate interface.

The user must know about two other OpenIPMI concepts: connections and
domains.  A connection provides the interface to the \acs{IPMI}
system.  In essence, it is the \ac{BMC} connection.  You must allocate
one or more connections and create a domain with them.  OpenIPMI
supports multiple connections to a domain in some cases, but currently
it requires some \acs{OEM} support for this.  A domain represents a
set of devices on a bus (like \ac{IPMB}) whose entities will be
unique.  For instance, a chassis with a lot of cards plugged in could be
a domain, each card could be an entity and then create it's own
sub-entities, but they will be designed so the entity id's don't
collide.

OpenIPMI will automatically manage the connections, activating and
deactating the proper connections (if the connections support that),
detecting failures and switching over, etc.

Though the user doesn't have know the inner details of \acs{IPMI} addressing
and messaging, they do need to know about entities and sensors.
OpenIPMI mainly focuses on representing the entities and sensors in
convenient ways.  The user still needs to understand the capabilities of
sensors, how the sensors advertise those capabilities, and the things
that can be done to the sensors.

You may register with an entity to be told when its physical presence
in the system changes.  Some devices (like power supplies) are
field-replaceable while the system is running; this type of device is
called a hot-swappable \ac{FRU}.  They may have sensors that monitor
them, but those sensors may not be active if the device is not
physically present in the system.

Sensors and controls are also automatically detected and reported.
This is done through entities; you register with an entity to be told
when a sensor or control has been added or removed.

\section{OpenIPMI Concepts}

OpenIPMI is an event-driven library that is designed to be relatively
operating system independent.  If you have written control systems or
things like that in the past, you will be quite familiar with
event-driven systems and may skip to the next section.  If not, you want
to read this.  Event-driven systems may seem a little unusual, but they
are accepted practice and by far the best way to build control systems.

\subsection{Event-Driven Systems}
\label{event-driven-systems}

In an event-driven system, you never stop and wait for something to
happen.  If you are not used to this, you are probably used to writing
code like this:

\begin{verbatim}
  while (true) {
    wait_for_input();
    perform_op1();
    wait_for_op1_results();
    perform_op2();
  }
\end{verbatim}

This is fairly straightforward, but it has some problems.  What if
another more important input comes in while you are waiting for the
results of \verb=perform_op1()=?  Now the program will have to handle
input in \verb=wait_for_op1_results()=, too, and somehow return and
say something is happening.  The loop will then have to somehow handle
multiple operations in progress.  And this is a simple example, what
if there were hundreds of possible inputs, each with their own result
handler, and each had to go through several states?  You could assign
each to a thread, but if you have thousands of possible pending
operations in a system, that many threads may thrash your system and
render it inoperable, probably right at the time you need it most
(since a lot of things are going on).

In an event-driven system, instead you would say:
\begin{verbatim}
  init()
  {
    <initialize input_data>
    register_for_input(op1_handler, input_data);
  }
  op1_handler(input_data)
  {
    <allocate and initialize op_data>
    perform_op1(..., op2_handler, op_data);
  }
  op2_handler(op_data)
  {
    perform_op2();
    <free op_data>
  }
\end{verbatim}

As you see, when you start an operation, you provide the next thing to
call when the operation completes.  The functions passed around are
called ``callbacks''.  You allocate and pass around chunks
of data to be passed to the handlers.  And you register input handlers
that get called when certain event occurs.  So the code runs in short
non-blocking sections, registers for the next operation, then returns
back to some invisible main loop that handles the details of scheduling
operations.  This may seem more complicated than the previous example,
but it has a large number of advantages:
\begin{itemize}
\item The system is almost always ready to handle input.  For instance,
user-interface systems (like most widget sets) are almost always
event-driven, this
makes them much more ``live'', since they are always ready to handle
user input.
\item This system can handle multiple simultaneous operations without
threads.  In general, threaded systems are less reliable and more
complicated; unless you need priorities or scalability on SMP, why use
them?  And even if you use them, you can have much better control over
what is running in the system with an event-driven system..
\item If you are building a redundant system with data replication, this
gives you a natural way to hold your data, know when to transfer it over
to the mate system, and continue an operation on the mate system.
\item If you track the data, it's easy to monitor every operation
occuring in the system, stop an operations, or whatever.
\item It's much easier to detect and manage overload situations in an
event driven system.  Event-driven systems have event queues of things
waiting to be processed.  You can put things in the queue and watch the
queue length.  If the queue length gets too big, you are in overload,
and can intelligently decide which events you want to throw away, based
on priority, time to live, or some other criteria.
\end{itemize}

In general, a threaded system is easier to conceptually understand until
you understand event-driven methods.  An event-driven system is almost
always easier to correctly implement.

Note that event-driven systems don't preclude the use of threads.
Threads may be vastly overused, but they are important.  You could, for
example, allocate one event loop thead per CPU to help scale your
system.  You need to use threads to manage priorities.  Some inputs may
be more important than others, so you may have an event loop for each
priority and feed them that way.  You have a thread per CPU, and/or a
thread per priority, but you don't need a thread per operation.

This is often called ``state-machine programming'' since most control
systems are state-machine based, and this is a natural way to implement
a state machine.  The \verb=op_data= holds the state of the state
machine, each input gets \verb=op_data=, looks at the current state, and
decides what to do next.

The OpenIPMI library is completely event-driven.  It has no internal
blocking operations, and it expects that anything it calls will not
block.  \acs{IPMI} messaging and operating system primitives are provided
through external plug-in pieces.

If a library function that takes a callback does not return an error,
the callback is guaranteed to be called, even if the object the call is
associated with goes away.  If it goes away, a NULL may be passed in as
the object to the callback, but the \verb=cb_data= will still be valid.

\subsection{The OS Handler}
\label{openipmi-os-handlers}

The OS handler provides services for the OpenIPMI library.  OpenIPMI
needs some things from the operating system that are not standardized
by the C language.  The os-handler include file is shown in Appendix
\ref{os-handler-h}.

\subsubsection{OS Handler Services}

The classes of services required by OpenIPMI are:

\begin{description}
\item[Input Callbacks]
The OpenIPMI code uses the ``file descriptor'' concept of *nix, input
devices are numbered.  This is not used internally in the library, but
it is used by the messaging interfaces, so the messaging interfaces and
OS handler may implement their own conventions for these numbers.  This
provides a way for OpenIPMI to register to receive input from devices.

\item[Timers]
OpenIPMI times everything (as it should), thus it needs timers.

\item[Locks] OpenIPMI does not require locks, you may leave the
operations NULL and they won't be used.  However, if you are doing
multi-threaded operations, you should almost certainly provide locks.
The locks do not need to be recursive (they used to, but this has
changed in OpenIPMI 1.4).  Read/write locks are no longer required.

\item[Condition Variables]
These are condition variables like the ones specified in POSIX threads.
Although OpenIPMI does not use condition variables (since it never waits
for anything) it may be convenient for other things to have them.
OpenIPMI does not use them, and if nothing in your system needs them,
they need not be provided.

\item[Random Data]
For certain operations, OpenIPMI needs random data.

\item[Logging]
Logs that OpenIPMI uses to report information and internal problems
comes through the OS Handler.

\item[Database]
OpenIPMI can use an external database to hold persistent information
(like SDRs) and thus avoid having to fetch them every time it starts
up.  This interface is not required, but can greatly reduce the
startup time of OpenIPMI.

\item[User Functions]
Not used by OpenIPMI, but available for the user for special things the
user will need.
\end{description}

\subsubsection{Standard User Functions in the OS Handler}
\label{std-func-os-handler}

OS handlers have some standard functions pointers for the user.  These
are:

\noindent\begin{tabularx}{\textwidth}{lX}
\texttt{free\_os\_handler} &
Free the OS handler.  Do not use the OS handler after calling this.\\

\texttt{perform\_one\_op} &
Handle one event (a timer timeout or a file operation) and return.
This takes a timeout; it will wait up to the amount of time given for
the event.\\

\texttt{operation\_loop} &
Continuously handle events.  This function will not return.\\
\end{tabularx}

These operations may not be available on all OS handlers, see the
particular OS handler you are using for more details.

These are part of the OS handler.  As an example on how to use them,
the following code performs one operation, prints any error it
returns, then frees the OS handler:

\begin{verbatim}
struct timeval tv;
int            rv;
tv.tv_sec = 10;
tv.tv_usec = 0;
rv = os_hnd->perform_one_op(os_hnd, &tv);
if (rv)
  printf("Error handling operation: 0x%x", rv);
os_hnd->free_os_handler(os_hnd);
\end{verbatim}

\subsubsection{POSIX OS Handlers}

OS handlers are already defined for POSIX systems, both with and
without threads.  These are defined in the include file
\verb=ipmi_posix.h=; see that file for more details.  If you are
running in a threaded application, you almost certainly should use the
threaded version of the OS handlers.

To allocate a POSIX OS handler, use one of the following:

\begin{verbatim}
os_hnd = ipmi_posix_setup_os_handler();

os_hnd = ipmi_posix_thread_setup_os_handler(wake_sig);
\end{verbatim}

The \verb=wake_sig= is a signal number that your program is not using
(usually \verb=SIGUSR1=, \verb=SIGUSR2=, or a real-time signal).  The
OS handlers uses this signal to send between threads to wake them up
if they need to be woken.

Freeing and handling the OS handler is done with the standard
functions in the OS handler, described in section
\ref{std-func-os-handler}.

\subsubsection{The GLIB OS Handler}

An OS handler is already defined for glib and will work with threads.
It is defined in the include file
\verb=ipmi_glib.h=; see that file for more details.

To allocate a GLIB OS handler, use:

\begin{verbatim}
os_hnd = ipmi_glib_get_os_handler();
\end{verbatim}

Presumably, GLIB handles the waking of threads, so unlike the POSIX
version no wakeup signal is required.

All the other the OS handler functions are done with the standard
functions in the OS handler, described in section
\ref{std-func-os-handler}.

\subsection{Error Handling}

Almost all OpenIPMI calls that do anything besides fetch a piece of
local data will return an integer error value.  A zero means no error.
Two types of errors are returned, system errors (which are standard
Unix errno values) and \acs{IPMI} errors (which are the standard
\acs{IPMI} error codes).  You can use the macros \verb=IPMI_IS_OS_ERR=
and \verb=IPMI_IS_IPMI_ERR= to tell the type of error, and
\verb=IPMI_GET_OS_ERR= and \verb=IPMI_GET_IPMI_ERR= to get the actual
error values.

Note that if your system doesn't have Unix-type error numbers, you will
have to provide those for the OpenIPMI library.

If a function returns an error, any callbacks provided to that
function will \emph{never} be called.  If a function that takes a
callback returns success, the callback will \emph{always} be called,
even if the object associated has ceased to exist.  If an object with
outstanding operations ceases to exist, all the callbacks for
outstanding operations will be called with \verb=ECANCELED= as the
error.  Errors are passed into many callbacks, if an error is present
the rest of the data in the callback is probably not valid except for
the \verb=cb_data= variable you provide, and possibly the object the
callback is associated with.  The object the callback is associated
with may be NULL if it has ceased to exist.

\subsection{Locking}

As mentioned before, you may or may not be using locking, \emph{but
you must read this section anyway.}  Locking here involves existance of
entities as well as normal locking.

Locking has changed between OpenIPMI 1.3 and 1.4.  In OpenIPMI 1.3,
locks were held in user callbacks.  Locking was very course grained
and the locks were recursive, so this was generally not a problem.
However, in general it is a bad idea to hold locks in user callbacks.
The user might have two domains and cause deadlocks between them.  For
instance, if the user had one thread in a callback from domain 1 that
then called a function in domain 2, and another thread in a callback
from domain 2 that called a function in domain 1, the system can
deadlock.  This is because the first thread holds locks in domain 1
that the second thread needs for the function in domain 1, and the
second thread holds locks in domain 2 that the first thread needs for
the domain 2 function.  Because of this, locking strategy has changed
in OpenIPMI 1.4.  The interfaces and basic usage are completely
unchanged, but the semantics have changed.

\subsubsection{Locking principles}

The basic principle of locking is that if you are in a callback for an
\acs{IPMI} object (an \acs{IPMI} object is passed in the callback),
that object is refcounted (marked in-use) and the system cannot delete
it.  In any callback for an object owned by a particular domain, that
object and anything it belongs to will be marked in-use.  So,
for instance, in a callback for a sensor, the sensor is in-use, the
entity the sensor belongs to is in-use, the management controller the
sensor is on is in-use, and the domain the sensor is in will be
in-use.  No other sensors, entities, or management controllers will
necessarily be marked in-use.  Outside of callbacks, the library is
free to change pointers, change information, add and remove objects,
or make whatever general changes that are required.

So how do you mark an \acs{IPMI} object in-use?  If you are handling
incoming \acs{IPMI} callbacks you generally don't have to worry about this.
But say you are handling outside input, such as a user interface.
What then?  If the pointers can change, how do you keep a reference to
something?

OpenIPMI provides two identifiers for \acs{IPMI} objects.  One is a
pointer, but a pointer is only good inside a callback.  The other is
an OpenIPMI id; the id is good outside callbacks.  But the only thing
you can do with an id is pass it to a function that will call a
callback for you with the pointer.  You can convert a pointer to an id
(inside a callback, of course) so you should do that if you need to
save a reference to the object.  Note that there are some functions
that take ids that do this for you (such as
\verb=ipmi_sensor_id_reading_get()=, other sensor functions, hot-swap
functions, and a few others); these are provided for your convenience.
Almost all sensor, control, and entity functions that you would
generally call asynchronously support these \verb=ipmi_xxx_id=
functions.  The operation is exactly the same as the same operation
without the \verb=_id=, it simply takes the id instead of the direct
pointer.  See the \verb=ipmiif.h= include file to see if the function
you desire exists.

This mechanism, though a little inconvenient, almost guarantees that
you will not forget to decrement a use count.  It nicely encapsulates
the locked operation in a function\footnote{This is how locking works
in Ada95 and Java, although their mechanisms are a little more
convenient since they are built into the language}.  You have to
return from the function unless you exit, longjmp, or throw an
exception that falls through the callback, and you shouldn't do those
things.

You \emph{must} do this whether you are using locking or not, because the
library uses this mechanism to determine whether the id you are holding
is good.  Once it converts the id to the pointer, your pointer is
guaranteed to be good until the function returns.

The functions to convert an id to a pointer are named
\verb=ipmi_xxx_pointer_cb()=, where ``xxx'' is control, entity,
domain, or sensor.  Unlike many other callbacks, the callback function
you provide to these functions will be called immediately in the same
thread of execution, this callback is not delayed or spawned off to
another thread.  So, for instance, you can use data on the stack of
the calling function and pass it to the callback function to use.

\subsubsection{Locking example}

For instance, suppose you have a callback registered with the domain
for finding when new entities are ready, and you are looking for a
specific entity.  The code might look like:

\begin{verbatim}
ipmi_entity_id_t my_entity_id = IPMI_ENTITY_ID_INVALID;

static void
entity_change(enum ipmi_update_e op,
              ipmi_domain_t      *domain,
              ipmi_entity_t      *entity,
              void               *cb_data)
{
    ipmi_entity_id tmp_id;

    switch (op) {
        case IPMI_ADDED:
            if (entity_i_care_about(entity))
                my_entity_id = ipmi_entity_convert_to_id(entity);
            break;

        case IPMI_DELETED:
            tmp_id = ipmi_entity_convert_to_id(entity);
            if (ipmi_cmp_entity_id(my_entity_id, tmp_id) == 0)
                ipmi_entity_id_set_invalid(&my_entity_id);
            break;

        default:
            break;
    }
}
\end{verbatim}

In this example, the entity is in-use in this call, because you have
received a pointer to the entity in the callback.

However, suppose you want to use the entity id later because the user
asks about the entity to see if it is present.  You might have a piece
of code that looks like:

\begin{verbatim}
static void
my_entity_id_cb(ipmi_entity_t *entity, void *cb_data)
{
    my_data_t *data = cb_data;

    data->exists = 1;
    data->present = ipmi_entity_is_present(entity);
}

void
check_if_my_entity_present(my_data_t *data)
{
    int rv;

    data->exists = 0;
    data->present = 0;
    rv = ipmi_entity_pointer_cb(my_entity_id, my_entity_id_cb, data);
    if (rv)
        printf("The entity could not be found\n");
}
\end{verbatim}

Most of the data about the various OpenIPMI objects is static, so you
can pre-collect the information about the objects in the callback
where there existance is reported.  Some local information, such as
entity presence, whether a MC is active, and entity hot-swap state
is dynamic, but the vast majority of information is not.  So, it is
recommended that you collect all the static information that you need
from an object when it is reported to you.

Many operations require a message to the remote system; the ones that
take callbacks.  For these operations, functions that directly take the
id are available.

Use of the id-base functions is recommended.  The entity presence code
could be rewritten using this to be:

\begin{verbatim}
void
check_if_my_entity_present(my_data_t *data)
{
    int rv;

    data->exists = 0;
    data->present = 0;
    rv = ipmi_entity_id_is_present(my_entity_id, &data->present);
    if (rv)
        printf("The entity could not be found\n");
    else
        data->exists = 1;
}
\end{verbatim}

\subsubsection{Locking semantics}

As mentioned before, OpenIPMI will not delete an object you have a
pointer to while in a callback, but in multi-threaded systems it is
free to do pretty much anything else to the object, including call
callbacks on it.  This means, for instance, that you can be iterating
over the entities in the system and a new entity can be added, have
the entity update callback called on it, and be added to the list.
There is no guarantee or order between the adding of entities to the
list and the callback.  So the new entity might be iterated, it might
not, the iteration might be before or after the the callback, etc.

How can you avoid this?  You have a few options:

\begin{itemize}
\item Ignore the problem.  I strongly recommend that you do not take this
option.

\item Single-thread your program.  If you don't need be able to take
advantage of multiple CPUs in an SMP system, and you have no need for
priorities, single-threading is a good option.  With OpenIPMI, you can
have a single-threaded application that is non-blocking and can
perform very well.  Plus, single-threaded programs are easier to
debug, easier to understand and maintain, and more reliable.

\item Do your own locking.  For instance, you could claim a lock in
both the entity iteration and the callback for a new entity.  This
would prevent the both pieces of code from running at the same time.
You are in control of the locks, so you can handle it as appropriate.
You have to know what you are doing, but that goes without saying when
doing multi-threaded programming.
\end{itemize}

This is pretty standard in multi-threaded systems.  \ac{HPI}, for
instance has the same problem.  If you have one thread waiting for
events from an \ac{HPI} domain, and another iterating the RDRs, or you
have two threads each doing operations on sensors, you have exactly
the same situation.  You have to protect yourself with locks the same
way.

Note that data about an object (like the device id data, whether the
\ac{MC} is active, or the entity is present, or whatever) will \emph{not}
change while the object is in use.  This data is held until the object
is no longer in use and then installed (and in the case of activity or
presence, the callbacks are then called).

\subsection{OpenIPMI Objects}

In OpenIPMI, the user deals with six basic objects: connections,
domains, entities, sensors, controls, and events.

\subsubsection{Connections}

A connection provides the low-level interface to the system.  It is
usually a connection to a \ac{BMC} in a system.  It handles getting \acs{IPMI}
messages to the proper elements in the system.

\subsubsection{Domains}

The domain is the container for the system, the entities in the system
are attached to it.  You create a domain with a connection to a
system; the domain handles the job of discovery of the things in the
system.

\subsubsection{Entities}

Entities are things that are monitored.  They may be physical things
such as a power supply or processor, or more abstract things such as the
set of all power supplies or the ambient air in a chassis.  Sensors
monitor entities, and controls are attached to entities.

Entities may be grouped inside other entities, thus an entity may have a
parent (if it is grouped inside another entity) and children (if it
contains other entities).  A raw system with no \ac{SDR} data will not have
any relationships defined.  Relationships are stored in the \ac{SDR}
repository.   You may change them and store them back, if you like and if
the system supports that, but changing SDR data is not recommended.

\ac{FRU} information about the entity is sometimes available.  You can
register with an entity to see if/when it becomes available using:
\begin{verbatim}
int ipmi_entity_add_fru_update_handler(ipmi_entity_t     *ent,
                                       ipmi_entity_fru_cb handler,
                                       void              *cb_data);
\end{verbatim}
Once it is available, you can fetch the \ac{FRU} data using the
commands defined in the \acs{IPMI} include file.

\paragraph{Device-Relative vs System-Relative Entities}

In \acs{IPMI}, entities may be either in a fixed place in the system, or
they may be moved about the system.  Fixed entities, are, well, in a
fixed location in the system.  These are called system relative
entities.  They have an entity instance less than 60h.

Other entities may not reside in a fixed location.  For instance, a
power supply or CompactPCI board may be plugged in to one of many
locations in a chassis; it doesn't know ahead of time which one.
These types of entities are generally device-relative and thus have an
entity instance of 60h or larger.  For these types of entities, the
management controller on which they reside becomes part of the entity.
In OpenIPMI, the \ac{IPMB} channel number and \ac{IPMB} address are
part of the entity.  In \verb=ipmi_ui= and \verb=ipmish=, these are
printed and entered as ``r$<$channel$>$.$<$ipmb$>$.$<$entity
id$>$.$<$entity instance$>$''.

\subsubsection{Sensors}

Sensor monitor something about an object.  \acs{IPMI} defines many types of
sensors, but groups them into two main categories: Threshold and
discrete.  Threshold sensors are ``analog'', they have continuous (or
mostly continuous) readings.  Things like fans speed, voltage, or
temperature.

Discrete sensors have a set of binary readings that may each be
independently zero or one.  In some sensors, these may be independent.
For instance, a power supply may have both an external power failure
and a predictive failure at the same time.  In other cases they may be
mutually exclusive.  For instance, each bit may represent the
initialization state of a piece of software.

\subsubsection{Controls}

Controls are not part of the \acs{IPMI} spec, but are necessary items in
almost all systems.  They are provided as part of OpenIPMI so that \acs{OEM}
code has a consistent way to represent these, and so OpenIPMI is ready
when the \acs{IPMI} team finally sees the light and adds controls.  OpenIPMI
defines many types of control: lights, relays, displays, alarms,
reset, one-shot-reset, power, fan speed, general outputs, one-shot
outputs, and identifiers.

For all controls except displays and identifiers, the control may
actually control more than one device.  With some controls, multiple
device may be controlled together and individual ones cannot be set (ie,
the same message sets all of them).  For these types of controls,
OpenIPMI represents them as a single control with multiple devices.
All the devices are read and set at once.

Reset controls are reset settings that can be turned on and off.
One-shot-reset controls cause a reset by setting the value to 1; they
are not readable and setting them to zero returns an error.

Lights are on/off colored devices, like an LED.  They may be
multi-color, but can only show one color at a time.  For instance, if
you work for Kmart, or you are managing a CompactPCI system with
hot-swap, you will have a blue light in your system.  You can search
through the controls to find a light that's blue.  Then, if a special
is on, or you want the operator to remove a card, you can light the
blue light.  Lights may blink, too.  Two types of lights are
available.  Transition lights can have a series of transitions; as
series of transition is called a value.  Each value describes a
sequence of one or more transitions the light may go through.  Setting
lights allow direct setting of the color and on/off time of the light.

Relays are binary outputs.  Most telephony systems have them; they are
required by telephony specs.  They are simple on/off devices.

Displays are two-dimensional arrays of characters.  OpenIPMI allows you
to change individual characters at will.

Alarms are bells, whistles, gongs, or anything that can alert the user that
something is wrong.

Reset controls are used to reset the entity to which they are attached.

Power controls can be used to control power to or from an entity.  A
power control on a power supply would generally control output power.  A
power control on a board would generally control input power to the
board.

Fan speed controls can be used to set the speed of a fan.

General outputs are outputs that don't fall into one of the previous
categories.  One-shot outputs are like general outputs, but perform
some action when set to one and are not readable.  Setting them to
zero returns an error.

Identifier controls hold identification information for a system, such
as a chassis id, chassis type, geographic address, or whatever.

\subsubsection{Events}
\label{sec-openipmi-events}

When an external event comes into OpenIPMI, the user will always
receive that event in some manner (unless they do not register with a
generic event handler, but they should always do that).  The event may
come through a callback for a sensor, control, entity, or other
callback.

All the callbacks you should be using return a value telling whether
the handler has ``handled'' the event.  Handling the event means that
the callback is going to manage the event.  Primarily, this means that
it is responsible for deleting the event from the event log with
\verb=ipmi_event_delete()=.  If no callback handles the event, then it
will be delivered to the main event handler(s).  This allows calls to
receive events but the events to be managed in a single location.

To handle the event, the event handler should return
\verb=IPMI_EVENT_HANDLED=.  To pass the event on, it should return
\verb=IPMI_EVENT_NOT_HANDLED=.

If a callback handles the event, then all future callbacks called due
to the event will receive a \verb=NULL= for the event.  So be ready to
handle a \verb=NULL= event in all your event handlers.  A \verb=NULL=
may also be passed to an event handler if the callback was not due to
an event.

\subsubsection{Where OpenIPMI Gets Its Data}

OpenIPMI generally gets all of its data from the IPMI system, either
from SDRs, the event log, or via commands.  OpenIPMI will pull in
anything it can recognize.  Note that some data in an IPMI system is
duplicated; if the data is not consistent it will continue to be
inconsistent in OpenIPMI.

For instance, OpenIPMI gets all the information about a management
controller from the ``Get Device Id'' command.  However, the system
may have a record in the SDR repository describing an entity that
represents the management controller.  If the data from the command
and the SDR repository is inconsistent, OpenIPMI will happily provide
the data from the SDR repository when looking at the entity, and the
data from the ``Get Device Id'' command when looking at the MC.

If the system has OEM controls and sensors, they may have been created
by OEM code and may not have come from SDRs (thus the phrase
``generally'' in the first sentance of this section).  This is a major
reason not to use direct IPMI messaging with OpenIPMI.  OpenIPMI
provides an abstraction for the sensors and controls and thus multiple
implementations can sit below it.  If software bypasses the
abstraction, it will loose the ability to talk to non-standard sensors
and controls that use the same abstraction.

\subsection{Callbacks}

As you will discover, OpenIPMI is very callback based.  The callbacks
are somewhat fined grained; you register for exactly what you want to
see on individual objects.  This is not as bad as you might imagine
(even though it may seem somewhat strange).  It does mean that you
have to do a lot of registering in all the right places, though.
\acs{IPMI} has a large number of asynchronous things that it has to
inform you about.  If it delivered all these through one interface,
you would have to look at each call and try to figure out what type of
things was being reported, what object is was associated, etc.  In
effect, that work is done by OpenIPMI.

For user-level callbacks, the object the callback is for will always
be valid, it will never be NULL.  This means, for instance, if you
request a reading from a sensor, the reading response will always get
called and the sensor parameter will always be valid.  It may be in
the destruction process and you cannot set any setting, get any
readings, or anything else that requires sending a message.  If the
handler gets an \verb=ECANCELED= error, the sensor is being destroyed.
This also applies to all control, entity, and most domain callbacks.
This is new for OpenIPMI 1.4, but is fully backwards compatible.

This does \emph{not} apply to internal interfaces, especially ones that
send messages.  If you send a message to a \acs{MC}, for instance, the
\acs{MC} can be NULL when the response comes back.  Be very careful.

Note that the handlers don't get called immediately with current state
when you add a callback handler.  So you must register for the event
then query the current state.

\subsubsection{Updated Callbacks}

Updated callbacks tell you when an object comes into existance, is
destroyed, or if configuration information about an object has
changed.  On an entity, for instance, when an entity is first added,
the entity update handler on the domain will be called with the
entity.  when an \ac{SDR} is read and causes a change to the entity, the
updated handler will be called again with the change.  When the entity
is deleted, it will be called again.

In general, you should add updated handlers whenever the thing you
want to register against comes into existance.  So for entities and
the main event handler, you should register them in the
\verb=setup_done= callback for the domain.  The entity update handler
should register the update handlers for sensors, controls, and \ac{FRU}
information.  It should register the event handlers for presence and
hot-swap there, too.

Sensor and control update handlers should set up and register for
events from the sensor.

\subsubsection{Asynchronous Callbacks}

Asynchronous callbacks tell you when asynchronous things happen in the
system.  For instance, a card gets plugged in and an entity becomes
present.  You will be told with the present callback on the entity.
The hot-swap state of an entity changes.  That is reported via the
hot-swap state callback.  Events because of sensors going out of range
is another example.

Note that these are usually due to an IPMI event, but do not
necessarily have to be caused by an IPMI event.  For instance, if,
during an audit, OpenIPMI discovers that it has the state wrong for
something, it will report the correct state in a callback.

\subsubsection{Synchronous Callbacks}

Synchronous callbacks are callbacks for things you request and are
one-shot operations.  For instance, if you want to know the current
value of a sensor, you call call \verb=ipmi_reading_get()= and you
give it a handler to call when the reading has been fetched.

This is always done for things that OpenIPMI might have to send a
message to do.  It is a result of OpenIPMI's requirement to be able to
work in non-threaded systems and still be responsive to operations
while waiting.

\section{OpenIPMI Include Files}

OpenIPMI has a large number of include files.  The ones dealing with
internals are in the internal directory and are only needed for
\acs{OEM} code.  The include file are classified by need in the
sections below.

\subsection{Files the normal user deals with}

\begin{tabularx}{\textwidth}{lX}
\texttt{ipmiif.h} & 
The main include file for OpenIPMI.  It contains the main functions the
user must deal with when working with the OpenIPMI library.  Almost
everything will include this.  It includes \texttt{ipmi\_types.h} and
\texttt{ipmi\_bits.h}, too, so you don't have to include those.\\

\texttt{ipmi\_fru.h} &
Interface for \ac{FRU} data.\\

\texttt{ipmi\_auth.h} &
The file holding information about athentication algorithms.  You need
this if dealing with an authenticated interface.\\

\texttt{ipmi\_bits.h} &
Various values, mostly for sensors, used by the user.  \texttt{ipmiif.h}
includes this file, so you generally don't have to include it explicitly.\\

\texttt{ipmi\_types.h} &
Types for the basic IPMI objects.  \texttt{ipmiif.h} includes this file,
so you generally don't have to include it explicitly.\\

\texttt{ipmi\_err.h} &
Error values, both IPMI and system, as well as macros for interpreting
these.\\

\texttt{os\_handler.h} &
The os-specific handler types are defined here.  You must implement this
and supply it to the IPMI code.\\

\texttt{selector.h} &
For *nix systems, This file provides a default mechanism for handling many of
the os-specific handler operations.\\

\texttt{ipmi\_posix.h} &
This defines some POSIX OS handlers.\\

\texttt{ipmi\_log.h} &
Holds definitions for the logging interface.\\

\end{tabularx}

\subsection{Files dealing with messaging interfaces}

\begin{tabularx}{\textwidth}{lX}
\texttt{ipmi\_lan.h} &
This is the \acs{LAN} messaging interface, this contains the calls for
creating a \acs{LAN} connection.\\

\texttt{ipmi\_smi.h} &
This is the messaging interface for talking to local IPMI interfaces
(like KCS), this contains the calls for creating an SMI connection.\\

\end{tabularx}

\subsection{File for system configuration}

\begin{tabularx}{\textwidth}{lX}
\texttt{ipmi\_pef.h} &
Contains code for configuring the \ac{PEF}.\\

\texttt{ipmi\_lanparm.h} &
Contains code for configuring the \acs{LAN} configuration data.\\

\texttt{ipmi\_pet.h} &
Contains code that allows the user to easily set up an IPMI \acs{LAN}
interface on a BMC to send \ac{SNMP} traps.\\

\end{tabularx}

\subsection{Semi-internal includes}
These files expose the more IPMI-ish parts of OpenIPMI; things that
are closer to raw IPMI.  You should not use these unless you really
need them.

\begin{tabularx}{\textwidth}{lX}
\texttt{ipmi\_mc.h} &
This defines interfaces for the management controllers.\\

\texttt{ipmi\_addr.h} &
The file holding information about IPMI addresses.\\

\texttt{ipmi\_conn.h} &
This defines the interface for the messaging interfaces.\\

\texttt{ipmi\_msgbits.h} &
This defines various IPMI messages.\\

\texttt{ipmi\_picmg.h} &
This defines various PIGMC messages.\\

\texttt{ipmi\_sdr.h} &
This defines internal interfaces for the \ac{SDR} repository.\\

\end{tabularx}

\section{Starting Up OpenIPMI}
\label{starting-up-openipmi}

Starting up OpenIPMI is relatively easy.  You must allocate an OS
handler and initialize the library with it.  Then you are free to set
up connections.  The following code shows this for a non-threaded
POSIX program:

\begin{verbatim}
    os_hnd = ipmi_posix_setup_os_handler();
    if (!os_hnd) {
        printf("ipmi_smi_setup_con: Unable to allocate os handler\n");
        exit(1);
    }

    /* Initialize the OpenIPMI library. */
    ipmi_init(os_hnd);
\end{verbatim}

The \verb=ipmi_init= function should be done \emph{once} when your
program starts up.  Generally, you only have one OS handler, but you
are free to have more if they interwork properly and you have some
special need.

\section{Creating OpenIPMI Domains}
\label{creating-openipmi-domains}

If you want to talk to an \acs{IPMI} \ac{BMC}, you must create a
connection to it.  The connection method depends on the type of
connection; these are described in Chapter \ref{ipmi-interfaces}.

Once you have a connection, you can open a domain with it.  You do
this like so:

\begin{verbatim}
ipmi_con_t       cons[N];
int              num_cons, rv;
ipmi_domain_id_t id;

/* Set up connection(s) here */

rv = ipmi_open_domain(cons, num_cons, con_change, user_data,
                      domain_fully_up, user_data2,
                      options, num_options, &domain_id);
\end{verbatim}

\subsection{Domain Connections}

Up to two connections to a single domain are currently supported.  A
connection is an independent \ac{MC} in the same domain; if two MCs
have external connections, they can both be used for fault-tolerance.
This generally requires some special support for the particular domain
type, see the appendices on specific domain types for more detail.
The \verb=con_change= function is called whenever the connection
changes states (a connection is established or lost).  The connection
change callback looks like:

\begin{verbatim}
static void
con_change(ipmi_domain_t *domain,
           int           err,
           unsigned int  conn_num,
           unsigned int  port_num,
           int           still_connected,
           void          *user_data)
{
  ...
}
\end{verbatim}

If a connection is established, then \verb=err= will be zero.
Otherwise it is the error that caused the connection to fail.  The
\verb=conn_num= parm is the particular connection number (from the
\verb=cons= array passed into the domain setup).  A connection may
have specific ports, generally multiple connections to the same
\ac{MC}.  The \verb=still_connected= parm tells if you still have some
connection to the domain.

If a connection is down, the connection change callback will be called
periodically to report the problem as OpenIPMI attempts to
re-establish the connection.

\subsection{Domain Fully Up}

The \verb=domain_fully_up= callback will be called after the domain
has been fully scanned, all SDRs fetched, all FRUs fetched, and all
SELs read for the first time.  This gives you an indication that the
domain is completely ``up'', although there really is no concept of
completely ``up'' in IPMI since the system may dynamically change.  It
is useful for some things, though (and people complained a lot about
not having it in the past) so it is now available.  The callback is in
the form:
\begin{verbatim}
static void
domain_fully_up(ipmi_domain_t *domain,
                void          *user_data2)
{
  ...
}
\end{verbatim}
Note that this will \emph{not} be called until the domain is fully up.
If the domain never comes up, this will \emph{never} be called.  So
don't rely on this.  The connection up callback will always be called.

\subsection{Redundancy in Domain Connections}

Since maintenance interfaces often need to be reliable in the face of
network or hardware outages, they often have multiple connections.
The IPMI standards do not address this, but many systems implement
some form of redundancy.

The OpenIPMI library manages two different forms of redundancy in
connections:
\begin{description}
\item[Two IP addresses for the same BMC] - In this mode, the library
talks to the same BMC over two different channels.  This is managed by
the connection code itself.  The \acs{LAN} code does this; it allows
you to specify more than one IP address and port.  It will make
connections to both and make them look like they are one connection.
It will report, through the connection interface, if the individual
connections go up or down.  Note that some systems have multiple IP
addresses but are unable to use both at the same time, so check with
your hardware to see if this will work.
\item[Connections to multiple BMCs] - This means you have connections
to more than one BMC.  The domain code will round-robin messages on
the active connections, handle and report failures, and switchover
from failed to working connections.  A connection has the concept of
being ``active'' or ``inactive''.  An inactive connection is one where
the connection is up but the BMC in question is not fully operational;
you don't want to use it.  This is an active/standby type
configuration.  If all connections are always active (an active/active
type configuration), no special handling is required.  If some
connections can be inactive, special OEM code is required for that
connection as the domain handling must have a way to activate an
inactive connection if the active connection goes down.  See the
Motorola MXP in appendix~\vref{app-motorola-mxp} for an example of an
active/standby connection.
\end{description}

Note that the two redundancy modes can be used together.  You can have
two \acs{LAN} connections each to two BMCs.  In the author's opinion,
this, with an active/active configuration is the best redundancy and
is simple to implement.

Some systems like \acs{ATCA} have a ``floating'' address that is used.
The system has more than one BMC, generally, but it has an address
that will ``float'' between the BMCs depending on which one is active.
If a BMC fails, another BMC transparently takes over the floating
address.  So in this type of configuration the redundancy is managed
by the BMCs.  This leaves the question open of how to monitor the
inactive BMCs, though.  ATCA has addressed this in recent standards.
See appendix~\vref{app-atca} for details on how this works in
\acs{ATCA}.

\subsection{Domain Options}

When a domain is created, it may be passed options to control how the
domain operates.  For instance, if you do not want to scan FRUs, or
you do not want to fetch SDRs, you can control exactly what OpenIPMI
will do.

Control of this is done through the options.  This is an array of values
passed to \verb=ipmi_open_domain=.  Each element is:
\begin{verbatim}
typedef struct ipmi_open_option_s
{
    int option;
    union {
        long ival;
        void *pval;
    };
} ipmi_open_option_t;
\end{verbatim}
The option goes into the \verb=option= variable and the union holds
the option value, whose type depends on the option.
Table~\vref{domain-options} shows the options available.

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_OPEN\_OPTION\_ALL} & Uses the \texttt{ival} value as a boolean.
        This is an all-or-nothing enable.  If this is enabled, then all
        startup processing will be done.  If this is disabled, then the
        individual startup processing options will be used to individually
        control the enables.  This is true by default.\\
\hline
\texttt{IPMI\_OPEN\_OPTION\_SDRS} & Uses the \texttt{ival} value as a boolean.
        The all option overrides this.
        This enables or disables fetching SDRs.
        This is false by default.\\
\hline
\texttt{IPMI\_OPEN\_OPTION\_FRUS} & Uses the \texttt{ival} value as a boolean.
        The all option overrides this.
        This enables or disables fetching FRU information.
        This is false by default.\\
\hline
\texttt{IPMI\_OPEN\_OPTION\_SEL} & Uses the \texttt{ival} value as a boolean.
        The all option overrides this.
        This enables or disables fetching SELs.  Note that you can
        fetch the SELs by hand from an MC by setting
        \texttt{ipmi\_mc\_set\_sel\_rescan\_time()} to zero and then calling
        \texttt{ipmi\_mc\_reread\_sel()} when you want to reread the SEL.
        This is false by default.\\
\hline
\texttt{IPMI\_OPEN\_OPTION\_IPMB\_SCAN} & Uses the \texttt{ival} value as
        a boolean.
        The all option overrides this.
        This enables or disables automatic scanning of the IPMB bus.  If
        you turn this off you can still scan the bus by hand using the
        \texttt{ipmi\_start\_ipmb\_mc\_scan()} function.
        This is false by default.\\
\hline
\texttt{IPMI\_OPEN\_OPTION\_OEM\_INIT} & Uses the \texttt{ival} value as a boolean.
        The all option overrides this.  This will enable or disable OEM
        startup code for handling special devices.  This is the code that
        creates custom controls and things like that.
        This is false by default.\\
\hline
\texttt{IPMI\_OPEN\_OPTION\_SET\_EVENT\_RCVR} & Uses the \texttt{ival} value as a
        boolean.  This is \emph{not} affected by the all option.  This
        enables setting the event receiver automatically.  If true,
        OpenIPMI will detect if the event destination of an MC is not set
        to a valid value and set it.  However, this requires admin level
        access; you will get errors if you connect with a lower level
        of access and have this turned on.
        This is true by default.\\
\hline
\end{tabularx}
\caption{\label{domain-options}Domain options in OpenIPMI}
\end{table}

%---------------------------------------------------------------------
\chapter{Use Cases}
\label{use-cases}
\acs{IPMI} brings a lot of complexity, so it better be useful for
something and we better know how to use it.  This chapter brings up
several different ways it can be used to improve system reliability.

\section{Simple Hardware Monitoring}
\label{simple-hardware-monitoring}
If you have a single system and wish to improve its reliability, you
may use IPMI to monitor the hardware.  We know a few things about
hardware:
\begin{enumerate}
\item Heat decreases the lifetime of silicon.
\item As capacitors degrade, they tend to fail slowly.
\item Fans tend to fail slowly.
\item If something fails, you generally have some time to do something
about it before the failure is catastrophic.
\end{enumerate}
By monitoring long-term trends of temperature, voltage, and fan speed
we may accurately predict when certain system components are going to
fail.  Then they can be replaced gracefully.

In addition, if software fails, you want want some mechanism to
automatically restart the failed software.

To do this, you need a four-fold approach:
\begin{itemize}
\item Record and periodically analyze long-term trends of heat,
voltage, and fan speed.  IPMI stores information about the limits of
the various components.  Long-term trending will tell you when values
of critical components are going to reach the limits.  It's a lot
better to know that your power supply will probably fail in five days
than to know that your power supply will fail in 30 seconds, or that
your system is now dead and you don't know why.
\item Monitor events coming from the system.  In the event of a sudden
failure, the IPMI system event log may give you some warning that
something is about to happen.  In the event of a catastrophic failure,
it may give you useful information for post-mortem analysis.
\item Use a watchdog timer to monitor for system software failures.
It is especially useful if the watchdog timer has a pretimeout that
says ``Hey, I'm going to reset you in a few seconds.'' that comes in
via an NMI.  If you have this, you can panic the system and get useful
information about what the system was doing when it failed.
\item Create a software system to monitor the rest of your software
and detect when it fails and restart the software.
\end{itemize}

OpenIPMI, of course, can be used to do a lot of this, but other useful
tools exist for this.  \acs{HPI} can be used in many places where
OpenIPMI can be used.  See chapter~\vref{comparison-with-hpi} for
details on the differences between OpenIPMI and HPI.

However, HPI and OpenIPMI can be overkill for this type of monitoring.
Another tool, ipmitool\cite{ipmitool}, can provide a simple interface
to the IPMI system.  It is easy to script and simple to use.

For the watchdog timer, the operation system generally provides an
abstract interface.  The OpenIPMI Linux device driver does this; it
provides a watchdog timer with pretimeouts via an NMI.  In an
operating system that does not have a nice interface to the watchdog
timer, it is possible to talk directly to the IPMI system to do this,
the NMI handling may be hard to do.

Software monitoring is beyond the scope of this book.

Figure~\vref{simple-monitoring} shows the pieces to accomplish this.

\begin{figure}
\includegraphics[width=\textwidth]{SimpleMonitoring.eps}
\caption{\label{simple-monitoring}Simple Monitoring}
\end{figure}

\section{Redundant Systems}
\label{redundant-systems}
In this case, your application may consist of two systems so that is
one fails, the other takes over.  In effect, these two systems are
``mated''.  For this configuration, you generally want each system to
monitor both itself (as described in
section~\vref{simple-hardware-monitoring} and its mate.  This way,
long-term trend data is held both in the local system and the mate so
it is resiliant agains faults.  It is generally a good idea to monitor
the mate's software.

Note that to monitor another system via IPMI, the IPMI system to be
monitored must have a LAN interface as described in
section~\vref{interface-lan}.

In addition to monitoring, it is generally necessary for a system to
be able to reset it's mate to recover it to a known state.  You can do
this over the IPMI LAN interface.

Since you now have multiple things managing the SEL, some extra logic
is required to coordinate their operation.
Section~\vref{multiple-sel-users} describes methods to do this.

In this situation, ipmitool becomes less attractive due to the polled
nature of it's operation.  Setting up LAN connections is expensive.
OpenIPMI and HPI tools will maintain a permanent connection to the
mate and reduce the connection overhead.

\section{Monitoring Clusters of Systems}
In this situation, you have a number of systems that are monitored by
a single management system\footnote{The management system may have
multiple nodes for fault tolerance, but can generally be viewed as a
single system}.  This is much like handling redundant systems as
described in section~\vref{redundant-systems} but instead of
monitoring one other system, the management system monitors a number
of other systems.  The system may or may not need hardware monitoring
on the individual monitored systems, as the management system can do
all that.  Individual system will still need software monitoring, of
course.

In this situation, the overhead of ipmitool may become burdensome to
the management systems.  Plus, these types of systems tend more toward
having a continuously running system management application.  In these
types of systems, something like OpenIPMI or HPI becomes even more
attractive.

\section{Bus Systems}
Bussed systems (as described in section~\vref{system-types} generally
have a number of computers plugged into and managed on a single
backplane.  They have a central management interface (that may be
redundant) that manages the system and communicates over a LAN to a
remote management application\footnote{The management application may
actually run on one or more of the computers on the bus, but is viewed
as ``remote'' because it would come in over the LAN.}.

In some ways these computers appear as individual systems and can be
viewed as such with an extra ``hop'' over the bus to get to them.
However, these systems have extra management capabilities and shared
resources that make monitoring somewhat different.

In a bussed system, cooling and power supply are shared.  In general
the management controller on the bus handles cooling control and power
management.  But if a power supply is about to fail or the cooling
system fails, it affects all the computers on the bus, not just one.
The management system must take this into account.

Also, these systems generally support hot-swap of the computers.  This
is generally done as a request mechanism where a maintenance person
will request (via a switch or something of that nature) that the board
be prepared for removal.  In general, the maintenance application must
approve the request and may need to inform the software on the board
what is happening.

Because these types of systems require more monitoring and persistent
state, ipmitool is not an option for maintaining a system like this.
It can still be used for querying information, but it cannot handle
the hot-swap operations.  OpenIPMI and/or HPI are needed for these
types of systems.

%---------------------------------------------------------------------
\chapter{IPMI Interfaces}
\label{ipmi-interfaces}

\acs{IPMI} has a large number of interfaces for talking to management
controllers.  They vary in performance and capability, but the same
messages work over the top of all of them.  Generally, it does not
matter how you interface to an \acs{IPMI} system, the messages will
work the same.

\section{OpenIPMI Generic Interface}
\label{openipmi-generic-interface}

The OpenIPMI libary has a generic interface to the various
connections.  You use a per-interface command to set up the interface,
but once set up, the interfaces all work the same.  The file shown in
Appendix \ref{ipmi-conn-h} defines the interface for connections.

Note that not all operations are available on all interfaces.  \acs{LAN}
connections, for instance, cannot receive commands.

\section{System Interfaces}

The most common interface to a management controller is the system
interface.  This provides a direct connection between the main
processor of a system and the management controller.  Obviously, this
interface isn't very useful if the system is turned off, but it allows
a running system to monitor itself.

The low-level format of a system interface message that is $n$ bytes
long is:

\begin{showmsg}
\hline
\msgitem{0}{Bits 0-1 - Destination \acs{LUN}\\
            Bits 2-7 - \acs{NetFN}}
\msgitem{1}{Command}
\msgitem{2 - n-1}{Message Data}
\end{showmsg}

Commands and responses have basically the same format, except that
responses always have the completion code as the first byte of the
message data.  See chapter \ref{ipmi-commands} for more details.

\subsection{\ac{SMIC}}
\label{sec-smic}
The \ac{SMIC} interface has been around a long time, but mostly during
a period when \acs{IPMI} was not popular.  This is a low-performance,
byte-at-a-time interface with no interrupt capability.

TBD - describe this interface in detail

\subsection{\ac{KCS}}
\label{sec-kcs}
The \ac{KCS} interface is currently the most popular \acs{IPMI} system
interface.  The \ac{KCS} interface looks electrically much like a
standard PC keyboard interface.  It was chosen because lots of cheap
hardware was available for these types of interfaces.  But it is still
a byte-at-a-time interface and performs poorly.  It has the capability
for interrupts, but very few systems have working interrupt capability
with \ac{KCS} interfaces.

TBD - describe this interface in detail

\subsection{\ac{BT}}
\label{sec-bt}
The \ac{BT} interface is the best interface for \acs{IPMI}.
Messages are sent a whole message at a time through the interface,
thus it is a much higher performance interface than the other system
interfaces.

TBD - describe this interface in detail

\subsection{\ac{SSIF}}
\label{sec-ssif}
The \ac{SSIF} interface was added in the 2.0 spec.  It provides an
interface over an \ac{I$^2$C} interface using the SMBus protocol.
This is very cost effective interface; most systems generally already
have an \ac{I$^2$C} bus, so no new interfaces to processor busses are
required.  However, \ac{I$^2$C} busses are not very fast and the
interfaces from the processor to the \ac{I$^2$C} bus tends to perform
poorly.

TBD - describe this interface in detail

\subsection{The OpenIPMI Driver}

The OpenIPMI driver on Linux provides a user interface to all the
standard \acs{IPMI} system interfaces.  It does so in a manner that allows
multiple users to use the driver at the same time, both users in the
kernel and users in user space.

To do this, the OpenIPMI driver handles all the details of addressing
and sequencing messages.  Other drivers allowed more direct access to
the \acs{IPMI} interface; that means that only one user at a time could use
the driver.  Since the \acs{IPMI} can be used for different purposes by
different users, it is useful to do the multiplexing in the kernel.

The details of configuring the \acs{IPMI} driver are found in the
\verb=IPMI.txt= file in the kernel documentation; those details won't
be discussed here.

To use the \acs{IPMI} device driver, you open the \verb=/dev/ipmi0= or
\verb=/dev/ipmidev/0= file.  The driver allows multiple \acs{IPMI} devices
at the same time; you would increment the number to get to successive
devices.  However, most systems only have one.

The primary interface to the driver is through \verb=ioctl= calls.
\verb=read= and \verb=write= calls will not work because the \acs{IPMI}
driver separates the addressing and data for an \acs{IPMI} message.

The core description of an \acs{IPMI} message is:

\begin{verbatim}
struct ipmi_msg
{
        unsigned char  netfn;
        unsigned char  cmd;
        unsigned short data_len;
        unsigned char  *data;
};
\end{verbatim}

The \verb=netfn= describes \ac{NetFN} of the class of message being
sent.  \acs{IPMI} messages are grouped into different classes by
function.  The \verb=cmd= is the command within the class.  Chapter
\ref{ipmi-commands} discusses this is more detail.  The \verb=data=
and \verb=data_len= fields are the message contents.  This structure
is used in both sent and received messages.

\subsubsection{Sending Commands}
To send a command, use the following:

\begin{verbatim}
rv = ioctl(fd, IPMICTL_SEND_COMMAND, &req);
\end{verbatim}

The \verb=req= structure has the following format:

\begin{verbatim}
struct ipmi_req
{
        unsigned char   *addr;
        unsigned int    addr_len;
        long            msgid;
        struct ipmi_msg msg;
};
\end{verbatim}

The \verb=addr= and \verb=addr_len= fields describe the destination
address of the management controller to receive message.  The
\verb=msg= field itself gives the message to send.  The msgid is a
field for the user; the user may put any value they want in this
field.  When the response comes back for the command, it will contain
the message id.  Since it is a long value, it can be used to hold a
pointer value.

The driver guarantees that the user will receive a response for every
message that is successfully sent.  If the message times out or is
undeliverable, an error resonse will be generated and returned.

The following code fragment shows how to send a message to the local
management controller, in this case a command to read the value of a
sensor:

\begin{verbatim}
struct ipmi_req                   req;
unsigned char                     data[1];
struct ipmi_system_interface_addr si;

/* Format the address. */
si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
si.channel = IPMI_BMC_CHANNEL;
si.lun = 0;

req.addr = (void *) &si;
req.addr_len = sizeof(si);
req.msgid = 0x1234;
req.msg.netfn = 0x04; /* Sensor/Event netfn */
req.msg.cmd = 0x2d; /* Get sensor reading */
req.msg.data = data;
req.msg.data_len = 1;
data[0] = 10; /* Read sensor 10 */

rv = ioctl(fd, IPMICTL_SEND_COMMAND, &req);
\end{verbatim}

Note that sending the command is asyncronous; you will not immediately
get the response.  Instead, the response comes back later and can be
received at that point in time.  This is what makes the \verb=msgid=
important.

The following example shows sending a get device id request to \ac{IPMB}
address 0xb2.

\begin{verbatim}
struct ipmi_req       req;
struct ipmi_ipmb_addr si;

/* Format the address. */
si.addr_type = IPMI_IPMB_ADDR_TYPE;
si.channel = 0;
si.lun = 0;
si.slave_addr = 0xb2;

req.addr = (void *) &si;
req.addr_len = sizeof(si);
req.msgid = 0x1234;
req.msg.netfn = 0x06; /* App netfn */
req.msg.cmd = 0x01; /* Get device id */
req.msg.data = NULL;
req.msg.data_len = 0;

rv = ioctl(fd, IPMICTL_SEND_COMMAND, &req);
\end{verbatim}

\subsubsection{Receiving Responses and Events}
As mentioned before, the responses to commands come back in later.
You can use standard \verb=select= and \verb=poll= calls to wait for
messages to come in.  However, you cannot use \verb=read= to get the
message.  The following data structure is used to receive messages:

\begin{verbatim}
struct ipmi_recv
{
        int             recv_type;
        unsigned char   *addr;
        unsigned int    addr_len;
        long            msgid;
        struct ipmi_msg msg;
};
\end{verbatim}

The \verb=recv_type= field can be one of the following values:

\begin{description}
\item[IPMI\_RESPONSE\_RECV\_TYPE] A response to a sent command.
\item[IPMI\_ASYNC\_EVENT\_RECV\_TYPE] An asyncronous event.
\item[IPMI\_CMD\_RECV\_TYPE] A command was received for the system
software.
\item[IPMI\_RESPONSE\_RESPONSE\_TYPE] Responses sent by this
interface get acked using one of these.  This way you can tell if
there was an error sending the response.
\end{description}

Received commands are discussed in section \ref{recv-cmd-resp}.  You
have to fill in the data for the driver to put the received
information into.  The following shows how to receive a message:

\begin{verbatim}
unsigned char    data[IPMI_MAX_MSG_LENGTH];
struct ipmi_addr addr;
struct ipmi_recv recv;
int              rv;

recv.msg.data = data;
recv.msg.data_len = sizeof(data);
recv.addr = (unsigned char *) &addr;
recv.addr_len = sizeof(addr);
rv = ioctl(fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv);
if (rv == -1) {
    if (errno == EMSGSIZE) {
        /* The message was truncated, handle it as such. */
        ...
    }
}
switch (recv.recv_type) {
case IPMI_RESPONSE_RECV_TYPE: ...
case IPMI_ASYNC_EVENT_RECV_TYPE: ...
case IPMI_CMD_RECV_TYPE: ...
case IPMI_RESPONSE_RESPONSE_TYPE: ...
\end{verbatim}

The \verb=msgid= comes in very handy for this responses, it lets you
easily correlate commands and responses.  It has no meaning for events.

The \verb=netfn= for a received message have a ``one'' bitwise or-ed
onto the value.  In \acs{IPMI}, even \acs{NetFN}s are always commands
and odd \acs{NetFN}s are always responses.

For responses, the address will always be the same as the sent
address.

An interface will not receive events by default.  You must register to
receive them with the following:

\begin{verbatim}
int val = 1;
rv = ioctl(fd, IPMICTL_SET_GETS_EVENTS_CMD, &val)
\end{verbatim}

Setting \verb=val= to true turns on events, setting it to false turns
off events.  Multiple users may register to receive events; they will
all get all events.  Note that this is for receiving asyncronous
events through the interface.  The events also go into the event log
as described in chapter \ref{events}, but that is a different thing.
If you receive an event through this interface, you will also get it
in the event log.  Section \ref{event-format} describes the format of
events.

\subsubsection{Receiving Commands and Responding}
\label{recv-cmd-resp}
Commands sent to \ac{LUN} two of a management controller will generally be
routed to the driver.  If the driver does not have a registered user
for that command, it will respond that it does not handle that
command.

If you wish to receive commands, you must register to receive those
commands.  The \verb=cmdspec= structure defines commands the program
wishes to receive:

\begin{verbatim}
struct ipmi_cmdspec
{
        unsigned char netfn;
        unsigned char cmd;
};
\end{verbatim}

These are registered with the following ioctl:

\begin{verbatim}
rv = ioctl(fd, IPMICTL_REGISTER_FOR_CMD, &cmdspec);
\end{verbatim}

To remove a registered command, use the following:

\begin{verbatim}
rv = ioctl(fd, IPMICTL_UNREGISTER_FOR_CMD, &cmdspec);
\end{verbatim}

If you receive a message, you must send a response.  The driver makes
this easy, you can always use the received address to send the
response to.  The program in Appendix \ref{recv-cmd-prog} receives one
message, sends a response, and exits.  When you respond, you must
supply the \verb=msgid= that came into the command.

\subsubsection{Overriding Default Timing Values}
Be default, commands over \ac{IPMB} get resent up to 5 times with a 1
second timeout between the sends.  For very select applications, this
is not suitable.  Primarily, some applications need to only send once,
they have a higher-level resend mechanism and the OpenIPMI resends
will only get in the way.

Note that responses over \ac{IPMB} will not get timed or resent.

The user may modify the timing values two different ways.  The user
can set the default resend and retry times for a file descriptor with
the following structure:

\begin{verbatim}
struct ipmi_timing_parms
{
        int          retries;
        unsigned int retry_time_ms;
};
\end{verbatim}

The \verb=retries= parm is the number of times the message will be
resent.  The \verb=retry_time_ms= is the time in milliseconds between
resends.  To get and set the parameters, use the following:

\begin{verbatim}
struct ipmi_timing_parms tparms;

rv = ioctl(fd, IPMICTL_GET_TIMING_PARMS_CMD, &tparms);
if (rv == -1)
  error handling...

printf("parms were: %d %d", tparms.retries, tparms.retry_time_ms);

tparms.retries = 0; /* No resends */
tparms.retry_time_ms = 1000; /* one second */
rv = ioctl(fd, IPMICTL_SET_TIMING_PARMS_CMD, &tparms);
if (rv == -1)
  error handling...
\end{verbatim}

This will set the timing parameters for all future messages.  You can
also override the timing on individual messages.

\begin{verbatim}
struct ipmi_req_settime
{
        struct ipmi_req req;

        int          retries;
        unsigned int retry_time_ms;
};
\end{verbatim}

The \verb=req= is the request as shown previously.  Use the following
ioctl to perform the request:

\begin{verbatim}
rv = ioctl(fd, IPMICTL_SEND_COMMAND_SETTIME, &req_time);
\end{verbatim}

\subsubsection{Setting Your Local \ac{IPMB} Address}
Unfortunately, \acs{IPMI} has no standard way to determing your local \ac{IPMB}
address.  It is usually set to 20h but, especially in bussed systems,
the local management controller may have a different address.

If you do not set your \ac{IPMB} address properly, messages sent out on the
\ac{IPMB} will not have the proper source address and thus the response will go
to the wrong place.  To avoid this problem, the OpenIPMI allows the
user to set the local \ac{IPMB} address and the local \ac{LUN}.  The following
shows how to get and set the \ac{IPMB} address:

\begin{verbatim}
unsigned int ipmb_addr;

rv = ioctl(fd, IPMICTL_GET_MY_ADDRESS_CMD, &ipmb_addr);
if (rv == -1)
  error handling...

printf("My address was: %x", ipmb_addr);

ipmb_addr = 0xb2;
rv = ioctl(fd, IPMICTL_SET_MY_ADDRESS_CMD, &ipmb_addr);
if (rv == -1)
  error handling...
\end{verbatim}

The driver also has ioctls to get and set the \ac{LUN}, but you should
almost certainly leave that alone.

\subsection{The OpenIPMI System Interface}
The OpenIPMI library system interface can be set up with the
following function:

\begin{verbatim}
int ipmi_smi_setup_con(int                if_num,
                       os_handler_t       *handlers,
                       void               *user_data,
                       ipmi_con_t         **new_con);
\end{verbatim}

The \verb=if_num= is the specific interface number.  Generally this is
\verb=0=, but if a system has more than one system interface then this
will be the specific interface number.  The \verb=handlers= is the OS
handler data to use for the connection (as described in section
\ref{openipmi-os-handlers}).  The \verb=user_data= field is put into
the \verb=user_data= filed in the \verb=ipmi_con_t= data structure.  A
new connection is returned in \verb=new_con=.

The OpenIPMI library understands how to get the local \ac{IPMB} address for
certain sytems.  If it can get the local \ac{IPMB} address, it will set it
automatically.

Once you have a connection, you can start it and use it directly.
However, usually you pass this to the domain startup code for creation
of a domain, as described in section \ref{creating-openipmi-domains}.

\section{Channels}

The \acs{IPMI} interfaces on a management controller are called
``channels''.  These are messaging channels.  \acs{LAN}, \ac{IPMB}, system
interface, and any other messaging interfaces will each have their own
channel on the \ac{MC}.

Messages directly sent to the local management controller do not
require any type of channel information.  When the user sends a
message out to another interface, it must specify the channel.  This
is called ``bridging''.  Channels also may have some type of
configuration information such as users and passwords.

\begin{table}
\begin{tabularx}{\textwidth}{|l|l|X|}
\hline
0h & Primary \acs{IPMB} & Channel 0 is the primary \acs{IPMB} bus on the
system.\\
\hline
1h-7h & \parbox{1in}{Implementation-specific} & This channel may be any
type of channel, including \acs{IPMB}, and \acs{LAN} interfaces.\\
\hline
8h-Dh & & Reserved\\
\hline
Eh & Present I/F & This specifies the channel the message is going over.
It's not really very useful, since you have to put the real channel in
the command to send a message to it.\\
\hline
Fh & System Interface & This specifies the system interface, but is
really never used.\\
\hline
\end{tabularx}
\caption{\label{channel-list}Channel Numbers}
\end{table}

\section{Bridging}

\ac{IPMI} does not have any type of automatic routing.  Instead,
commands and responses are ``bridged'' between different interfaces
generally using a ``Send Message'' command.  So you have to know the
route to the destination when you send the message.  Generally, this
is not a big deal because only one level is generally bridged (eg
system interface to \ac{IPMB}, \ac{LAN} interface to \ac{IPMB}).

Note that OpenIPMI handles most of the bridging work for you.  The
OpenIPMI address described in section \ref{openipmi-addressing} has
address formats for routing messages to the proper places.  But
knowing what goes on behind the scenes can be helpful, and some of
this information is required even with OpenIPMI.

\subsection{Channels}

An interface has the concept of a ``channel''.  A channel is an
independent communication interface.  Each \ac{LAN} interface, serial
interface, \ac{IPMB} interface, and system interface has its own
channel number.  Messages are bridged to specific channels.

There are 16 specified channels.  Channel 0 is always the primary
\ac{IPMB} channel.  Channels 1-7 are for general use, like for
\ac{LAN}, secondary \ac{IPMB}, \ac{ICMB}, etc.  Channels 8-Dh are
reserved.  Channel Fh is for the system interface.  Channel Eh is used
for whatever the present interface is.  This is useful because some
commands take a channel as one of their fields, if you just want to
use the current channel you can put Eh here.

To discover the channels in a system, the ``Get Channel Info'' command
shown in table \ref{get-channel-info-cmd} must be sent for each
possible channel.

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{
        \begin{tightdefs}
        \item[bits 0-3] - Channel number
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgitem{1}{
        \begin{tightdefs}
        \item[bits 0-3] - Actual channel number (if you put Eh in the
          request, the real channel number is returned here)
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgitem{2}{
        \begin{tightdefs}
        \item[bits 0-6] - Channel medium type.  Valid values are:
          \begin{tightdefs}
          \item[00h] - reserved
          \item[01h] - \acs{IPMB} (\acs{I$^2$C})
          \item[02h] - \acs{ICMB} version 1.0
          \item[03h] - \acs{ICMB} version 0.9
          \item[04h] - 802.3 (Ethernet)
          \item[05h] - Async serial/modem (RS-232)
          \item[06h] - Other \acs{LAN}
          \item[07h] - PCI SMBus
          \item[08h] - SMBus Versions 1.0/1.1
          \item[09h] - SMBus Version 2.0
          \item[0Ah] - reserved for USB 1.x
          \item[0Bh] - reserved for USB 2.x
          \item[0Ch] - System Interface
          \item[60h-7Fh] - \acs{OEM}
          \end{tightdefs}
          All other values are reserved.
        \item[bit 7] - reserved
        \end{tightdefs}}
\msgitem{3}{
        \begin{tightdefs}
        \item[bits 0-4] - Channel protocol type.  Valid values are:
          \begin{tightdefs}
          \item[00h] - reserved
          \item[01h] - \acs{IPMB}-1.0, used for acs{IPMB}, serial/modem
            basic mode, and \acs{LAN}.
          \item[02h] - \acs{ICMB}-1.0, see section \ref{sec-icmb}
          \item[03h] - reserved
          \item[04h] - \acs{IPMI} over SMBus
          \item[05h] - \acs{KCS}, see section \ref{sec-kcs}
          \item[06h] - \acs{SMIC}, see section \ref{sec-smic}
          \item[07h] - \acs{BT} from IPMI v1.0, see section \ref{sec-bt}
          \item[08h] - \acs{BT} from IPMI v1.5, see section \ref{sec-bt}
          \item[09h] - Terminal mode, see section \ref{sec-terminal-mode}
          \item[1Ch-1Fh] - \acs{OEM}
          \end{tightdefs}
          All other values are reserved.
        \item[bits 5-7] - reserved
        \end{tightdefs}}
\msgitem{4}{This field describes session information about the channel.
        See section \ref{sec-session-support} for details on sessions.
        \begin{tightdefs}
        \item[bits 0-5] - The number of sessions that have been activated
          on a given channel.  This is only valid if the channel has session
          support.
        \item[bits 6-7] - Session support, values are:
          \begin{tightdefs}
          \item[00b] - channel does not support sessions.
          \item[01b] - channel is single-session. 
          \item[10b] - channel is multi-session.
          \item[11b] - channel is sessions based, but may switch
            between single and multiple sessions.
          \end{tightdefs}
        \end{tightdefs}}
\msgitem{5-7}{Vendor ID, used to specify the IANA number for the organization
        that defined the protocol.  This should always be the IPMI IANA,
        which is 7154 (decimal), or F2H, 1Bh, and 00H for these bytes.}
\msgitem{8-9}{Auxiliary channel info.

        For channel Fh, this is byte 8 is the interrupt for the system
        interface, byte 9 is the interrupt for the event message buffer
        interface.  Valid values are:
        \begin{tightdefs}
        \item[00h-0Fh] - IRQ 0-15
        \item[10h-13h] - PCI A-D, respectively
        \item[14h] - SMI
        \item[15h] - SCI
        \item[20h-5Fh] - System interrupt 0-62, respecitively
        \item[60h] - Assigned by ACPI, SMBIOS, or a plug and play mechanism.
        \item[FFh] - No interrupt or unspecified
        \end{tightdefs}
        All other values are reserved.

        For \ac{OEM} channel types, this value is OEM defined. These
        bytes are reserved for all other channel types.}
\msgcaption{\label{get-channel-info-cmd}Get Channel Info Command,
  NetFN App (06h), Cmd 42h}
\end{showmsg}

\subsection{Sending Bridged Messages}

Table \ref{send-msg-cmd} shows the format of a Send Message command.
Note that the spec says the response can have response data for
non-system interface channels.  However, this is not actually the
case, response data for \acs{LAN} and serial channels is carried in a
different manner.

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{Channel information, bits are:
        \begin{tightdefs}
        \item[0-4] - Channel number
        \item[4-5] - reserved
        \item[6-7] - tracking type.  See section \ref{sec-message-tracking}
          for more information.  Values are:
          \begin{tightdefs}
          \item[00b] - No tracking
          \item[01b] - Track request
          \item[10b] - Send raw.  This is a test mechanism or a mechanism
            used for transmitting proprietary protocols.  It is optional.
          \item[11b] - reserved
          \end{tightdefs}
        \end{tightdefs}}
\msgitem{1-n}{Message data.  The format depends on the channel type.  See
        the section on the specific channel type for more information.}
\msgtag{Response}
\msgitem{0}{Completion code.  If transmitting on an \acs{IPMB}, SMBus, or
        PCI management bus, the following return codes are used to inform
        the sender of sending problems:
        \begin{tightdefs}
        \item[81h] - lost arbitration
        \item[82h] - Bus Error
        \item[83h] - NAK on Write
        \end{tightdefs}}
\msgcaption{\label{send-msg-cmd}Send Message Command,
  NetFN App (06h), Cmd 34h}
\end{showmsg}

\subsection{Message Tracking}
\label{sec-message-tracking}

Message tracking is relatively simple, but difficult to understand from
the spec.  This section should clear that up.

Messages sent from the system interface to the IPMB interface do not
have to be tracked.  Instead, the sender sets the requester (source)
LUN to 2.  In the response, the responder will thus set the requester
(destination) LUN to 2.  If an \ac{MC} receives a message with a destination
LUN of 2, it will route it back to the system interface.  Simple to do and
no state is required in the \ac{MC}.

Other channels cannot do this.  They must instead rely on message
tracking to handle the responding.  With message tracking, the \ac{MC}
reformats the message with its own information and remembers the
original message information.  When the response comes back, the
\ac{MC} will restore the original information in the response.  Note
that the sender must still format the message properly for the
destination channel.

\subsection{Receiving Asynchronous Messages on the System Interface}
\label{sec-recv-async-msg}

Asynchronous messages to the system interfaces (ones with the
destination \ac{LUN} set to 2), both commands and responses, have no
direct route to be sent up the system interface.  Instead, they go
into the receive message queue and the software is informed
through the system interface that something is in the queue.  The
software must then fetch the message from the queue using the Get
Message command described in table \ref{get-msg-cmd}.

\begin{showmsg}
\msgtag{Request}
\msgitem{-}{}
\msgtag{Response}
\msgitem{0}{Completion code}
\msgitem{1}{Channel information, bits are:
        \begin{tightdefs}
        \item[0-4] - Channel number
        \item[4-7] - Inferred privilege level for the message.  Table
          \ref{ipmi-priv-levels} describes the privilege levels.

          If the message is received from a session-oriented channel,
          this will generally be set to the maximum privilege level of
          the session.

          If per-message authentication is enabled, this will be set to
          User privilege for unauthenticated messages.

          The privilege will be then lowered based on the privilege
          limit set by the Set Session Privilege Level command.

          For messages from sessionless channels, this will always
          be set to ``None''.

          Privilege levels are:
          \begin{tightdefs}
          \item[0] - None (unspecified)
          \item[1] - Callback
          \item[2] - User
          \item[3] - Operator
          \item[4] - Admin
          \item[5] - OEM
          \end{tightdefs}
        \end{tightdefs}}
\msgitem{2-n}{Message data.  The format depends on the channel type.  See
        the section on the specific channel type for more information.}
\msgcaption{\label{get-msg-cmd}Get Message Command,
  NetFN App (06h), Cmd 33h}
\end{showmsg}

To know if a message is waiting in the asynchronous queue, the
interface will generally set some flag so that the user may
immediately know.  The software will then send a Get Message Flags
command (table \ref{get-msg-flags}) to know find out what is up.  A
bit will be set in the response to tell it something is in the queue.

\begin{showmsg}
\msgtag{Request}
\msgitem{-}{}
\msgtag{Response}
\msgitem{0}{Completion code}
\msgitem{1}{Flags.  The bits are:
        \begin{tightdefs}
        \item[0] - message(s) in the receive message queue.
        \item[1] - Event message buffer is full
        \item[2] - reserved
        \item[3] - Watchdog pre-timeout
        \item[4] - reserved
        \item[5] - OEM 0
        \item[6] - OEM 1
        \item[7] - OEM 2
        \end{tightdefs}}
\msgcaption{\label{get-msg-flags}Get Message Flags Command,
  NetFN App (06h), Cmd 31h}
\end{showmsg}

\subsection{System Interface to \acs{IPMB} Bridging}

For bridging from a system interface to \ac{IPMB}, format an \ac{IPMB}
message as described in section \ref{sec-ipmb} and set the requester
\ac{LUN} to 2.  Then issue a Send Message command with the \ac{IPMB}
message as the data to the proper IPMB channel; the message will be
routed out onto the IPMB bus.

The response will come back to the \ac{MC} with the requester \ac{LUN}
set to 2.  This will route the message back to the system interface,
where it will be put into the receive message queue.  The
software running on the system must receive the message from the queue
using the Get Message command described in section \ref{sec-recv-async-msg}.

The response data will be in the same \ac{IPMB} format.

\subsection{\acs{LAN} to IPMB Bridging}

Unfortunately, the description in the spec of the LAN protocol is very
confusing.  An errata was introduced that, instead of clearing things
up, added another possible interpretation.  Four popular
interpretations are common.  Fortunately, one piece of software can be
written to work with three of these possibilities, and the fourth
possibility is rather broken.  The three main possibilities are:

\begin{itemize}
\item Response comes back in the Send Message response
\item Separate Send Message and IPMB responses
\item Separate Send Message and Translated responses
\end{itemize}

One might also infer from the spec that you implement the receive
message queue on the LAN interface and poll it with the Get Message
command.  It is yet another possible interpretation, but the side
effects of this are very bad.  This will not be discussed any more.

In the examples below, a Get Device ID is encasulated in a Send
Message and sent to IPMB address C0h.  For these examples, the RMCP
headers and authentication information are skipped, we start directly
with the \ac{IPMI} message.  The sent data is always the same, and is:

\begin{longtable}{|l|l|p{0.7\textwidth}|}
\hline
\bfseries{Byte} & \bfseries{Value} & \bfseries{Description}\\
\hline
0 & 20h & \acs{LAN} Responder address, this is the BMC's IPMB, generally\\
\hline
1 & 18h & \acs{LAN} Responder \acs{LUN} in bits 0-1 (0 in this case),
         Send Message \acs{NetFN} in bits 2-7 (6 in this case)\\
\hline
2 & C8h & Checksum for the previous two bytes\\
\hline
3 & 81h & \acs{LAN} Requester address (this is the value for system management
        software)\\
\hline
4 & B8h & Requester LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2eh in this case).  Note that the sequence number
        is returned in the response as-is and helps differentiate the
        messages.\\
\hline
5 & 34h & The command, a Send Message for \acs{NetFN} 6.\\
\hline
6 & 40h & The channel number in bits 0-4 (0 in this case), and message
        tracking selection in bits 6-7 (10b in this case, message tracking
        is on).\\
\hline
7 & C0h & The destination \acs{IPMB} address\\
\hline
8 & 18h & \acs{IPMB} Responder \acs{LUN} in bits 0-1 (0 in this case),
         Get Device ID \acs{NetFN} in bits 2-7 (6 in this case)\\
\hline
9 & 28h & Checksum for the previous two bytes\\
\hline
10 & 20h & Source address, the IPMB address of the BMC.\\
\hline
11 & BEh & Requester LUN in bits 0-1 (2 in this case, although it generally
        doesn't matter), Sequence number in bits 2-7 (2fh in this case).\\
\hline
12 & 01h & The command, a Get Device Id for \acs{NetFN} 6\\
\hline
13 & 25h & Checksum for the IPMB message (from bytes 7-12)\\
\hline
14 & 49h & Checksum for the whole message\\
\hline
\end{longtable}

If you look at this, a lot of the contents seem pretty silly.  The
addresses in the LAN header, for instance, are pretty useless, but
probably there for consistency.

\subsubsection{Response comes back in the Send Message response}

In this possibility, the send message response contains the message
data response.  This seems to be implied in the text of the Send
Message command, and is certainly the most efficient way to handle
this.  However, it does not seem to be the accepted way.

As an example, the following shows the response to the Get Device ID
previously sent:

\begin{longtable}{|l|l|p{0.7\textwidth}|}
\hline
\bfseries{Byte} & \bfseries{Value} & \bfseries{Description}\\
\hline
0 & 81 & Requester Address\\
\hline
1 & 1c & \acs{LAN} Requester \acs{LUN} in bits 0-1 (0 in this case),
         Send Message response \acs{NetFN} in bits 2-7 (7 in this case)\\
\hline
2 & 63 & Checksum for the previous two bytes\\
\hline
3 & 20 & Responder Address\\
\hline
4 & b8 & Responder LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2eh in this case).\\
\hline
5 & 34 & The command, a Send Message response in this case.\\
\hline
6 & 00 & Completion code\\
\hline
7 & 20 & IPMB Destination address (the BMC's IPMB address)\\
\hline
8 & 1E & \acs{IPMB} Requester \acs{LUN} in bits 0-1 (2 in this case),
         Send Message response \acs{NetFN} in bits 2-7 (7 in this case)\\
\hline
9 & C2 & Checksum for the previous two bytes\\
\hline
10 & C0 & Responder IPMB address\\
\hline
11 & BC & Requester LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2fh in this case).\\
\hline
12 & 01 & Command, a Get Device ID response\\
\hline
13 & 00 & message data\\
\hline
14 & 00 & message data\\
\hline
15 & 00 & message data\\
\hline
16 & 01 & message data\\
\hline
17 & 05 & message data\\
\hline
18 & 51 & message data\\
\hline
19 & 29 & message data\\
\hline
20 & 57 & message data\\
\hline
21 & 01 & message data\\
\hline
22 & 00 & message data\\
\hline
23 & 00 & message data\\
\hline
24 & 09 & message data\\
\hline
25 & 01 & message data\\
\hline
26 & 01 & message data\\
\hline
27 & 00 & message data\\
\hline
28 & 00 & message data\\
\hline
29 & 94 & Checksum for the entire message\\
\hline
\end{longtable}

That's it, the Send Message response contains all the data.

\subsubsection{Separate Send Message and IPMB responses}

In this possibility, a Send Message response comes back with no data
and the Send Message header data in the response header, then a
separate message comes back with the IPMB parameters in the header.
For instance, in the first message the source is the \ac{BMC}, in the
second message the source is the IPMB sender.

The following is the first message, the Send Message response, from
this format:

\begin{longtable}{|l|l|p{0.7\textwidth}|}
\hline
\bfseries{Byte} & \bfseries{Value} & \bfseries{Description}\\
\hline
0 & 81 & Requester Address\\
\hline
1 & 1c & \acs{LAN} Requester \acs{LUN} in bits 0-1 (0 in this case),
         Send Message response \acs{NetFN} in bits 2-7 (7 in this case)\\
\hline
2 & 63 & Checksum for the previous two bytes\\
\hline
3 & 20 & Responder Address\\
\hline
4 & b8 & Responder LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2eh in this case).\\
\hline
5 & 34 & The command, a Send Message response in this case.\\
\hline
6 & 00 & Completion code\\
\hline
7 & f4 & Checksum for the whole message.\\
\hline
\end{longtable}

The following is the second message, the IPMB response:

\begin{longtable}{|l|l|p{0.7\textwidth}|}
\hline
\bfseries{Byte} & \bfseries{Value} & \bfseries{Description}\\
\hline
0 & 20 & IPMB Destination address (the BMC's IPMB address)\\
\hline
1 & 1E & \acs{IPMB} Requester \acs{LUN} in bits 0-1 (2 in this case),
         Send Message response \acs{NetFN} in bits 2-7 (7 in this case)\\
\hline
2 & C2 & Checksum for the previous two bytes\\
\hline
3 & C0 & Responder IPMB address\\
\hline
4 & BC & Requester LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2fh in this case).\\
\hline
5 & 01 & Command, a Get Device ID response\\
\hline
6 & 00 & message data\\
\hline
7 & 00 & message data\\
\hline
8 & 00 & message data\\
\hline
9 & 01 & message data\\
\hline
10 & 05 & message data\\
\hline
11 & 51 & message data\\
\hline
12 & 29 & message data\\
\hline
13 & 57 & message data\\
\hline
14 & 01 & message data\\
\hline
15 & 00 & message data\\
\hline
16 & 00 & message data\\
\hline
17 & 09 & message data\\
\hline
18 & 01 & message data\\
\hline
19 & 01 & message data\\
\hline
20 & 00 & message data\\
\hline
21 & 00 & message data\\
\hline
22 & a0 & Checksum for the whole message\\
\hline
\end{longtable}

Notice that in this second response, the destination address, LUNs,
sequence numbers, etc. are from the IPMB message, not from the
original LAN message.

\subsubsection{Separate Send Message and Translated responses}

In this possibility, a Send Message response comes back with no data,
then a separate message comes back with the data, but the data in the
second message has the same header information as the first, with a
different command.  This could be inferred from the errata, but it
makes things more difficult to track.  For instance, if you
encapsulated a Send Message command inside a Send Message, the second
response would have the same command number as the first, so it would
be harder to tell the first response from the second.

The first response for the Get Device ID would be:

\begin{longtable}{|l|l|p{0.7\textwidth}|}
\hline
\bfseries{Byte} & \bfseries{Value} & \bfseries{Description}\\
\hline
0 & 81 & Requester Address\\
\hline
1 & 1c & \acs{LAN} Requester \acs{LUN} in bits 0-1 (0 in this case),
         Send Message response \acs{NetFN} in bits 2-7 (7 in this case)\\
\hline
2 & 63 & Checksum for the previous two bytes\\
\hline
3 & 20 & Responder Address\\
\hline
4 & b8 & Responder LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2eh in this case).\\
\hline
5 & 34 & The command, a Send Message response in this case.\\
\hline
6 & 00 & Completion code\\
\hline
7 & f4 & Checksum for the whole message.\\
\hline
\end{longtable}

This is the same as the previous example.  However, the second
response would be:

\begin{longtable}{|l|l|p{0.7\textwidth}|}
\hline
\bfseries{Byte} & \bfseries{Value} & \bfseries{Description}\\
\hline
0 & 81 & Requester Address\\
\hline
1 & 1c & \acs{LAN} Requester \acs{LUN} in bits 0-1 (0 in this case),
         Send Message response \acs{NetFN} in bits 2-7 (7 in this case)\\
\hline
2 & 63 & Checksum for the previous two bytes\\
\hline
3 & 20 & Responder Address\\
\hline
4 & b8 & Responder LUN in bits 0-1 (0 in this case), Sequence number
        in bits 2-7 (2eh in this case).\\
\hline
5 & 01 & Command, a Get Device ID response\\
\hline
6 & 00 & IPMB completion code\\
\hline
7 & 00 & message data\\
\hline
8 & 00 & message data\\
\hline
9 & 01 & message data\\
\hline
10 & 05 & message data\\
\hline
11 & 51 & message data\\
\hline
12 & 29 & message data\\
\hline
13 & 57 & message data\\
\hline
14 & 01 & message data\\
\hline
15 & 00 & message data\\
\hline
16 & 00 & message data\\
\hline
17 & 09 & message data\\
\hline
18 & 01 & message data\\
\hline
19 & 01 & message data\\
\hline
20 & 00 & message data\\
\hline
21 & 00 & message data\\
\hline
22 & 44 & Checksum for the whole message\\
\hline
\end{longtable}

Notice that the header information, except for the command, is from
the LAN header, not from the IPMB header.

\subsection{System Interface to LAN}

TBD - write this, use the formats described in the send/receive
message commands.

\section{\acs{IPMB}}
\label{sec-ipmb}

\ac{IPMB} provides the main channel for transferring messages around
an \acs{IPMI} system.  It is a message bus that works somewhat like
Ethernet, it is a CSMA (carrier-sense multiple access) system.  It
does check to see if another sender is transmitting before sending,
and will wait for that sender to complete before starting to transmit.
However, it does not have collision detection; so if two \ac{MC}s
attempt to transmit at the same time, both messages will be lost.
Because of this, \ac{IPMB} does not scale very well; careful use needs
to be made of the bandwith on the bus.

The format of an \ac{IPMB} message of $n$ bytes is:

\begin{showmsg}
\hline
\msgitem{0}{Destination \acs{IPMB} address}
\msgitem{1}{Bits 0-1 - Destination \acs{LUN}\\
            Bits 2-7 - \acs{NetFN}}
\msgitem{2}{Checksum for bytes 0-1}
\msgitem{3}{Source \acs{IPMB} address}
\msgitem{4}{Bits 0-1 - Source \acs{LUN}\\
            Bits 2-7 - Sequence Number}
\msgitem{5}{Command}
\msgitem{6 .. n-2}{Message Contents}
\msgitem{n-1}{Checksum for the whole message}
\end{showmsg}

Note that for commands, the ``destination \acs{LUN}'' will be called
the ``responder \acs{LUN}'' and the ``source \acs{LUN}'' will be
called the ``requester \acs{LUN}.''  For responses, the ``destination
\acs{LUN}'' will be called the ``requester \acs{LUN}'' and the
``source \acs{LUN}'' will be called the ``responder \acs{LUN}.''
\ac{IPMB} is a peer-to-peer protocol, but there is a strong
master-slave sentiment in \ac{IPMI}.

Unfortunately, \acs{IPMI} does not have any type of routing handling or
transparency of messages.  To send a message out on the \ac{IPMB}, you
encapsulate the entire \ac{IPMB} message in a \textit{Send Message}
command and send it over the proper channel.

Since \ac{IPMB} can lose messages, the OpenIPMI device driver
implements a resend mechanism on commands sent over \ac{IPMB}; if a
response is not seen withing a given period of time, the command will
be resent.  This will be done a few times before an error is returned.

\subsection{IPMB Broadcast}
One special type of message is the broadcast \ac{IPMB} message.  This
message is exactly like a normal \ac{IPMB} message, but it has a 0 byte
prepended to the message.  This can only be a \textit{Get Device Id}
command.  It is used to discover management controllers in the system.
Broadcast is a really bad name, because it will not actually
broadcast, it will go to the \ac{IPMB} address in the second byte of the
message.  This is used for discovery because it will not have any
effect on \acs{I$^2$C} devices on the bus, but \acs{IPMI} devices will
do a normal response.

Many IPMI systems do not correctly implement broadcast; it seems to be
an oft ignored part of the spec.

\subsection{OpenIPMI and \acs{IPMB}}
The OpenIPMI driver and library handle the details of IPMB for the
user.  To send a message over IPMB, the user creates an OpenIPMI
\ac{IPMB} address as described in section \ref{openipmi-addressing} and
sends a normal OpenIPMI message.  The library and driver take care of
selecting the sequence numbers, formatting the messages, tracking and
decoding the response, and resending messages.

\section{ICMB}
\label{sec-icmb}

TBD - write this.

\section{SMBus}
\label{sec-smbus}

TBD - write this.

\section{Session Support}
\label{sec-session-support}

TBD - write this.

\section{\acs{LAN}}
\label{interface-lan}
The \ac{IPMI} \acs{LAN} interface allows users to connect to \ac{IPMI}
systems over an Ethernet interface.  This can generally even be done
when the system is turned off, although it probably has to be plugged
in.  This lets you do things like power control the system and reset
the main processor even when the operating system is not operational
on the system.

The \ac{IPMI} \acs{LAN} protocol runs over a subset of the \ac{RMCP}
protocol.  \ac{RMCP} is defined in RMCP\cite{rmcp}.

The \ac{IPMI} \acs{LAN} is not well defined in the spec.  Many valid
interpretations of the spec were possible.  Some errata has been
issued, but that really only added one more possible interpretation.
OpenIPMI implements the three different common interpretations of the
spec.  They can interwork seamlessly, so it is not a problem.

TBD - describe the protocol in detail.

\subsection{\acs{LAN} Configuration}
\label{lan-config}
Most systems have tools to configure the \ac{IPMI} \acs{LAN}
interface.  IPMI has a built-in way to do this, too, through a set of
tables.

\subsubsection{\acs{LAN} Configuration Commands}
To set up the \acs{LAN} configuration table, the command shown in table
\ref{set-lan-conf-cmd} is used to set parameters.

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{Bits 0-3 - Channel Number\\
            Bits 4-7 - reserved}
\msgitem{1}{Parameter Selector.  This selects the entry in the table that you
        want to set.}
\msgitem{2-n}{The data for the parameter.  You must look up the entry in
        table \ref{lan-conf-parms} for the exact contents, it depends on
        which entry you are setting.}
\msgtag{Response}
\msgitem{0}{Completion code.  Standard completion codes, plus:\\
        80h - Parameter not supported\\
        81h - Attempt to set the ``set in progress' value (parm 0) when
                the parameter is not in the free (set complete) state.\\
        82h - Attempt to write a read-only parameter.}
\msgcaption{\label{set-lan-conf-cmd}Set \acs{LAN} Configuration Parameters
  Command, NetFN Transport (0Ch), Cmd 01h}
\end{showmsg}

Table \ref{get-lan-conf-cmd} shows the command used to get \acs{LAN}
parameters.

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{Bits 0-3 - Channel Number\\
            Bits 4-6 - reserved\\
            Bit 7 - If 1, only get parameter revision}
\msgitem{1}{Parameter Selector.  This selects the entry in the table that you
        want to get.}
\msgitem{2}{Set Selector.  Some parameters are in an array, this tells which
        array element to set.  Set to zero if the parameter does not have a
        set selector.}
\msgitem{3}{Block Selector.  Some parameters have two levels of arrays
        (an array inside of the array).  The Set Selector is the first
        level array specifier, this is the second level.  No standard
        \acs{LAN} parameters use this, although OEM ones might.  Set to zero
        if the parameter does not have a block selector.}
\msgtag{Response}
\msgitem{0}{Completion code.  Standard codes, plus:\\
        80h - parameter not supported}
\msgitem{1}{Parameter revision.  Format is:\\
        Bits 0-3 - Oldest revision parameter is backward compatible with\\
        Bits 4-7 - Current parameter revision}
\msgitem{2-n}{Parameter data.  This will not be present if bit 7 of byte 0
        of the response is set to 1.  The contents of this depends on the
        particular parameter being fetched, see table \ref{lan-conf-parms}
        for the parameters.}
\msgcaption{\label{get-lan-conf-cmd}Get \acs{LAN} Configuration Parameters
  Command, NetFN Transport (0Ch), Cmd 02h}
\end{showmsg}

\subsubsection{The \acs{LAN} Configuration Table}
\label{sec-lan-conf-parms}
The \acs{LAN} Configuration table has an unusual locking mechanism
(although it is usual for \acs{IPMI}).  Parameter zero is a lock.  If
you set the value to one, it will only succeed if the value is zero.
Thus, to lock the table, you set the value to one until it succeeds.
You then set it to zero when you are done.  This locking mechanism
leads to problem if the locker dies while it holds the lock, so you
probably need some way to override the lock if this happens.  The lock
does not actually keep anyone from changing the data, it is simply a
common mechanism to mutual exclusion.  Note also that the lock has a
``commit'' mechanism, writing two to the lock will commit the contents
if the system supports it.  If the system supports rollback, setting
the value to zero will rollback and not commit the changes you made.
So for correctness, you should write a two when you are complete, and
if that fails then write a zero.

All network parameters such as \acs{IP} address, port, and \acs{MAC}
address are in network order, also called big endian or most
significant byte first.  Unless marked ``volatile'', all of these
will survive removal of power.

\begin{longtable}{|p{0.2\textwidth}|l|p{0.65\textwidth}|}
\caption{\acs{LAN} Configuration Parameters\label{lan-conf-parms}}
\\ \hline
\bfseries{Parameter} & \bfseries{\#} & \bfseries{Description}\\
\endhead
\hline
Set In Progress (volatile) & 0 &
        Used to indicate that the parameters are being updated.
        Bits 2-7 are reserved.  Bits 0-1 have the following values:
        \begin{tightdefs}
        \item[00b] - set complete.  This is the state the system comes up in.
                This means that any user is finished updating the
                parameters.  If rollback is implemented, setting this
                value will cause any changes made since last setting
                this value to ``set in progress'' to be undone.
        \item[01b] - set in progress.  A user will set this value to inform
                others that it is updating these parameters.  This value
                can only be set if the current value is ``set complete''.
        \item[10b] - commit write (optional).  This will commit any changes
                that
                are pending and go to ``set complete'' state.  Some systems
                may not support this, if setting this returns an error you
                should set this value to ``set complete'' by hand.
        \end{tightdefs}\\
\hline
Authentication Type Support (Read only) & 1 &
        A read only field showing which authentication types are supported.
        The format for this is defined in table \ref{auth-bitmask}.\\
\hline
Authentication Type Enables & 2 &
        A 5 byte field that holds the allowed authentication type for each
        privilege level.  The bytes are:
        \begin{tightdefs}
        \item[byte 0] - callback
        \item[byte 1] - user
        \item[byte 2] - operator
        \item[byte 3] - admin
        \item[byte 4] - oem
        \end{tightdefs}
        The format for each byte is defined in table \ref{auth-bitmask}.\\
\hline
\acs{IP} Address & 3 &
        A 4 byte field holding the \acs{IP} address, in network order.  This
        is the local \acs{IP} address used for this particular channel.  You
        only need to set this if parameter 4 is set to ``static address''.\\
\hline
\acs{IP} Address Source & 4 &
        One byte field telling the BMC where to get its IP address. Bits 4-7
        are reserved.  Values for bits 0-3 are:
        \begin{tightdefs}
        \item[0] - unspecified (I don't know what that means)
        \item[1] - static address, configured from parameter 3
        \item[2] - get address from DHCP
        \item[3] - get address from BIOS or system software
        \item[4] - get address by some other method
        \end{tightdefs}
        As you probably can tell, static address and DHCP are really the
        only useful values.\\
\hline
\acs{MAC} Address & 5 &
        A 6 byte field.  This is the Ethernet \ac{MAC} address to use as the
        source when transmitting packets, in network order.  You must set
        this value properly.\\
\hline
Subnet Mask & 6 &
        A 4 byte field holding the subnet mask for the \acs{IP} connection,
        in network order.\\
\hline
IPv4 Header Parms & 7 &
        A 3 byte field controlling some parameters in the \acs{IP} header.
        The bytes are:
        \begin{tightdefs}
          \item[byte 0] - time to live (default 40h) - The number of network
            hops allowed for \acs{IP} packets sent by the \acs{BMC}.
          \item[byte 1]
            \begin{tightdefs}
              \item[bits 0-4] - reserved
              \item[bits 5-7] - flags.  Sets the of the flags field in the
                IP header.  The default value is 010b, or do not fragment.
            \end{tightdefs}
          \item[byte 2]  This is the setting of the 8-bit type of service
            field in the \acs{IP} header. Only one of bits 1-4 should be
            set.
            \begin{tightdefs}
            \item[bit 0] - unused, set to zero.
            \item[bit 1] - minimize monetary cost
            \item[bit 2] - maximize reliability
            \item[bit 3] - maximize throughput
            \item[bit 4] - minimize delay
            \item[bits 5-7] - Precedence, which is unused by IP systems now.
            \end{tightdefs}
            The default value is 00010000b.
        \end{tightdefs}\\
\hline
Primary RMCP port number (optional) & 8 &
        A 2 byte field holding the \acs{UDP} port number to use for primary
        \acs{RMCP}.  Default value is 623.\\
\hline
Secondary RMCP port number (optional) & 9 &
        A 2 byte field holding the \acs{UDP} port number to use for the
        secure aux bus \acs{RMCP} port.  IPMI does not use this, but it is
        here for completeness.  Default value is 664.\\
\hline
\acs{BMC}-generated \acs{ARP} control (optional) & 10 &
        A 1 byte field controlling how the BMC generates \acs{ARP}s.  If a
        user attempts to set
        an unsupported field, the \acs{BMC} will return an error.  The
        bits are:
        \begin{tightdefs}
        \item[bit 0] - set to 1 to enable \acs{BMC} generated gratuitous
          \acs{ARP}s.
        \item[bit 1] - set to 1 to enable \acs{BMC} generated \acs{ARP}
          responses.
        \item[bits 2-7] - reserved
        \end{tightdefs}\\
\hline
Gratuitous \acs{ARP} interval (optional) & 11 &
        A one byte field holding the interval between gratuitous \acs{ARP}s.
        The interval is specified in 500 millisecond increments, with a 10\%
        accuracy.  If this is not implemented, the interval will be 2
        seconds.\\
\hline
Default gateway address & 12 &
        A 4 byte field holding the IP address of the default gateway, in
        network order.  The BMC will send packets to this address if the
        destination is not on its subnet, if this gateway is chosen as
        the gateway to use.\\
\hline
Default gateway \acs{MAC} address & 13 &
        A 6 byte filed holding the Ethernet MAC address to use in
        the destination when
        sending packets to the default gateway.\\
\hline
Backup gateway address & 14 &
        A 4 byte field holding the IP address of the backup gateway, in
        network order.  The BMC will send packets to this address if the
        destination is not on its subnet, if this gateway is chosen as
        the gateway to use.\\
\hline
Backup gateway \acs{MAC} address & 15 &
        A 6 byte filed holding the Ethernet MAC address to use in the
        destiination when
        sending packets to the backup gateway.\\
\hline
Community String & 16 &
        An 18 byte field holding the \acs{SNMP} community string to
        use in traps send by the BMC.  The default is ``public''.\\
\hline
Number of Destinations (read only) & 17 &
        The number of entries in the destination type and destination address
        tables in parameters 18 and 19.\\
\hline
Destination type & 18 &
        This is an array of destination types, each 4 bytes long.  The first
        byte in bits 0-3 is the index into the array, you put the index
        here when you set the value, and that index gets set.  This index
        comes from the alert policy entry destination field
        defined in table \ref{alert-policy-table-entry}.  Destination 0 is
        special and used by the Alert Immediate command as described in
        section \ref{sec-alert-immediate}.  The fields are:
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
            \item[bits 0-3] - The index into the array
            \item[bits 4-7] - reserved
          \end{tightdefs}
        \item[byte 1] The destination type.  The bits are:
          \begin{tightdefs}
          \item[bits 0-2] - Destination type, values are:
            \begin{tightdefs}
            \item[000b] - PET Trap
            \item[001b-101b] - reserved
            \item[110b] - OEM 1
            \item[111b] - OEM 1
            \end{tightdefs}
          \item[bits 3-6] - reserved
          \item[bit 7] - If zero, the alert does not need to be acknowledged
            to be considered successful.  If 1, the alert needs to be
            acknowledged with a \acs{PET} Acknowledge Command as defined
            in table \ref{pet-ack-cmd}.
          \end{tightdefs}
        \item[byte 2] \acs{PET} Retry Time.  This specified the amount
          of time between resends when waiting for an acknowledge of
          the sent trap.
        \item[byte 3] Max \acs{PET} Retries.
          \begin{tightdefs}
          \item[bits 0-2] - The maximum number of retries of a trap before
            giving up.
          \item[bits 3-7] - reserved
          \end{tightdefs}
        \end{tightdefs}\\
\hline
Destination address & 19 &
        This is an array of destination address, each 13 bytes long.  The
        first byte in bits 0-3 is the index into the array, you put the index
        here when you set the value, and that index gets set.  This index
        comes from the alert policy entry destination field
        defined in table \ref{alert-policy-table-entry}. Destination 0 is
        special and used by the Alert Immediate command as described in
        section \ref{sec-alert-immediate}.  The fields are:
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
            \item[bits 0-3] - The index into the array
            \item[bits 4-7] - reserved
          \end{tightdefs}
        \item[byte 1] The address format:
          \begin{tightdefs}
            \item[bits 0-3] - The address type, 0h is the only valid
              value, specifying IP.
            \item[bits 4-7] - reserved
          \end{tightdefs}
        \item[byte 2] Gateway selector
          \begin{tightdefs}
          \item[bit 0]
            \begin{tightdefs}
            \item[0] - use the default gateway
            \item[0] - use the backup gateway
            \item[bits 1-7] - reserved
            \end{tightdefs}
          \end{tightdefs}
        \item[bytes 3-6] The \acs{IP} address to send the alert to when using
          this destination, in network order.
        \item[bytes 7-12] The Ethernet \acs{MAC} address to send the alert
          to when using this destination, in network order.
        \end{tightdefs}\\
\hline
OEM & 192+ &
        Parameters 192 to 255 are OEM parameters.  The rest of the
        parameters are reserved.\\
\hline
\end{longtable}

\subsection{ARP control}

TBD - write this, include command, talk about config table entries.

\subsection{\acs{LAN} Messaging}

TBD - write this, describe the formatting of LAN messages

\subsection{OpenIPMI \acs{LAN} Configuration}
OpenIPMI has some support for handling the \acs{LAN} configuration.
This is defined in the \verb=ipmi_lanparm.h= include file; it has all
the details on how to use this.

To configure the \acs{LAN} parameters for a BMC, you must first
allocate a lanparm structure with:
\begin{verbatim}
int ipmi_lanparm_alloc(ipmi_mc_t      *mc,
                       unsigned int   channel,
                       ipmi_lanparm_t **new_lanparm);
\end{verbatim}

The channel is the \acs{IPMI} channel number of the \acs{LAN} port you are
configuring.  Generally, if a server has more than one port, it will
have a separate channel for each port, you will have to find the
channel numbers from the manufacturer, although channels 6 and 7 are
commonly used as the \acs{LAN} channels.

Once you have a \verb=lanparm= structure, you can get and set
individual parms assuming you follow all the rules associated with the
configuration table.  However, there is a much easier way that
OpenIPMI provides.  After you have allocated a \verb=lanparm=
structure these, the function:
\begin{verbatim}
typedef void (*ipmi_lan_get_config_cb)(ipmi_lanparm_t    *lanparm,
                                       int               err,
                                       ipmi_lan_config_t *config,
                                       void              *cb_data);
int ipmi_lan_get_config(ipmi_lanparm_t         *lanparm,
                        ipmi_lan_get_config_cb done,
                        void                   *cb_data);
\end{verbatim}
will fetch the full current configuration.  Note that when you call
this, you will be holding a lock if it succeeds.  You must release the
lock when you are done, or no one else will be able to change the
configuration unless they forcefully remove your lock.

At this point, you can change the value in the \verb=config=
structure.  But those changes are only local.  When you have complete
making the changes, you must commit them back to the BMC.  To do this,
call:
\begin{verbatim}
int ipmi_lan_set_config(ipmi_lanparm_t       *lanparm,
                        ipmi_lan_config_t    *config,
                        ipmi_lanparm_done_cb done,
                        void                 *cb_data);
\end{verbatim}
After this point in time, the \verb=config= cannot be used for future
set operation, because it has been committed.  You must re-read it to
modify parameters again.

If you do not wish to modify the configuration, you still need to
clear the lock.  Do that with:
\begin{verbatim}
int ipmi_lan_clear_lock(ipmi_lanparm_t       *lanparm,
                        ipmi_lan_config_t    *config,
                        ipmi_lanparm_done_cb done,
                        void                 *cb_data);
\end{verbatim}

Once you are done with the \verb=config= structure, you must free it with:
\begin{verbatim}
void ipmi_lan_free_config(ipmi_lan_config_t *config);
\end{verbatim}

When you are done with a \verb=lanparm= structure, you must free it with:
\begin{verbatim}
int ipmi_lanparm_destroy(ipmi_lanparm_t       *lanparm,
                         ipmi_lanparm_done_cb handler,
                         void                 *cb_data);
\end{verbatim}
If the \verb=lanparm= structure currently has operations pending on
it, the destroy will be delayed until those operations are complete.
The handler will be called when the actual destroy takes place.

\subsection{The OpenIPMI \acs{LAN} Interface}
The \acs{LAN} interface is complicated, but OpenIPMI handles most of the
details for the user.  A single function sets up the interface.
Unfortunately, that function takes a huge number of parameters due to
the large number of things required to configure a \ac{IPMI} \acs{LAN}
connection.  The function is:

\begin{verbatim}
int ipmi_ip_setup_con(char         * const ip_addrs[],
                      char         * const ports[],
                      unsigned int num_ip_addrs,
                      unsigned int authtype,
                      unsigned int privilege,
                      void         *username,
                      unsigned int username_len,
                      void         *password,
                      unsigned int password_len,
                      os_handler_t *handlers,
                      void         *user_data,
                      ipmi_con_t   **new_con);
\end{verbatim}

The parameters are:

\begin{description}
\item[\texttt{ip\_addrs}] An array of \acs{IP} addresses.  Each \acs{IP}
address must be an address that connects to the exact same management
controller.
If you need connections to multiple management controllers, you must set
up two different connections and use multiple connections in the domain.
\item[\texttt{ports}] An array of \acs{UDP} ports for each IP address.  This is
defined as 623 in the \acs{IPMI} spec, but is here for flexibility.
\item[\texttt{num\_ip\_addrs}] The number of IP addresses and ports.
\item[\texttt{authtype}] The authentication type to use for the connection.
Table \ref{ipmi-authtypes} describes the different authentication types.
\item[\texttt{privilege}] The privilege level to connect at.  Table
\ref{ipmi-priv-levels} describes the different privilege levels.
\item[\texttt{username}] The username to connect as.  See section
\ref{user-mgmt} for details on users.
\item[\texttt{username\_len}] The length of the username.  Required because
usernames can be binary and contain zeros.
\item[\texttt{password}] The password for the user.  See section \ref{user-mgmt}
for details on users.
\item[\texttt{password\_len}] The length of the password.  Required because
usernames can be binary and contain zeros.
\item[\texttt{handlers}] The OS handler to use for this domain.  See section
\ref{openipmi-os-handlers} for more details.
\item[\texttt{user\_data}] This is a field that will be put into the connection
data structure of the same name.  This is for user use and OpenIPMI will
not use it.
\item[\texttt{new\_con}] The new connection is returned in this field.
\end{description}

Once you have a connection, it works like a normal connection as 
defined in section \ref{openipmi-generic-interface}.

\section{Serial}

TBD - OpenIPMI does not support serial interfaces, but this needs to be
written someday.

\subsection{Serial Configuration}
\label{serial-config}

\subsection{Direct Serial}

\subsection{Terminal Mode}
\label{sec-terminal-mode}

\subsection{Serial over \acs{PPP}}

\begin{longtable}{|p{0.2\textwidth}|l|p{0.65\textwidth}|}
\caption{Serial Configuration Parameters\label{serial-conf-parms}}
\\ \hline
\bfseries{Parameter} & \bfseries{\#} & \bfseries{Description}\\
\endhead
\hline
\end{longtable}

\section{User Management}
\label{user-mgmt}

IPMI uses users for access control on IPMI systems with LAN or serial
interfaces.  The local system interface has no access controls, but
the more external interfaces require authentication to be able to use
the interface.  Users may be able to authenticate links and send and
receive IPMI messages.  

Users have a defined maximum privilege level.  They may not negotiate
a connection with a higher privilege level than that.  The privilege
levels are defined in table~\vref{ipmi-priv-levels} and they affect
what messages the system will accept from the user.  In addition to
that, the user may be restricted to only work in a callback session.

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_PRIVILEGE\_CALLBACK (1)} & The user is only allowed to request
that the IPMI system call back home.\\
\hline
\texttt{IPMI\_PRIVILEGE\_USER (2)} & A ``read-only'' user.  The user can look
at system state, but not change anything.  For instance, the user can
fetch \acs{SEL} entries, but not delete them.\\
\hline
\texttt{IPMI\_PRIVILEGE\_OPERATOR (3)} & This user can do everything but configuration
commands.  For instance, they can clear the SEL and configure sensors, but
they cannot add users or configure \acs{LAN} parameters.\\
\hline
\texttt{IPMI\_PRIVILEGE\_ADMIN (4)} & This user can do pretty much anything on an
IPMI system.\\
\hline
\texttt{IPMI\_PRIVILEGE\_OEM (5)} & Undefined by the spec, it's whatever the \acs{OEM}
wants.\\
\hline
\end{tabularx}
\caption{\label{ipmi-priv-levels}Privilege levels in IPMI}
\end{table}

The systems have two ways of identifying users: by number and by name.
A BMC will have a set of users (up to 63, but the BMC may have a lower
limit) indexed by number.  User 0 is reserved.  User 1 is a special
user that is defined to not have a name.  This provides a simple but
insecure way to access the system, especially if user 1 does not have
a password.  All the other user numbers may be assigned names.  The
name is used for system authentication.

Users may have passwords assigned to them.  If no password is
assigned, then an empty password is able to authenticate the user.
The passwords are used to authenticate the link and the messages.

The user number, name, password and enable are global for all channels
in an BMC.  The link/message authentication enables are done
per-channel.

\subsection{User management in OpenIPMI}

Enabling a user is a complicated process.  The user must have a name
and password assigned.  It must be set with the proper authentication
enables.  Then it must be enabled with a separate enable command.

Fortunately, OpenIPMI handles a lot of this process for you.  The
functions are found in the \texttt{ipmi\_user.h} include file.  You
may get a list of users (or a specific user in a one-user list) with
the command:
\begin{verbatim}
typedef void (*ipmi_user_list_cb)(ipmi_mc_t        *mc,
                                  int              err,
                                  ipmi_user_list_t *list,
                                  void             *cb_data);
#define IPMI_MC_ALL_USERS       0
int ipmi_mc_get_users(ipmi_mc_t         *mc,
                      unsigned int      channel,
                      unsigned int      user,
                      ipmi_user_list_cb handler,
                      void              *cb_data);
\end{verbatim}
Using \verb=IPMI_MC_ALL_USERS= will fetch all users, otherwise the
user specified will be used.  The channel-specific information will be
fetched for only the given channel.

Once you have the list, you can fetch information from the list:
\begin{verbatim}
int ipmi_user_list_get_channel(ipmi_user_list_t *list, unsigned int *channel);
int ipmi_user_list_get_max_user(ipmi_user_list_t *list, unsigned int *max);
int ipmi_user_list_get_enabled_users(ipmi_user_list_t *list, unsigned int *e);
int ipmi_user_list_get_fixed_users(ipmi_user_list_t *list, unsigned int *f);
\end{verbatim}

You can also fetch individual users from the user list.  Note that if
you fetch a user this way, you must free it with \verb=ipmi_user_free()=.
\begin{verbatim}
unsigned int ipmi_user_list_get_user_count(ipmi_user_list_t *users);
ipmi_user_t *ipmi_user_list_get_user(ipmi_user_list_t *list,
                                     unsigned int     idx);
\end{verbatim}

Once you fetch a user, you can get information from it.  You can also
set information for the user.  This only sets the local copy, it must
be written out into the real data to activate it on the BMC.
\begin{verbatim}
int ipmi_user_get_channel(ipmi_user_t *user, unsigned int *channel);

/*
 * Get/set the number for the user.
 */
int ipmi_user_get_num(ipmi_user_t *user, unsigned int *num);
int ipmi_user_set_num(ipmi_user_t *user, unsigned int num);

/*
 * Get/set the name for the user.  When getting the name, the pointer
 * to "len" should point to a value of the length of "name".  "len"
 * will be updated to the actual number of characters copied.  The
 * password set is for 16-byte passwords, the password2 is for 20-byte
 * passwords.
 */
int ipmi_user_get_name_len(ipmi_user_t *user, unsigned int *len);
int ipmi_user_get_name(ipmi_user_t *user, char *name, unsigned int *len);
int ipmi_user_set_name(ipmi_user_t *user, char *name, unsigned int len);
int ipmi_user_set_password(ipmi_user_t *user, char *pw, unsigned int len);
int ipmi_user_set_password2(ipmi_user_t *user, char *pw, unsigned int len);

/*
 * Various bits of information about a user, this is per-channel.
 */
int ipmi_user_get_link_auth_enabled(ipmi_user_t *user, unsigned int *val);
int ipmi_user_set_link_auth_enabled(ipmi_user_t *user, unsigned int val);
int ipmi_user_get_msg_auth_enabled(ipmi_user_t *user, unsigned int *val);
int ipmi_user_set_msg_auth_enabled(ipmi_user_t *user, unsigned int val);
int ipmi_user_get_access_cb_only(ipmi_user_t *user, unsigned int *val);
int ipmi_user_set_access_cb_only(ipmi_user_t *user, unsigned int val);
int ipmi_user_get_privilege_limit(ipmi_user_t *user, unsigned int *val);
int ipmi_user_set_privilege_limit(ipmi_user_t *user, unsigned int val);
int ipmi_user_get_session_limit(ipmi_user_t *user, unsigned int *val);
int ipmi_user_set_session_limit(ipmi_user_t *user, unsigned int val);

/*
 * The enable for the user.  Note that the enable value cannot be
 * fetched and will return an error unless set.
 */
int ipmi_user_get_enable(ipmi_user_t *user, unsigned int *val);
int ipmi_user_set_enable(ipmi_user_t *user, unsigned int val);
\end{verbatim}

To actually set the user information on the BMC, the following command
can be used:
\begin{verbatim}
int ipmi_mc_set_user(ipmi_mc_t       *mc,
                     unsigned int    channel,
                     unsigned int    num,
                     ipmi_user_t     *user,
                     ipmi_mc_done_cb handler,
                     void            *cb_data);
\end{verbatim}

Note that OpenIPMI keeps track of what has changed in the user and
will only write out the changed information.  If you wish to rewrite
all information in the user (like if you want to write the same
information to a new user number) you can call
\verb=ipmi_user_set_all()= with the user to set the changed bits for
all items.  Then you can write the user out.

\subsection{User management commands}

Table~\vref{set-user-access-cmd} shows the command used to set the
enables for the user (this is not the same as the user enable).  These
are all per-channel.
\begin{showmsg}
\msgtag{Request}
\msgitem{0}{Sets various controls for the user on the channel:
        \begin{tightdefs}
        \item[bits 0-3] - channel number
        \item[bit 4] - Enable IPMI messaging for the user.  If this is
          not set, the user may not send IPMI messages.
        \item[bit 5] - Enable link authentication for the user.  If
          this is not set, the user may not authenticate a link.
        \item[bit 6] - User restricted to callback only.  If this is
          set, the user is restricted to callback authentication in
          non-callback situations.  In a callback situation, the
          privilege level is determined by the normal setting.
        \item[bit 7] - If this is 1, modify the fields in this byte.
          If this is 0, the fields in this byte are ignored.
        \end{tightdefs}}
\msgitem{1}{User ID:
        \begin{tightdefs}
        \item[bits 0-5] - User number
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{2}{User limits
        \begin{tightdefs}
        \item[bits 0-3] - The privilege level, as defined in
          table~\vref{ipmi-priv-levels}.  Putting a value of Fh in this
          field will disable access to this channel for the user.
        \item[bits 4-7] - reserved.
        \end{tightdefs}}
\msgitem{(3)}{User session limit - optional byte
        \begin{tightdefs}
        \item[bits 0-3] - The user session limit.  If set to 0, then
          the limit is the channel's session limit.  There does not
          appear to be any way to read this value, so it is a ``write
          only'' parameter.
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgcaption{\label{set-user-access-cmd}Set User Access Command,
  NetFN S/E (06h), Cmd 43h}
\end{showmsg}

To fetch the channel information for a user, use the command shown in
table~\vref{get-user-access-cmd}.
\begin{showmsg}
\msgtag{Request}
\msgitem{0}{%
        \begin{tightdefs}
        \item[bits 0-3] - channel number
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgitem{1}{%
        \begin{tightdefs}
        \item[bits 0-5] - User number
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgitem{1}{%
        \begin{tightdefs}
        \item[bits 0-5] - Maximum number of user ids available.  If
          this is 1, then only user 1 is supported.
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{2}{%
        \begin{tightdefs}
        \item[bits 0-5] - Number of enabled user ids.
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{3}{%
        \begin{tightdefs}
        \item[bits 0-5] - Count of user ids with fixed names (that cannot
          be changed with the set user name command).  This includes user
          1 and must be sequential starting with user 2.
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{1}{Various controls for the user on the channel:
        \begin{tightdefs}
        \item[bits 0-3] - User privilege limit.
        \item[bit 4] - IPMI messaging enabled for the user.  If this is
          not set, the user may not send IPMI messages.
        \item[bit 5] - Link authentication enabled for the user.  If
          this is not set, the user may not authenticate a link.
        \item[bits 6] - User restricted to callback only.  If this is
          set, the user is restricted to callback authentication in
          non-callback situations.  In a callback situation, the
          privilege level is determined by the normal setting.
        \item[bits 7] - If reserved.
        \end{tightdefs}}
\msgcaption{\label{get-user-access-cmd}Get User Access Command,
  NetFN S/E (06h), Cmd 44h}
\end{showmsg}

The user name is set using the command defined in
table~\vref{set-user-name-cmd} and the name can be fetched with the
command defined in table~\vref{get-user-name-cmd}.
\begin{showmsg}
\msgtag{Request}
\msgitem{0}{User ID:
        \begin{tightdefs}
        \item[bits 0-5] - User number
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{1-16}{User name - These bytes are ASCII-encoded bytes that
        define the name of the user.}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgcaption{\label{set-user-name-cmd}Set User Name Command,
  NetFN S/E (06h), Cmd 45h}
\end{showmsg}
\begin{showmsg}
\msgtag{Request}
\msgitem{0}{User ID:
        \begin{tightdefs}
        \item[bits 0-5] - User number
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgitem{1-16}{User name - These bytes are ASCII-encoded bytes that
        define the name of the user.}
\msgcaption{\label{get-user-name-cmd}Get User Name Command,
  NetFN S/E (06h), Cmd 46h}
\end{showmsg}

The Set User Password command defined in
table~\vref{set-user-password-cmd} sets the password and also enables
and disables the user with a different mode of the command.
Obviously, there is no way to get the password, but unfortunately,
there is no way to get the enable value, either.  Passwords for the
IPMI 1.5 authentication are 16-bytes long.  Passwords for RMCP+ may be
either 16 or 20 bytes long.  You may set a 20-byte password for a
user, but then that user may not be used for IPMI 1.5 authentication,
only for RMCP+ authentication.
\begin{showmsg}
\msgtag{Request}
\msgitem{0}{User ID:
        \begin{tightdefs}
        \item[bits 0-5] - User number
        \item[bit 6] - If this is 0, then use 16-byte passwords.  If this
          is 1, then use 20-byte passwords.
        \item[bit 7] - reserved
        \end{tightdefs}}
\msgitem{1}{%
        \begin{tightdefs}
        \item[bits 0-1] - Operation:
          \begin{tightdefs}
          \item[00b] - disable the user.
          \item[01b] - enable the user.
          \item[10b] - set the password to the value in this command.
          \item[11b] - test the password in this command and return an
            error code if it is incorrect.
          \end{tightdefs}
        \item[bits 2-7] - reserved
        \end{tightdefs}}
\msgitem{2-17/20}{Password - These bytes are ASCII-encoded bytes that
        define the name of the user.  This is only present for the
        set and test password operations.}
\msgtag{Response}
\msgitem{0}{Completion Code.  Special values are:
        \begin{tightdefs}
        \item[80h] - Password test failed
        \item[81h] - Password was the wrong length
        \end{tightdefs}}
\msgcaption{\label{set-user-password-cmd}Set User Password Command,
  NetFN S/E (06h), Cmd 45h}
\end{showmsg}


\section{Channel Configuration}

The channels on an IPMI system are controlled with a channel setting
command.  In addition, channel information is available.

Channels are numbered 0-7 and Fh.  Channel 0 is generally IPMB.
Channels 1-7 are used for other IPMB channels, LAN interfaces, serial
interfaces, and whatnot.  Channel Fh is used for the system interface.

If you specify channel Eh in a command, it will use the channel the
command came from; any returned channel number will be the actual
channel number of the channel.  This can be used to discover the
channel number of the current channel.

The channel information contains the channel type, protocol, and other
detailed information about the channel.

The channel access allows control of how the channel works.  It allows
alerting to be enabled, it controls whether user and per-message
authentication are required for the channel, it controls when the
channel is available and the privilege limit of the channel.  Channel
access has two separate areas to store the information, a volatile
area and a non-volatile area.  The volatile area is the area that is
used in normal operation, setting that modified behaviour immediately.
This area is lost if power is lost to the system.  The system loads
the volatile area from the non-volatile area at startup.  The areas
are set separately.

In addition to this, LAN interfaces have specific configuration
information as defined in section~\vref{lan-config} and serial
interfaces have their own information as defined in
section~\vref{serial-config}.

\subsection{Channel handling in OpenIPMI}

\subsubsection{Channel Information}

OpenIPMI allows the user to get channel information with the following
command:
\begin{verbatim}
typedef struct ipmi_channel_info_s ipmi_channel_info_t;
typedef void (*ipmi_channel_info_cb)(ipmi_mc_t           *mc,
                                     int                 err,
                                     ipmi_channel_info_t *info,
                                     void                *cb_data);
int ipmi_mc_channel_get_info(ipmi_mc_t            *mc,
                             unsigned int         channel,
                             ipmi_channel_info_cb handler,
                             void                 *cb_data);
\end{verbatim}
The callback gets a channel information structure which can be
accessed with the following functions:
\begin{verbatim}
int ipmi_channel_info_get_channel(ipmi_channel_info_t *info,
                                  unsigned int        *channel);
int ipmi_channel_info_get_medium(ipmi_channel_info_t *info,
                                 unsigned int        *medium);
int ipmi_channel_info_get_protocol_type(ipmi_channel_info_t *info,
                                        unsigned int        *prot_type);

int ipmi_channel_info_get_session_support(ipmi_channel_info_t *info,
                                          unsigned int        *sup);
/* Data is 3 bytes long */
int ipmi_channel_info_get_vendor_id(ipmi_channel_info_t *info,
                                    unsigned char       *data);
/* Data is 2 bytes long */
int ipmi_channel_info_get_aux_info(ipmi_channel_info_t *info,
                                   unsigned char       *data);
\end{verbatim}

Table~\vref{ipmi-channel-medium} describes the channel mediums defined
in OpenIPMI.  Table~\vref{ipmi-channel-protocol-types} describes the
channel protocol types.  Table~\vref{ipmi-channel-session-support}
describes the channel session support settings.

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_IPMB} (1) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_ICMB\_V10} (2) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_ICMB\_V09} (3) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_8023\_LAN} (4) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_RS232} (5) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_OTHER\_LAN} (6) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_PCI\_SMBUS} (7) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_SMBUS\_v1} (8) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_SMBUS\_v2} (9) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_USB\_v1} (10) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_USB\_v2} (11) & \\
\hline
\texttt{IPMI\_CHANNEL\_MEDIUM\_SYS\_INTF} (12) & \\
\hline
\end{tabularx}
\caption{\label{ipmi-channel-medium}Channel mediums in IPMI}
\end{table}

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_IPMB} (1) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_ICMB} (2) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_SMBus} (4) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_KCS} (5) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_SMIC} (6) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_BT\_v10} (7) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_BT\_v15} (8) & \\
\hline
\texttt{IPMI\_CHANNEL\_PROTOCOL\_TMODE} (9) & \\
\hline
\end{tabularx}
\caption{\label{ipmi-channel-protocol-types}Protocol types in IPMI}
\end{table}

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_CHANNEL\_SESSION\_LESS} (0) & \\
\hline
\texttt{IPMI\_CHANNEL\_SINGLE\_SESSION} (1) & \\
\hline
\texttt{IPMI\_CHANNEL\_MULTI\_SESSION} (2) & \\
\hline
\texttt{IPMI\_CHANNEL\_SESSION\_BASED} (3) & \\
\hline
\end{tabularx}
\caption{\label{ipmi-channel-session-support}Session support in IPMI}
\end{table}

\subsubsection{Channel Access}

Channels have access controls that define who may use them, privilege
limits, and other things of that nature.  These are available to be
fetched and set with OpenIPMI functions:
\begin{verbatim}
typedef struct ipmi_channel_access_s ipmi_channel_access_t;
typedef void (*ipmi_channel_access_cb)(ipmi_mc_t             *mc,
                                       int                   err,
                                       ipmi_channel_access_t *info,
                                       void                  *cb_data);
int ipmi_mc_channel_get_access(ipmi_mc_t              *mc,
                               unsigned int           channel,
                               enum ipmi_set_dest_e   dest,
                               ipmi_channel_access_cb handler,
                               void                   *cb_data);
int ipmi_mc_channel_set_access(ipmi_mc_t             *mc,
                               unsigned int           channel,
                               enum ipmi_set_dest_e  dest,
                               ipmi_channel_access_t *access,
                               ipmi_mc_done_cb       handler,
                               void                  *cb_data);
\end{verbatim}
Once you have a channel access type, you can get/set information in it
with the following functions:
\begin{verbatim}
int ipmi_channel_access_get_channel(ipmi_channel_access_t *access,
                                    unsigned int          *channel);
int ipmi_channel_access_get_alerting_enabled(ipmi_channel_access_t *access,
                                             unsigned int          *enab);
int ipmi_channel_access_set_alerting_enabled(ipmi_channel_access_t *access,
                                             unsigned int          enab);
int ipmi_channel_access_get_per_msg_auth(ipmi_channel_access_t *access,
                                         unsigned int          *msg_auth);
int ipmi_channel_access_set_per_msg_auth(ipmi_channel_access_t *access,
                                         unsigned int          msg_auth);
int ipmi_channel_access_get_user_auth(ipmi_channel_access_t *access,
                                      unsigned int          *user_auth);
int ipmi_channel_access_set_user_auth(ipmi_channel_access_t *access,
                                      unsigned int          user_auth);
int ipmi_channel_access_get_access_mode(ipmi_channel_access_t *access,
                                        unsigned int          *access_mode);
int ipmi_channel_access_set_access_mode(ipmi_channel_access_t *access,
                                        unsigned int          access_mode);
int ipmi_channel_access_get_priv_limit(ipmi_channel_access_t *access,
                                       unsigned int          *priv_limit);
int ipmi_channel_access_set_priv_limit(ipmi_channel_access_t *access,
                                       unsigned int          priv_limit);
\end{verbatim}
Table~\vref{ipmi-priv-levels} gives the privilege levels that the
privilege limits used in this command.
Table~\vref{ipmi-channel-access-mode} gives the modes the channel can
run in.  Not that not all channel types can support all modes.

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_CHANNEL\_ACCESS\_MODE\_DISABLED} (0) & Channel is never
        available.\\
\hline
\texttt{IPMI\_CHANNEL\_ACCESS\_MODE\_PRE\_BOOT} (1) & Channel is only available
        when the firmware is running, not when an OS is running.\\
\hline
\texttt{IPMI\_CHANNEL\_ACCESS\_MODE\_ALWAYS} (2) & Channel is always
        available.\\
\hline
\texttt{IPMI\_CHANNEL\_ACCESS\_MODE\_SHARED} (3) & Channel is always available
        for multiple simultaneous users.\\
\hline
\end{tabularx}
\caption{\label{ipmi-channel-access-mode}Channel access modes in IPMI}
\end{table}

Note that OpenIPMI tracks what has changed in the channel access and
only writes out the changed information.  If you wish to force all
data to be rewritten, you may use the
\verb=ipmi_channel_access_setall()= function to mark all data as
changed.

\subsection{Channel handling commands}

Table~\vref{get-channel-info-cmd} gives the command used to fetch the
channel information.

Channel access is fetched and written with the commands defined in
table~\vref{set-channel-access-cmd} and
table~\vref{get-channel-access-cmd}.
\begin{showmsg}
\msgtag{Request}
\msgitem{0}{%
        \begin{tightdefs}
        \item[bits 0-3] - Channel
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgitem{1}{%
        \begin{tightdefs}
        \item[bits 0-2] - Set the channel access mode per
          table~\vref{ipmi-channel-access-mode}
        \item[bit 3] - If 1, require authentication for user-level
          command.  Otherwise authentication is not required for
          user-level commands.  Note that this has no effect on
          operator or admin level commands.
        \item[bit 4] - If 1, require per-message authentication.  If
          0, no authentication is required per-message.  Note that if
          this is 0, a session must still be established, but
          subsequent messages after session establishment do not
          require authentication.
        \item[bit 5] - Enable or diable PEF alerting on the channel.
          Note that if this is 0 (disabled) alert immediate still
          works.
        \item[bits 6-7] - Operation:
          \begin{tightdefs}
          \item[00b] - Do not modify the values specified in the rest
            of this byte.
          \item[01b] - Set the non-volatile area
          \item[10b] - Set the volatile area.
          \item[11b] - reserved
          \end{tightdefs}
        \end{tightdefs}}
\msgitem{2}{%
        \begin{tightdefs}
        \item[bits 0-3] - Set the privilege limit for the channel per
          table~\vref{ipmi-priv-levels}.
        \item[bits 4-5] - reserved
        \item[bits 6-7] - Operation:
          \begin{tightdefs}
          \item[00b] - Do not modify the values specified in the rest
            of this byte.
          \item[01b] - Set the non-volatile area
          \item[10b] - Set the volatile area.
          \item[11b] - reserved
          \end{tightdefs}
        \end{tightdefs}}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgcaption{\label{set-channel-access-cmd}Set Channel Access Command,
  NetFN S/E (06h), Cmd 40h}
\end{showmsg}

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{%
        \begin{tightdefs}
        \item[bits 0-3] - Channel
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgitem{1}{%
        \begin{tightdefs}
        \item[bits 0-5] - reserved
          \begin{tightdefs}
          \item[00b] - reserved
          \item[01b] - Get the non-volatile area
          \item[10b] - Get the volatile area.
          \item[11b] - reserved
          \end{tightdefs}
        \end{tightdefs}}
\msgtag{Response}
\msgitem{0}{Completion Code.  The following special return codes are
        defined:
        \begin{tightdefs}
        \item[82h] - The channel is session-less thus does not support
          this command.
        \end{tightdefs}}
\msgitem{1}{%
        \begin{tightdefs}
        \item[bits 0-2] - The channel access mode per
          table~\vref{ipmi-channel-access-mode}
        \item[bit 3] - If 1, require authentication for user-level
          command.  Otherwise authentication is not required for
          user-level commands.  Note that this has no effect on
          operator or admin level commands.
        \item[bit 4] - If 1, require per-message authentication.  If
          0, no authentication is required per-message.  Note that if
          this is 0, a session must still be established, but
          subsequent messages after session establishment do not
          require authentication.
        \item[bit 5] - Enable or diable PEF alerting on the channel.
          Note that if this is 0 (disabled) alert immediate still
          works.
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{2}{%
        \begin{tightdefs}
        \item[bits 0-3] - The privilege limit for the channel per
          table~\vref{ipmi-priv-levels}.
        \item[bits 4-7] - reserved
        \end{tightdefs}}
\msgcaption{\label{get-channel-access-cmd}Get Channel Access Command,
  NetFN S/E (06h), Cmd 41h}
\end{showmsg}


\subsection{Channel Authentication}

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
\texttt{IPMI\_AUTHTYPE\_NONE} & No authentication.\\
\hline
\texttt{IPMI\_AUTHTYPE\_MD2} & \acs{MD2} style authentication.\\
\hline
\texttt{IPMI\_AUTHTYPE\_MD5} & \acs{MD5} style authentication.  This is the
recommended type of authentication.\\
\hline
\texttt{IPMI\_AUTHTYPE\_STRAIGHT} & Puts the password into the message in
plain text.  Don't use this.\\
\hline
\end{tabularx}
\caption{\label{ipmi-authtypes}Authentication types in IPMI}
\end{table}

\begin{table}
\begin{tabularx}{\textwidth}{|l|X|}
\hline
0 & no authentication\\
\hline
1 & MD2 authentication\\
\hline
2 & MD5 authentication\\
\hline
3 & reserved\\
\hline
4 & straight password authentication\\
\hline
5 & OEM authentication\\
\hline
6-7 & reserved\\
\hline
\end{tabularx}
\caption{\label{auth-bitmask}Authentication bitmask often used in \acs{IPMI}}
\end{table}

\section{The \acs{PEF} Table and \acs{SNMP} Traps}

Many \ac{IPMI} systems can specify that certain operations be done
when an event comes in.  This can depend on the event's contents;
different actions can be done for different sets of events.  This is
done with the \acf{PEF} configuration.  Not all \acs{IPMI} systems can
do event filtering, but ones that do will work as this section
describes.

The \ac{PEF} configuration allows several different actions to be
performed when an IPMI event comes in (or when the BMC powers up and
there are pending events in its event queue).  Except for sending an
alert, if multiple event filters match, the higher priority action
will be done and the lower priority action will be ignored.  The
actions are:

\noindent\begin{tabularx}{\textwidth}{|p{0.2\textwidth}|l|X|}
\hline
\bfseries{Action} & \bfseries{Priority} & \bfseries{Description}\\
\hline
power down & 1 & (optional) Power the system down.\\
\hline
power cycle & 2 & (optional) Power off the system, then power it back on.\\
\hline
reset & 3 & (mandatory) Reset the main processor in the system.\\
\hline
Diagnostic Interrupt & 4 & (optional) Send a system-defined diagnostic
        interrupt to the main processor in the system.  This is generall
        an \ac{NMI}.\\
\hline
Send Alert & 5 & Send an alert of some type, via an \acs{SNMP} trap,
        a page, or a modem dialup.  Note that unlike the rest of the
        actions, this action will still be done if a higher priority
        action is done.  Alerts can also be prioritized via the
        Alert Policy Table as described in section \ref{sec-pef-conf-parms}.\\
\hline
\acs{OEM} & \acs{OEM} & (optional) Priority is defined by the \acs{OEM}.\\
\hline
\end{tabularx}

This sections will mainly focus on sending SNMP traps with alerts,
although the other parts will also be covered.  The \acs{PEF}
configuration can specify sending \acs{SNMP} traps to inform the the
management system that something has happened.  Generally, it is
saying that an event has been placed into the event log.  Most of the
event information is in the SNMP trap, but unfortunately, some key
information is not there.  It does give the system an immediate
notification.

To have a system send traps, two tables must be set up.  The \acs{LAN}
configuration table described in section \ref{lan-config} has
parameters to set the \acs{SNMP} community string and the trap
destination addresses available.  The \ac{PEF} table contains
information about how to filter traps.  Different events can cause
different traps to be sent to different places.  As well, specific
events can do other things, such as reset or power off the system.
The thing we are interested in is the ``Alert'' capability.

Note that alerts can also cause telephone pages, serial dialups and
things like that to happen.  They are pretty flexible, although this
section will mostly focus on \acs{SNMP} traps.

\subsection{\acs{PEF} and Alerting Commands}

These commands control the \ac{PEF} and alerting capabilities of a
system.

Table \ref{get-pef-cap-cmd} shows the command used to find out what
alert capabilities a BMC has.

\begin{showmsg}
\msgtag{Request}
\msgitem{-}{-}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgitem{1}{\acs{PEF} version, encoded as:
        \begin{tightdefs}
        \item[bits 0-3] - Major version \#
        \item[bits 4-7] - Minor version \#
        \end{tightdefs}}
\msgitem{2}{Supported PEF actions, if the bit is one then the action is
        supported:
        \begin{tightdefs}
        \item[bit 0] - alert
        \item[bit 1] - power down
        \item[bit 2] - reset
        \item[bit 3] - power cycle
        \item[bit 4] - OEM action
        \item[bit 5] - diagnostic interrupt
        \item[bits 6-7] - reserved
        \end{tightdefs}}
\msgitem{3}{Number of entries in teh event filter table}
\msgcaption{\label{get-pef-cap-cmd}Get \acs{PEF} Capabilities Command,
  NetFN S/E (04h), Cmd 10h}
\end{showmsg}

Table \ref{set-pef-conf-cmd} shows the command used to set the
\acs{PEF} configuration parameters in a BMC.

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{Parameter Selector.  This selects the entry in the table that you
        want to set.}
\msgitem{1-n}{The data for the parameter.  You must look up the entry in
        table \ref{pef-conf-parms} for the exact contents, it depends on
        which entry you are setting.}
\msgtag{Response}
\msgitem{0}{Completion code.  Standard completion codes, plus:\\
        80h - Parameter not supported\\
        81h - Attempt to set the ``set in progress' value (parm 0) when
                the parameter is not in the free (set complete) state.\\
        82h - Attempt to write a read-only parameter.}
\msgcaption{\label{set-pef-conf-cmd}Set \acs{PEF} Configuration Parameters
  Command, NetFN S/E (04h), Cmd 12h}
\end{showmsg}

Table \ref{get-pef-conf-cmd} shows the command used to get \acs{PEF}
configuration parameters in a BMC.

\begin{showmsg}
\msgtag{Request}
\msgitem{0}{\begin{tightdefs}
        \item[bits 0-6] - Parameter Selector.  This selects the entry in the
          table that you want to get.\\
        \item[bit 7] - If 1, only get parameter revision
        \end{tightdefs}}
\msgitem{1}{Set Selector.  Some parameters are in an array, this tells which
        array element to set.  Set to zero if the parameter does not have a
        set selector.}
\msgitem{2}{Block Selector.  Some parameters have two levels of arrays
        (an array inside of the array).  The Set Selector is the first
        level array specifier, this is the second level.  Set to zero
        if the parameter does not have a block selector.}
\msgtag{Response}
\msgitem{0}{Completion code.  Standard codes, plus:\\
        80h - parameter not supported}
\msgitem{1}{Parameter revision.  Format is:\\
        Bits 0-3 - Oldest revision parameter is backward compatible with\\
        Bits 4-7 - Current parameter revision}
\msgitem{2-n}{Parameter data.  This will not be present if bit 7 of byte 0
        of the response is set to 1.  The contents of this depends on the
        particular parameter being fetched, see table \ref{pef-conf-parms}
        for the parameters.}
\msgcaption{\label{get-pef-conf-cmd}Get \acs{PEF} Configuration Parameters
  Command, NetFN S/E (04h), Cmd 13h}
\end{showmsg}

Table \ref{pet-ack-cmd} shows the command used to send an acknowledge
for a received trap.  If the ``Alert Acknowledge'' bit is set in
``Destination Type'' entry of the \acs{LAN} Configuration Table (Table
\ref{lan-conf-parms}) or in the `` ``Destination Info'' entry of the
Serial Configuration Table (Table \ref{serial-conf-parms}), then the
receiver of the trap must send this message to stop the resends.

\begin{showmsg}
\msgtag{Request}
\msgitem{0-1}{Sequence Number, from the field in the \ac{PET} of the trap
  being acknowledged.  Least significant byte first.}
\msgitem{2-5}{Local Timestamp, from the field in the \ac{PET} of the trap
  being acknowledged.  Least significant byte first.}
\msgitem{6}{Event Source Type, from the field in the \ac{PET} of the trap
  being acknowledged}
\msgitem{7}{Sensor Device, from the field in the \ac{PET} of the trap
  being acknowledged}
\msgitem{8}{Sensor Number, from the field in the \ac{PET} of the trap
  being acknowledged}
\msgitem{9-11}{Event Data 1-3, from the field in the \ac{PET} of the trap
  being acknowledged}
\msgtag{Response}
\msgitem{0}{Completion Code}
\msgcaption{\label{pet-ack-cmd}\acs{PET} Acknowledge Command,
  NetFN S/E (04h), Cmd 17h}
\end{showmsg}

\subsection{The \acs{PEF} Postpone Timer}

TBD - write this.

\subsection{\acs{PEF} Configuration Parameters}
\label{sec-pef-conf-parms}

The \acs{PEF} Configuration table has an unusual locking mechanism
(although it is usual for \acs{IPMI}).  Parameter zero is a lock.  If
you set the value to one, it will only succeed if the value is zero.
Thus, to lock the table, you set the value to one until it succeeds.
You then set it to zero when you are done.  This locking mechanism
leads to problem if the locker dies while it holds the lock, so you
probably need some way to override the lock if this happens.  The lock
does not actually keep anyone from changing the data, it is simply a
common mechanism to mutual exclusion.  Note also that the lock has a
``commit'' mechanism, writing two to the lock will commit the contents
if the system supports it.  If the system supports rollback, setting
the value to zero will rollback and not commit the changes you made.
So for correctness, you should write a two when you are complete, and
if that fails then write a zero.

Table \ref{pef-conf-parms} has the parameters used to configure the
event filter. Unless marked ``volatile'', all of these will survive
removal of power.

\begin{longtable}{|p{0.2\textwidth}|l|p{0.65\textwidth}|}
\caption{\acs{PEF} Configuration Parameters\label{pef-conf-parms}}
\\ \hline
\bfseries{Parameter} & \bfseries{\#} & \bfseries{Description}\\
\endhead
\hline
Set In Progress (volatile) & 0 &
        Used to indicate that the parameters are being updated.
        Bits 2-7 are reserved.  Bits 0-1 have the following values:
        \begin{tightdefs}
        \item[00b] - set complete.  This is the state the system comes up in.
                This means that any user is finished updating the
                parameters.  If rollback is implemented, setting this
                value will cause any changes made since last setting
                this value to ``set in progress'' to be undone.
        \item[01b] - set in progress.  A user will set this value to inform
                others that it is updating these parameters.  This value
                can only be set if the current value is ``set complete''.
        \item[10b] - commit write (optional).  This will commit any changes
                that
                are pending and go to ``set complete'' state.  Some systems
                may not support this, if setting this returns an error you
                should set this value to ``set complete'' by hand.
        \end{tightdefs}\\
\hline
\acs{PEF} Control & 1 &
        One byte field global control bits for the \acs{PEF}:
        \begin{tightdefs}
        \item[bit 0] - Set to one to enable the PEF.
        \item[bit 1] - Set to one to cause event messages to be sent for
          each action triggered by a filter.  These events are send as the
          System Event Sensor (12h), offset 04h, see table
          \ref{sensor-type-codes}.  Note that these events are subject
          to PEF filtering, so be careful not to cause an infinite
          event message send.
        \item[bit 2] - PEF Startup Delay Enable (optional).  When set
          to one, this bit enables a PEF startup delay on manual
          startup of a chassis and on all system resets.  If this bit
          is supported, the spec says that the implementation must
          supply a way for the user to diable the PEF in case the filter
          entries are causing an infinite loop.  I have no idea what that
          means.  If this bit is not implemented, the spec says that there
          must always be a startup delay.  Parameter 3 of this table
          sets the time.
        \item[bit 3] - PEF Alert Startup Delay Enable (optional).  When
          set to one, this bit enables a delay between startup time and
          when alerts are allowed to be sent.  Parameter 4 of this table
          sets the time.
        \item[bits 4-7] - reserved
        \end{tightdefs}\\
\hline
\acs{PEF} Action Global Control & 2 &
        A one byte field for controlling whether specific \acs{PEF} actions
        are enabled at all.  If the bit is set to one, it is enabled.  The
        bits are:
        \begin{tightdefs}
        \item[bit 0] - alert
        \item[bit 0] - power down
        \item[bit 0] - reset
        \item[bit 0] - power cycle
        \item[bit 0] - OEM
        \item[bit 0] - diagnostic interrupt
        \item[bits 6-7] - reserved
        \end{tightdefs}\\
\hline
PEF Startup Delay (optional) & 3 &
        A one byte field giving the \acs{PEF} startup delay, in
        seconds, 10\% accuracy.  A zero value means no delay.  This
        goes along with bit 2 of byte 1 of parameter 1 of this table,
        see that for more details.\\
\hline
PEF Alert Startup Delay (optional) & 4 &
        A one byte field giving the \acs{PEF} Alert startup delay, in
        seconds, 10\% accuracy.  A zero value means no delay.  This
        goes along with bit 3 of byte 1 of parameter 1 of this table,
        see that for more details.\\
\hline
Number of Event Filters (read only) & 5 &
        The number of array entries in the event filter table, parameter
        6 of this table.  The bits are:
        \begin{tightdefs}
        \item[bits 0-6] - The number of event filter entries.  A zero
          here means that events filters are not supported.
        \item[bit 7] - reserved
        \end{tightdefs}\\
\hline
Event Filter Table & 6 &
        This is a 21 byte field giving access to the event filter table.
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
          \item[bits 0-6] - The set selector, the array index of which
            event filter to set.  00h is reserved and not used and does
            not count in the number of event filters.
          \item[bit 7] - reserved
          \end{tightdefs}
        \item[bytes 1-20] - The filter data for the array element given
          by byte 1 of this parameter.  See table \ref{pef-table-entry}
          for the contents of this data.
        \end{tightdefs}\\
\hline
Event Filter Table Byte 1 & 7 &
        This is a 2 byte field giving access to the first byte of an
        event filter table entry.  This makes it convenient to set the
        first byte without having to read-modify-write the whole entry.
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
          \item[bits 0-6] - The set selector, the array index of which
            event filter to set.  00h is reserved and not used and does
            not count in the number of event filters.
          \item[bit 7] - reserved
          \end{tightdefs}
        \item[byte 1] - Byte 1 of the event filter table entry.  See
          table \ref{pef-table-entry} for the contents of this data.
        \end{tightdefs}\\
\hline
Number of Alert Policies (read only) & 7 &
        The number of array entries in the alert policy table, parameter
        9 of this table.  The bits are:
        \begin{tightdefs}
        \item[bits 0-6] - The number of event filter entries.  A zero
          here means that alert policies are not supported.
        \item[bit 7] - reserved
        \end{tightdefs}\\
\hline
Alert Policy Table & 8 &
        This is a 4 byte field giving access to the alert policy table.
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
          \item[bits 0-6] - The set selector, the array index of which
            alert policy to set.  00h is reserved and not used and does
            not count in the number of event filters.
          \item[bit 7] - reserved
          \end{tightdefs}
        \item[bytes 1-3] - The filter data for the array element given
          by byte 1 of this parameter.  See table
          \ref{alert-policy-table-entry}
          for the contents of this data.
        \end{tightdefs}\\
\hline
System \acs{GUID} & 9 &
        A 17 byte field telling how to get the system \acs{GUID} for \acs{PET}
        traps.
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
          \item[bit 0] - If one, use the value in bytes 1-16 of this field
            as the \acs{GUID} in traps.  If not set, use the value returned
            from the Get System \acs{GUID} command.
          \item[bits 1-7] - reserved
          \end{tightdefs}
        \item[bytes 1-16] - The system \acs{GUID}
        \end{tightdefs}\\
\hline
Number of Alert String Keys (read only) & 11 &
        The number of array entries in the alert string keys, parameter
        12 of this table.  The bits are:
        \begin{tightdefs}
        \item[bits 0-6] - The number of alert string keys.  A zero
          here means that alert policies are not supported.
        \item[bit 7] - reserved
        \end{tightdefs}\\
\hline
Alert String Keys (some parts are volatile) & 12 &
        Some actions require alert strings for paging an operator.  This
        key is used in conjunction with the alert policy table (table
        \ref{alert-policy-table-entry}) in some cases.  If bit 7 of byte
        3 of an alert policy table entry is set to 1, then it will use
        the alert string set field from that table and the event filter
        number from the event being processed to search this table.
        If it finds a match, it will use the alert string that corresponds
        with the same index as the entry in this table.

        For instance, if entry 4h of this table has a 3h in byte 1 and
        a 7h in byte 2, if event filter 4 matches an event and the
        alert policy used has 87h in byte 3, then the alert string
        entry 4h of the alert strings are used.
        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
          \item[bits 0-6] - The set selector, the array index of which
            alert key to set.  Entry 0h is volatile and used by the
            Alert Immediate command as described in section
            \ref{sec-alert-immediate}.  Entries 1h-7h are
            non-volatile.  All other entries are reserved.
          \item[bit 7] - reserved
          \end{tightdefs}
        \item[byte 1]
          \begin{tightdefs}
          \item[bits 0-6] - Event filter number to match
          \item[bit 7] - reserved
          \end{tightdefs}
        \item[byte 2]
          \begin{tightdefs}
          \item[bits 0-6] - Alert String Set to match
          \item[bit 7] - reserved
          \end{tightdefs}
        \end{tightdefs}\\
\hline
Alert Strings (some parts are volatile) & 13 &
        Some actions require alert strings for paging an operator.
        This table holds the actual alert strings.  This table is
        indexed by the alert policy table (table
        \ref{alert-policy-table-entry}) either directly if bit 7 of
        byte 3 of an alert policy table entry is set to 0, or indirectly
        through parameter 12 of this table if that bit is one.

        The meanings of the values in this table are dependent on the
        alert type and channel.

        For dial paging, this string will have a carraige return
        automatically appended to the string.

        For TAP paging, this string corresonds to 'Field 2', the pager
        message.  Note that TAP only supports 7-bit ASCII and the
        \acs{BMC} will zero the high bit when doing TAP paging.

        \begin{tightdefs}
        \item[byte 0]
          \begin{tightdefs}
          \item[bits 0-6] - The set selector, the array index of which
            alert string to set.  Entry 0h is volatile and used by the
            Alert Immediate command as described in section
            \ref{sec-alert-immediate}.  Entries 1h-7h are
            non-volatile.  All other entries are reserved.
          \item[bit 7] - reserved
          \end{tightdefs}
        \item[byte 1] - Block selector.  The strings may be much larger than
          can be set in a single message.  This selects which block to
          write, in 16-byte increments.  So, a 0 here is the first 16 bytes,
          a 1 is the second 16 bytes, and so on.
        \item[byte 2-n] - The bytes to write into the specific block
          If this is less than 16 bytes, then only the given number of
          bytes are written.
        \end{tightdefs}\\
\hline
OEM Parmeters & 96+ &
        Parameters 96-127 are allowed for OEM use.  All other parameters
        are reserved.\\
\hline
\end{longtable}

The \ac{PEF} table is read and written as part of the PEF
Configuration table, parameter 6, but the contents are documented
separately in table \ref{pef-table-entry}.  When an event comes in,
it is compared against each filter in order.  If a match occurs on
multiple filters, then the highest priority action is done and the
rest except for alerts are ignored.  After the operation is completed,
any alert operations are done by scanning the alert policy table in
order.  The order of the alert policy table defines the priority of
the different alerts.

\begin{longtable}{|l|p{0.2\textwidth}|p{0.65\textwidth}|}
\caption{\acs{PEF} Table Entry\label{pef-table-entry}}
\\ \hline
\bfseries{Byte} & \bfseries{Field} & \bfseries{Description}\\
\endhead
\hline
0 & Filter Configuration &
        Bits that control the operation of this filter:
        \begin{tightdefs}
        \item{bits 0-4} - reserved
        \item{bits 5-6} - filter type
          \begin{tightdefs}
          \item[00b] - Software configurable filter.  A manging system may
            configure all parts of this filter.
          \item[01b] - reserved
          \item[10b] - pre-configured filters.  A managing system should
            not modify the contents of this filter, although it may turn
            on and off the filter using bit 7 of this field.
          \item[11b] - reserved
          \end{tightdefs}
        \end{tightdefs}\\
\hline
1 & Event filter action &
        These bits set what action this filter will do if it matches.
        These bits are enable if set to one.
        \begin{tightdefs}
        \item[bit 0] - alert
        \item[bit 1] - power off
        \item[bit 2] - reset
        \item[bit 3] - power cycle
        \item[bit 4] - OEM action
        \item[bit 5] - diagnostic interrupt
        \item[bits 6-7] - reserved
        \end{tightdefs}\\
\hline
2 & Alert Policy Number &
        \begin{tightdefs}
        \item[bits 0-3] - If alert is selected in byte 1, this chooses the
          policy number to use in the alert policy table.
        \item[bits 4-7] - reserved
        \end{tightdefs}\\
\hline
3 & Event Severity &
        This is the value that will be put into the event severity field
        of the \ac{PET} trap.  If more than one event filter matches, the
        highest priority in all event filters will be used.  Valid values
        are:
        \begin{tightdefs}
        \item[00h] - unspecified
        \item[01h] - monitor
        \item[02h] - information
        \item[04h] - OK (returned to OK condition)
        \item[08h] - non-critical condition
        \item[10h] - critical condition
        \item[20h] - non-recoverable condition
        \end{tightdefs}\\
\hline
4 & Generator ID byte 1 &
        This matches the slave address or software id in the event.
        It must be an exact match.  Use FFh to ignore this field when
        comparing events.\\
\hline
5 & Generator ID byte 2 &
        This matches the channel and LUN in the event.  It must be an
        exact match.  Use FFh to ignore this field when comparing events.\\
\hline
6 & Sensor type &
        This matches the sensor type field in the event.  It must be an
        exact match.  Use FFh to ignore this field when comparing events.\\
\hline
7 & Sensor Number &
        This matches the sensor number field in the event.  It must be an
        exact match.  Use FFh to ignore this field when comparing events.\\
\hline
8 & Event Trigger &
        This matches the event direction and event type byte (byte 13)
        in the event.  It must be an
        exact match.  Use FFh to ignore this field when comparing events.\\
\hline
9-10 & Event data 1 low nibble values &
        This field is a bitmask specifying which values in the low 4 bits
        of the event data 1 field will match.  If a bit is set, then the
        corresponding value will match for this filter.  For instance, if
        bits 2 and 7 are set, then a value of 2 or 7 in the low nibble
        of event data 1 will cause a filter match (if everything else
        matches too, of course).
        \begin{tightdefs}
        \item[byte 9] - bit positions 0-7
        \item[byte 10] - bit positions 8-15
        \end{tightdefs}\\
\hline
11 & Event data 1 AND mask &
        This bit indicates which bits in event data 1 are used for
        comparison.  If a bit in the mask is zero, then the bit is not
        used for comparison.  if a bit is one, then the corresponding
        bit in event data 1 is used for comparison using
        the next two bytes of the table.\\
\hline
12 & Event data 1 compare 1 &
        This byte tells how the bits in event data 1 are compared.  For
        every bit set to one in this byte and one in the AND mask, the
        corresponding bit in event data 1 must exactly match the data
        in the compare 2 field.  For all bits set to zero in this byte
        and one in the AND mask, if any of those bits must be set to the
        same value as the bit in the compare 2 field, it is considered
        a match for that byte.

        For instance, if the AND mask is 00001111b, the compare 1 field
        is 00001100b, and the compare 2 field is 00001010b, then the
        event data 1 byte matches this comparison if:
        \begin{verbatim}
          ((bit0 == 0) || (bit1 == 1))
          && (bit2 == 0) && (bit3 == 1)
        \end{verbatim}
        Because there are zeroes in bits 4-7, those are not used in the
        mask.  Exact matches are required in bits 2 and 3 to compare 2,
        and one of bits 0 and 1 must be set the same as compare 2.

        Setting bytes 11-13 to all zero will cause event data 1 to be
        ignored for comparison (it will always match).\\
\hline
13 & Event data 1 compare 2 &
        This byte is used to compare the values of event data 1.  See
        byte 12 for more details on how this works.\\
\hline
14-16 & Event data 2 fields &
        These bytes work the same a bytes 11-13, but apply to event data
        2.  See those fields for details.\\
\hline
17-19 & Event data 3 fields &
        These bytes work the same a bytes 11-13, but apply to event data
        3.  See those fields for details.\\
\hline
\end{longtable}

The Alert Policy table tells the \acs{BMC} what to do when an event filter
matches and the alert action is set.  Every matching filter with the
alert action sets that alert policy to be run.  Once all the filters
have been checked, the set alert policies are checked and executed in
order of their policy number.  Depending on the settings in the
policy, the \acs{BMC} may go to the next alert policy or stop.

\begin{longtable}{|l|p{0.2\textwidth}|p{0.65\textwidth}|}
\caption{Alert Policy Table Entry\label{alert-policy-table-entry}}
\\ \hline
\bfseries{Byte} & \bfseries{Field} & \bfseries{Description}\\
\endhead
\hline
0 & Policy Number and Policy &
        \begin{tightdefs}
        \item[bits 0-2] - The policy.  Valid values are:
          \begin{tightdefs}
          \item[0h] - Alway do this alert if chosen, even if other
            alert policy tables tell the \acs{BMC} to stop.
          \item[1h] - If an alert to a previous destination was successful,
            do not do this alert.  If no alert has been successful so far,
            do this alert.  Then go to the next entry in the policy table.
          \item[2h] - If an alert to a previous destination was successful,
            do not do this alert.  If no alert has been successful so far,
            do this alert.  Then stop processing the policy table (except
            for entries with a 0h policy).
          \item[3h] - If an alert to a previous destination was successful,
            do not do this alert.  If no alert has been successful so far,
            do this alert.  Then proceed to the next policy entry that
            has a different channel.
          \item[4h] - If an alert to a previous destination was successful,
            do not do this alert.  If no alert has been successful so far,
            do this alert.  Then proceed to the next policy entry that
            has a different destination type.
          \end{tightdefs}
        \item[bit 3] - Entry enable.  If set to one, the entry is enabled,
          if set to zero it is ignored.
        \item[bits 4-7] - The policy number, the array index of which
          policy table entry to set.
        \end{tightdefs}\\
\hline
1 & Channel / Destination &
        \begin{tightdefs}
        \item[bits 0-3] - The destination selector.  For the chosen
          channel, this is the specific destination in the channel
          to use to send the alert.  See the \acs{LAN} Configuration Table
          (table \ref{lan-conf-parms}) or the Serial Configuration Table
          (table \ref{serial-conf-parms}) for information on what the
          destination selectors can do.
        \item[bits 4-7] - The channel.  This tells the BMC which channel
          to send the alert over.
        \end{tightdefs}\\
\hline
2 & Alert String Info &
        Some types of alerts need a string associated with them, this
        chooses the string.  The specific strings are stored in the \ac{PEF}
        configuration parameters 12 and 13 in table \ref{pef-conf-parms}.

        If bit 7 of this byte is one, then the string is dependent on
        the event filter number that was matched for this alert policy.
        Bits 0-6 of this byte are the alert string set.
        The event filter number and the alert string set are looked up in
        the table in parameter 12 of the \ac{PEF} configuration to choose the
        alert string to use.  See that parameter for more details on how
        this works.

        if bit 7 of this byte is zero, then the bits 0-6 of this field
        are the alert string selector.  The alert string selector is
        used as a direct index into the alert string table in parameter
        13 of the \ac{PEF} configuration.\\
\hline
\end{longtable}

\subsection{OpenIPMI and \acs{SNMP} Traps}

\subsubsection{Setting Up A System To Send Traps}

Setting up a system to send traps with OpenIPMI can be done two basic
ways.  The hard way is to set up each table individually.  This is
more work, but is very flexible.  The easy way just sets up for SNMP
traps but does all the work for you.

\paragraph{Setting Up the \acs{PEF} Table and \acs{LAN} Configuration Table}

For a system to send traps, you must set up the \acs{PEF} table as
described in section \ref{sec-pef-conf-parms} and the \acs{LAN}
configuration table described in section \ref{sec-lan-conf-parms}.
However, this is a lot of work.

\paragraph{Setting Up For Traps the Easy Way}

OpenIPMI provides a way to set up a simple SNMP trap send from a
\ac{BMC}.  The call has an unfortunately large number of parameters
because OpenIPMI cannot pick the various selectors and policy numbers
needed to set up for the trap, because you may be using them for other
things.  The function call is:

\begin{verbatim}
int ipmi_pet_create(ipmi_domain_t    *domain,
                    unsigned int     connection,
                    unsigned int     channel,
                    struct in_addr   ip_addr,
                    unsigned char    mac_addr[6],
                    unsigned int     eft_sel,
                    unsigned int     policy_num,
                    unsigned int     apt_sel,
                    unsigned int     lan_dest_sel,
                    ipmi_pet_done_cb done,
                    void             *cb_data,
                    ipmi_pet_t       **pet);
\end{verbatim}

\begin{description}
\item[domain] - The domain to set up a trap sender for.
\item[connection] - Which specific connection to the domain do you
  want to configure?
\item[channel] -  The specific channel to configure.  You will have
  to know the channel you want to configure.
\item[ip\_addr] - The IP address to tell the \ac{BMC} to send messages to.
\item[mac\_addr] - The MAC address to tell the \ac{BMC} to send messages to.
\item[eft\_sel] - the Event Filter selector to use for this PET destination.
  Note that this does *not* need to be unique for different OpenIPMI
  instances that are using the same channel, since the configuration
  will be exactly the same for all EFT entries using the same
  channel, assuming they share the same policy number.
\item[policy\_num] - The policy number to use for the alert policy.  This
  should be the same for all users of a domain.
\item[apt\_sel] - The Alert Policy selector to use for this PET destination.
  Note that as \verb=eft_sel=, this need not be unique for each different
  OpenIPMI instance on the same channel.
\item[lan\_dest\_sel] - The LAN configuration destination selector for
  this PET destination.  Unlike \verb=eft_sel= and \verb=apt_sel=,
  this *must* be unique for each OpenIPMI instance on the same
  channel, as it specifies the destination address to use.
\item[done] - This function will be called when the PET configuration is
  complete.
\item[cb\_data] - Data to pass to the \verb=done= call.
\item[pet] - The created object.
\end{description}

This creates an object that will continue to live and periodically
check that the configuration is correct.  If you wish to destroy this,
use the following:

\begin{verbatim}
int ipmi_pet_destroy(ipmi_pet_t       *pet,
                     ipmi_pet_done_cb done,
                     void             *cb_data);
\end{verbatim}

\subsubsection{Handling Incoming Traps}

OpenIPMI has some ability to handle \acs{SNMP} traps.  It does not
implement its own \acs{SNMP} stack though, so it cannot do all the
work for you.  Indeed, different \acs{SNMP} exist and OpenIPMI would
not want to presume that you would only use one of them.  Also, since
the \acs{SNMP} trap port is fixed, some cooperative mechanism may be
required between different pieces of software. You must have your own
stack, like NetSNMP\cite{netsnmp}, and catch the traps with that.

Once you have a trap, you must call:

\begin{verbatim}
int ipmi_handle_snmp_trap_data(void            *src_addr,
                               unsigned int    src_addr_len,
                               int             src_addr_type,
                               long            specific,
                               unsigned char   *data,
                               unsigned int    data_len);
\end{verbatim}

Where \verb=src_addr= is the \acs{IP} source address
(\verb=struct sockaddr_in=) and length is the length of the address
structure.  Only \acs{IP} is supported for now, so
\verb=src_addr_type= must be \verb=IPMI_EXTERN_ADDR_IP=.  The
\verb=specific= field is the field of the same name from the
\acs{SNMP} \ac{PDU}.  The \verb=data= field is a pointer to the user
data from the \acs{SNMP} \ac{PDU}, and the length of that data is in
\verb=data_len=.

The data in the trap is not enough information to fully decode the
event, so currently an incoming trap will only cause an SEL fetch on
the proper \acs{SEL}.
OpenIPMI will automatically send the \acs{PET} Acknowledge command
described in Table \ref{pet-ack-cmd}.

Note that \acs{SNMP} traps can only be received on one port, and that
port is privileged, so you must run as root to receive SNMP traps.

\subsection{The Alert Immediate Command}
\label{sec-alert-immediate}

\section{OpenIPMI Addressing}
\label{openipmi-addressing}

The OpenIPMI driver and library use a common addressing scheme.  This
attempts to normalize the messaging from the user's point of view.
The message data will look the same no matter where you send it.  The
only difference is the message.

The main OpenIPMI address structure is:

\begin{verbatim}
struct ipmi_addr
{
        int   addr_type;
        short channel;
        char  data[IPMI_MAX_ADDR_SIZE];
};
\end{verbatim}

The \verb=addr_type= and \verb=channel= are common to all OpenIPMI
addresses.  You have to look at the \verb=addr_type= to determine the
type of address being used and cast it to the proper address.  The
specific messages are overlays on this structure.

A system interface address is used to route the message to the local
management controller.  It is:

\begin{verbatim}
#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE ...
struct ipmi_system_interface_addr
{
        int           addr_type;
        short         channel;
        unsigned char lun;
};
\end{verbatim}

The channel should be \verb=IPMI_BMC_CHANNEL= and the lun should
generally be zero.

An \acs{IPMI} address routes messages on the \ac{IPMB}.  The format is:

\begin{verbatim}
#define IPMI_IPMB_ADDR_TYPE             ...
#define IPMI_IPMB_BROADCAST_ADDR_TYPE   ...
struct ipmi_ipmb_addr
{
        int           addr_type;
        short         channel;
        unsigned char slave_addr;
        unsigned char lun;
};
\end{verbatim}

The \verb=channel= should be the \ac{IPMB} bus channel number, the
\verb=slave_address= should be the \ac{IPMB} address of the destination,
and the \verb=lun= should be the destination \ac{LUN}.  Notice that two
address types can be used with this command, a normal \ac{IPMB} message and
a broadcast \ac{IPMB} can be sent with this.  Note that if you send a
broadcast \ac{IPMB}, you will receive a normal \ac{IPMB} address in the
response.

A \acs{LAN} to system interface address is:

\begin{verbatim}
#define IPMI_LAN_ADDR_TYPE ...
struct ipmi_lan_addr
{
        int           addr_type;
        short         channel;
        unsigned char privilege;
        unsigned char session_handle;
        unsigned char remote_SWID;
        unsigned char local_SWID;
        unsigned char lun;
};
\end{verbatim}

This deviates a little from the \ac{IPMI} spec.  In the spec, the
SWIDs used are the requester SWID and responder SWID.  For this
message, the remote SWID is other end and the local SWID is this end.
This way, there is no confusion when sending and receiving messages,
and no special handling of the SWIDs needs to be done.

%---------------------------------------------------------------------
\chapter{The \acs{MC}}
\label{ipmi-mc}

The \ac{MC} is the ``intelligent'' device in an OpenIPMI system.  It
is a processor that is always on and handles management operations in
the system.  It is the thing that receives commands, processes them,
and returns the results.

An \ac{IPMI} system will have at least one \ac{MC}, the \ac{BMC}.  The
\ac{BMC} is the ``main'' management controller; it handles most of the
interfaces into the system.

\section{OpenIPMI and MCs}

\emph{Note: This section deals with OpenIPMI internals.  The user does
not generally need to know about management controllers, as they are
internal to the operation of OpenIPMI.  However, they are discussed
because users writing plugins or fixup code will need to know about
them.  Plus, these interfaces are subject to change.}

\subsection{Discovering \acs{MC}s}

In OpenIPMI, the \ac{MC} devices in a system are part of the domain.
When the user creates the domain, OpenIPMI will start scanning for
\acs{MC}s in the system.  The user can discover the \acs{MC}s in a
domain in two ways: iterating or registering callbacks.

Iterating the \acs{MC}s in a domain simply involves calling the
iterator function with a callback function:

\begin{verbatim}
static void
handle_mc(ipmi_domain_t *domain, ipmi_mc_t *mc, void *cb_data)
{
  my_data_t *my_data = cb_data;
  /* Process the MC here */
}

void
iterate_mcs(ipmi_domain_t *domain, my_data_t *my_data)
{
  int rv;
  rv = ipmi_domain_iterate_mcs(domain, handle_mc, my_data);
  if (rv)
    handle_error();
}
\end{verbatim}

This is relatively simple to do, but you will not be able to know
immediately when new \acs{MC}s are added to the system.  To know that,
you must register a callback function as follows:

\begin{verbatim}
static void
handle_mc(enum ipmi_update_e op,
          ipmi_domain_t *domain,
          ipmi_mc_t *mc,
          void *cb_data)
{
  my_data_t *my_data = cb_data;
  /* Process the MC here */
}

void
handle_new_domain(ipmi_domain_t *domain, my_data_t *my_data)
{
  int rv;
  rv = ipmi_domain_add_mc_updated_handler(domain, handle_mc, my_data);
  if (rv)
    handle_error();
}
\end{verbatim}

You should call the function to add an MC updated handler when the
domain is reported up (or even before); that way you will not miss
any \acs{MC}s.

\subsection{\acs{MC} Active}

An \ac{MC} may be referenced by another part of they system, but may
not be present.  For instance, it may be on a plug-in card.  An
\ac{MC} that is not present is called ``inactive'', an \ac{MC} that is
present is called ``active''.  OpenIPMI automatically detects whether
\ac{MC}s are active or inactive.

The \verb=ipmi_mc_is_active= function is used to tell if an \ac{MC} is
active.  As wall, callback handlers can be registered with
\verb=ipmi_mc_add_active_handler= to know immediately when an \ac{MC}
is set active or inactive.

\subsection{\acs{MC} Information}

OpenIPMI will extract information about the MC from the Get Device ID
command; you can fetch this with functions.  The functions are almost
all of the form:

\begin{verbatim}
int ipmi_mc_xxx(ipmi_mc_t *mc)
\end{verbatim}

The fields available (replace ``xxx'' with these in the previous
definition) are:

\begin{longtable}{|l|p{0.65\textwidth}|}
\hline
provides\_device\_sdrs & Returns true if the \ac{MC} has device \ac{SDR}s,
        false if not.\\
\hline
device\_available & Return false if the \ac{MC} is operating normally, or true
        if the \ac{MC} is updating its firmware.\\
\hline
chassis\_support & Returns true if the \ac{MC} supports the chassis commands,
        false if not.\\
\hline
bridge\_support & Returns true if the \ac{MC} support bridge commands
        (generally for ICMB), false if not.\\
\hline
ipmb\_event\_generator\_support & Return true if the \ac{MC} will generate
        events
        on the \ac{IPMB}.  Note that if this is false, it can still generate
        events and store them on a local \ac{SEL}, like on a \ac{BMC}.\\
\hline
ipmb\_event\_receiver\_support & Returns true if the \ac{MC} can receive
        events from other \acs{MC}s on the \ac{IPMB}.\\
\hline
fru\_inventory\_support & If true, the \ac{MC} support \ac{FRU} inventory
        commands.\\
\hline
sel\_device\_support & If true, the \ac{MC} has an event log on it.\\
\hline
sdr\_repository\_support & If true, the \ac{MC} supports a writable \ac{SDR}
        repository.  This is \emph{not} a device \ac{SDR} repository.\\
\hline
sensor\_device\_support & If true, this \ac{MC} supports sensor commands.\\
\hline
device\_id & The device id of the \ac{MC}.  This helps identify the
        capabilities of the \ac{MC}; it is used along with the product
        and manufacturer IDs to know the exact capabilities of the device.
        It's use is \acs{OEM}-specific, though.\\
\hline
device\_revision & The hardware revision for the \ac{MC} and associated
        hardware.  It's use is \acs{OEM}-specific, though.\\
\hline
major\_fw\_revision & The major revision of the firmware running on the
        \ac{MC}.\\
\hline
minor\_fw\_revision & The minor revision of the firmware running on the
        \ac{MC}.\\
\hline
major\_version & The major version of the \ac{IPMI} specification version
        supported by the \ac{MC}.\\
\hline
minor\_version & The minor version of the \ac{IPMI} specification version
        supported by the \ac{MC}.\\
\hline
manufacturer\_id & A 24-bit number assigned by the IANA for the manufacturer
        of the MC hardware.\\
\hline
product\_id & A 16-bit number assigned by the manufacturer to identify
        the specific MC hardware.\\
\hline
\end{longtable}

In addition, the following function:

\begin{verbatim}
void ipmi_mc_aux_fw_revision(ipmi_mc_t *mc, unsigned char val[]);
\end{verbatim}

returns the optional 4-byte auxiliary firmware revision information
field.  The meaning of this field is vendor-specific and the field may
not be present (in which case all zeros is returned).

\subsection{\acs{MC} Reset}

OpenIPMI has a function to reset an MC.  It is:

\begin{verbatim}
#define IPMI_MC_RESET_COLD ...
#define IPMI_MC_RESET_WARM ...
int ipmi_mc_reset(ipmi_mc_t       *mc,
                  int             reset_type,
                  ipmi_mc_done_cb done,
                  void            *cb_data);
\end{verbatim}

Note that this resets the \ac{MC}, not the main processor on the board
the \ac{MC} is located on.  There are two types of reset, cold and
warm. Not all systems support resetting the MC and the effects of the
reset are system-dependent.

\subsection{Global Event Enables}
\label{sec-global-event-enables}

An MC has a global event enable.  If events are disabled, then all
events from the MC are disabled.  If events are enabled, then the
sending of events depends on more specific event settings on the
sensors.  The value is a true-false, setting it to true enables
events.  False disables events.  The functions are:

\begin{verbatim}
int ipmi_mc_get_events_enable(ipmi_mc_t *mc);
int ipmi_mc_set_events_enable(ipmi_mc_t       *mc,
                              int             val,
                              ipmi_mc_done_cb done,
                              void            *cb_data);
\end{verbatim}

The setting is fetched and held locally, so the ``get'' function is
immediate.  The ``set'' function requires sending a message and thus
it has a callback.

%---------------------------------------------------------------------
\chapter{\acs{IPMI} Commands}
\label{ipmi-commands}

\ac{IPMI} does everything except events through commands and
responses.  A user sends a command to an \ac{MC}, and the \ac{MC}
returns a response.  All commands have responses.  Commands may
optionally have some data; the data depends on the command.  The same
goes for responses, except that all responses contain at least one data
byte holding the completion code.  Every response has a completion
code in the first byte.

Every command and response has a \ac{NetFN} and command number.  A
\ac{NetFN} is a number that describes a function group.  All
sensor-related commands, for instance, have the same \ac{NetFN}.  The
command number is the number for the specific command within the
\ac{NetFN}.  Responses contain the same \ac{NetFN} and command number
as the command, except the \ac{NetFN} has one added to it.  So
responses to sensor command (\ac{NetFN} 04h) will use NetFN 05h.
Table \ref{netfn-codes} shows the \ac{NetFN} values.  All commands
have even \ac{NetFN}s, and all responses have odd \ac{NetFN}s.

\begin{longtable}{|l|p{0.15\textwidth}|p{0.6\textwidth}|}
\caption{\acs{NetFN} codes\label{netfn-codes}}
\\ \hline
\bfseries{NetFN} & \bfseries{Name} & \bfseries{Description}\\
\hline
00h, 01h & Chassis & Common chassis control and status functions.\\
\hline
02h, 03h & Bridge & Messaging for bridging to another bus, generally
        ICMB.\\
\hline
04h, 05h & Sensor/Event & Handling of sensors and events.\\
\hline
06h, 07h & Application & General control and status of a connection
        and basic operations.  This is the ``catch all'' where things
        that don't really fit elsewhere fall, too.\\
\hline
08h, 09h & Firmware & Used for formware checking and upgrade, generally.
        The messaging for this is completely proprietary and not defined
        by the spec.\\
\hline
0Ah, 0Bh & Storage & Non-volatile storage handling, the \ac{SDR}s and
        \ac{SEL}.\\
\hline
0Ch, 0Dh & Tranport & Configuration of the \acs{LAN} and serial interfaces.\\
\hline
0Eh-2Bh & Reserved & \\
\hline
2Ch, 2Dh & Group Extensions & A way for external groups to define their
        own extensions without conflicting.  The first byte of the
        command and second byte of the response are a field that
        identifies the entity defining the messages; these bytes are, in
        effect, an extension of the \ac{NetFN}.  The external groups
        are free to define the message outside those bounds.  Current
        defined external groups are:
        \begin{tightdefs}
        \item[00h] CompactPCI
        \item[01h] DMTF Pre-OS Working Group ASF Specification
        \end{tightdefs}
        All other values are reserved.\\
\hline
2Eh, 2Fh & OEM/Group & Basically more group extensions, except that the
        first three bytes (bytes 0-2) of commands and second three bytes
        (bytes 1-3) of responses are the IANA enterprise number.  The
        owner of the IANA enterprise number is free to define these
        values any way they like.\\
\hline
30h-3Fh & OEM & OEMs are free to use these messages any way they like.\\
\hline
\end{longtable}

Every response has a one byte error code that is always the first byte
of the message.  There are a number of error code.  Unfortunately, the
error responses returned in a response are not bounded per command;
the implementor is free to return pretty much anything it likes as an
error response.  Some commands define explicit error return code for
some situations, but not generally.  Table \ref{error-codes} shows the
error codes in IPMI.

\begin{longtable}{|l|p{0.15\textwidth}|p{0.6\textwidth}|}
\caption{Error codes\label{error-codes}}
\\ \hline
\bfseries{Error} & \bfseries{Name} & \bfseries{Description}\\
\hline
00h & & No error, command completed normally\\
\hline
01h-7Eh & & OEM error codes.  Implementors may use these error codes for
        their own commands if a standard error code does not apply.\\
\hline
7Fh & & reserved\\
\hline
80h-BEh & & Command-specific error codes.  Some commands have specific
        errors they return that only apply to that command.  These
        are defined by the command.\\
\hline
BFh & & reserved\\
\hline
C0h & Node Busy & The command could not complete because command processing
        resources on the \ac{MC} are temporarily unavailable.\\
\hline
C1h & Invalid Command & The \ac{MC} did not support the given \ac{NetFN}
        and command.\\
\hline
C2h & Invalid Command for \acs{LUN} & The given command was not supported
        on the \ac{LUN} it was sent to.\\
\hline
C3h & Timeout & A timeout occurred while processing the command.\\
\hline
C4h & Out of Space & There was not enough storage space to perform the
        given command.\\
\hline
C5h & Reservation Invalid & This is for commands that require reservations
        (like \ac{SEL} and \ac{SDR} commands).  This means the reservation
        number given was invalid or the reservation was lost.\\
\hline
C6h & Data Truncated & The request data was truncated (it is unknown what
        this means).\\
\hline
C7h & Command Length Invalid & The received command was the wrong length
        for the command.\\
\hline
C8h & Command Field Too Long & A field in a command was too long for the
        given command.\\
\hline
C9h & Parameter Out of Range & One or more fields in a command were outside the
        range of allowed values.  According to the spec, ``This is different
        from the 'Invalid data field' (CCh) code in that it indicates that
        the erroneous field(s) has a contiguous range of possible values.''
        The meaning of that enigmatic statement is unknown.\\
\hline
CAh & Too Many Requested Bytes & A request was made for some data, but the
        requested number of bytes was either beyond the end of the data or
        too long to fit into the return response.\\
\hline
CBh & Invalid Object & The requested sensor, record, or data was not present.
        The command is supported, but the specific object asked for does
        not exist.\\
\hline
CCh & Invalid Data Field & An invalid data field was in the request.  See
        error C9h for more details.\\
\hline
CDh & Command Invalid for Object & The specific sensor, record, or data
        does not support the given command.\\
\hline
CEh & No Response & The command response could not be provided.  The meaning
        of this is unknown.\\
\hline
CFh & Duplicate Request & A duplicate request was received and ignored.
        The spec says ``This completion code is for devices which cannot
        return the response that was returned for the original instance of
        the request.  Such devices should provide separate commands that
        allow the completion status of the original request to be determined.
        An Event Receiver does not use this completion code, but returns
        the 00h completion code in response to (valid) duplicate requests.''
        The meaning of this statement is unknown.  However, in general IPMI
        should be stateless because reponses can be lost and commands
        retransmitted.  Commands that have intermediate state need to be
        handled very carefully (and there are none in the main spec).\\
\hline
D0h & SDR Respository Being Updated & The SDR repository is currently
        in update mode so the given command could not be executed.\\
\hline
D1h & Firmware Being Updated & The given command could not be executed
        because firmware on the system is being updated.\\
\hline
D2h & \ac{BMC} Initializing & The given command could not be executed because
        the \ac{BMC} (or probably any \ac{MC}) is currently initializing.\\
\hline
D3h & Destination Unavailable & An \ac{MC} could not deliver the command
        to the given destination.  For instance, if you send a ``Send Message''
        command to a channel that is not active, it may return this.\\
\hline
D4h & Insufficient Privilege & The user does not have sufficient privilege
        to execute the command.\\
\hline
D5h & Invalid State & The given command cannot be supported in the present
        state.\\
\hline
D6h & Subfunction Disabled & The given command cannot be executed because
        the subfunction required has been disabled.\\
\hline
D7h-FEh &  & reserved\\
\hline
FFh & Unspecified & Some error occurred, but the true error could not be
        determined.\\
\hline
\end{longtable}

The actual mechanics of sending a message depend on the interface, see
the interface sections in chapter \ref{ipmi-interfaces} for the
details of sending over specific interfaces.

\section{Sending Commands in the OpenIPMI Library}

The OpenIPMI library hides most of the details of sending a command
and handles all the aspects of talking to sensors, controls, and
\acs{MC}s.  You should generally not need to send a command to an
\ac{MC}.  However, exceptions exist, so the operation is described
here.

If you are trying to control some physical thing on the system (an
LED, siren, reset, or some other output) you probably want a clean
interface to the function through a control.  You would then send the
messages from functions that are part of the control interface.

But not everything fits that scenario, and if you build a control,
you probably still need to send messages, so...

To send a message, you can either send it to an address in the domain
or to an \acs{MC}.  To send to an address, you must have or construct
a valid IPMI address and use:

\begin{verbatim}
ipmi_send_command_addr(ipmi_domain_t                *domain,
                       ipmi_addr_t                  *addr,
                       unsigned int                 addr_len,
                       ipmi_msg_t                   *msg,
                       ipmi_addr_response_handler_t rsp_handler,
                       void                         *rsp_data1,
                       void                         *rsp_data2);
\end{verbatim}

To send to an \acs{MC}, you must have a valid MC.  You can usually
extract this from a control or sensor (the MC the sensor belongs to)
or you can iterate the \acs{MC}s or keep the \ac{MC} id around.  The
function to send a message to an \acs{MC} is:

\begin{verbatim}
int ipmi_mc_send_command(ipmi_mc_t                  *mc,
                         unsigned int               lun,
                         ipmi_msg_t                 *cmd,
                         ipmi_mc_response_handler_t rsp_handler,
                         void                       *rsp_data);
\end{verbatim}


%---------------------------------------------------------------------
\chapter{\acs{SDR} Repositories}

\ac{IPMI} systems keep information about their sensors and entities in
an \ac{SDR} repository.  The SDR repository is a set of record; each
record holding information about the sensor or entity.  An \ac{SDR}
repository may also hold \ac{OEM} records; those are system-specific
and not discussed here.

\ac{IPMI} systems have two types of SDR repositories.  The \ac{IPMI}
spec does not give a name to the first type, but we shall refer to it
here as the ``main'' \ac{SDR} repository.  A system should generally
only have one of these.  This repository is writable by the user using
standard operations.

Each \ac{MC} in an IPMI system may have a device \ac{SDR} repository.
\ac{IPMI} does not have standard operations to write this repository,
just to read it.  This repository may also change dynamically.  For
instance, if some device is hot-plugged onto a board, the \ac{MC} for
that board may dynamically add or change sensors and entities for the
new device.

The records in these two types of repositories are the same.

\section{\acs{SDR} Reservations}

Both SDR repository types support the concept of a reservation.

\section{The Main \acs{SDR} Repository}

TBD - write this

\subsection{Modal and Non-Modal \acs{SDR} Repositories}

\subsection{Commands for Main \acs{SDR} Repositories}

\section{Device \acs{SDR} Repositories}

TBD - write this

\subsection{Dynamic Device \acs{SDR} Repositories}

\subsection{Commands for Device \acs{SDR} Repositories}

\section{Records in an \acs{SDR} Repository}

Section~\ref{sec-entity-sdrs} on entities and
section~\ref{sec-sensor-sdrs} on sensors describe the specific records
in \ac{SDR} repositories.  They all follow a general format, though;
this section describes that format.

Each SDR has three parts: A header, a key, and a body.  Note that all
multi-byte values in SDRs are little-endian unless specified
otherwise.  The header is:

\begin{showmsg}
\hline
\msgitem{0-1}{Record ID.  This is the number used to fetch the record
        from the \ac{SDR} repository.}
\msgitem{2}{IPMI Version.  This is the IPMI version the record is
        specified under.}
\msgitem{3}{Record Type.  This tells the specific type of record
        contained in the \ac{SDR}; it gives the format of the data
        after the header.}
\msgitem{4}{Record Size.  This is the number of bytes in the SDR,
        not including the header.}
\msgcaption{The \acs{SDR} header}
\end{showmsg}

The key and body are dependent on the record type and are defined in
the specific record definitions.  Table~\ref{tab-sdr-types} shows the
various record types supported by IPMI.

\begin{table}
\begin{tabular}{|l|p{0.85\textwidth}|}
\hline
01h & Type 1 sensors are generally used for analog sensors.  They
        can be used for discrete sensors, too, but most of the
        fields are irrelevant for discrete sensors.\\
\hline
02h & Type 2 sensors are used for discrete sensors.  Multiple
        similar sensors may be specific in a single type 2
        record if the sensor meet certain criteria.\\
\hline
03h & Type 3 sensors are used for sensors that only send events.\\
\hline
08h & A type 8 sensor is called a \acf{EAR}.  These are used to specify
        entity containment; to specify, for instance that a processor
        entity is on a specific board entity.\\
\hline
09h & A type 9 sensor is called a \acf{DREAR}.  It is like a type 8
        record, but can contain device-relative entities.\\
\hline
10h & A type 16 record is called a \acf{GDLR}.  It is used to give
        information about an entity when the entity is not a \acs{FRU}
        or \acs{MC}.\\
\hline
11h & A type 17 record is called a \acf{FRUDLR}.  It is used to give
        information about a \acs{FRU} entity in the system that is
        not a \acs{MC}.\\
\hline
12h & A type 18 record is called a \acf{MCDLR}.  It is used to give
        information about a \acs{MC} entity in the system.\\
\hline
13h & A type 19 record is called a Management Controller Confirmation
        Record.  It record the fact that a \acs{MC} has been found in
        the system.  Note that OpenIPMI does not currently use these.\\
\hline
14h & A type 20 record is called a \acs{BMC} Message Channel Info Record.
        It is only used in \acs{IPMI} version 1.0; it specifies the
        channels available on the system.  Newer version of \acs{IPMI}
        use specific messages to carry this information.\\
\hline
C0h & This is used for OEM records.  The format depends on the specific
        system type.\\
\hline
\end{tabular}
\caption{\label{tab-sdr-types}SDR types.  All other record types are reserved}
\end{table}

To fetch an SDR, first fetch the SDR header.  Once the size is known
the rest of the SDR can be fetched.

\section{Dealing with \acs{SDR} Repositories in OpenIPMI}

\acs{SDR}s can be rather difficult to deal with.  OpenIPMI hides most,
if not all, of the difficulty from the user.  It fetches the
\acs{SDR}s, decodes them, create entities and sensors as necessary,
and reports those to the user.  The user of OpenIPMI will not have to
know anything about \acs{SDR}s, in general.

The type used by OpenIPMI to hold an \acs{SDR} repository is
\verb=ipmi_sdr_info_t=.  The type used to hold individual SDRs is
\verb=ipmi_sdr_t=.  The internals of \verb=ipmi_sdr_info_t= are
opaque, you can only use functions to manipulate it.  The internals of
\verb=ipmi_sdr_t= are not (currently) opaque, you can access the
internals directly.

\subsection{Getting an SDR Repository}

If you need access to the SDRs for a system, you can get the main SDRs
by calling:

\begin{verbatim}
ipmi_sdr_t *ipmi_domain_get_main_sdrs(ipmi_domain_t *domain);
\end{verbatim}

You can get the \acs{SDR}s for an \acs{MC} with the following:

\begin{verbatim}
ipmi_sdr_t *ipmi_mc_get_sdrs(ipmi_domain_t *domain);
\end{verbatim}

These are the pre-fetched copies that OpenIPMI holds.  You can also
fetch your own copy of an \acs{SDR} repository using the following call to
create it:

\begin{verbatim}
int ipmi_sdr_info_alloc(ipmi_domain_t   *domain,
                        ipmi_mc_t       *mc,
                        unsigned int    lun,
                        int             sensor,
                        ipmi_sdr_info_t **new_sdrs);
\end{verbatim}

If you want the main \acs{SDR}s held on an MC, set the sensor value to
false (zero).  If you want the device \acs{SDR}s, set the value to
true (one).  After you allocate an SDR info structure, you can use the
following call to fetch it:

\begin{verbatim}
typedef void (*ipmi_sdrs_fetched_t)(ipmi_sdr_info_t *sdrs,
                                    int             err,
                                    int             changed,
                                    unsigned int    count,
                                    void            *cb_data);
int ipmi_sdr_fetch(ipmi_sdr_info_t     *sdrs,
                   ipmi_sdrs_fetched_t handler,
                   void                *cb_data);
\end{verbatim}

If you allocate your own \acs{SDR} info structure, you should destroy
it when you are done with it with the following call:

\begin{verbatim}
typedef void (*ipmi_sdr_destroyed_t)(ipmi_sdr_info_t *sdrs, void *cb_data);
int ipmi_sdr_info_destroy(ipmi_sdr_info_t      *sdrs,
                          ipmi_sdr_destroyed_t handler,
                          void                 *cb_data);
\end{verbatim}

Note that you should \emph{not} destroy an SDR repository you fetched
from the domain or \acs{MC}.  Those are managed by OpenIPMI; if you
destroy them you will cause problems.

Note that an \acs{SDR} repository from a \acs{MC} or domain is
dynamic; it may change because OpenIPMI rescans the \acs{SDR}s to make
sure they haven't changed.

\subsection{\acs{SDR} Repository Information}

General SDR info is available about the repository once the fetch is
complete.  The format of the functions to get them are all
\begin{verbatim}
int ipmi_sdr_get_xxx(ipmi_sdr_info_t *sdr, int *val);
\end{verbatim}
where the \verb=xxx= is replaced by the item you wish to get.  Valid
items are:

\begin{longtable}{|p{.24\textwidth}|p{0.7\textwidth}|}
\hline
major\_version & The major IPMI version the SDR repository supports, like
        1 for IPMI 1.0 and 1.5, and 2 for IPMI 2.0.\\
\hline
minor\_version & The minor IPMI version the SDR repository supports, like
        0 for IPMI 1.0 and 2.0, and 5 for IPMI 1.5.\\
\hline
overflow & An SDR write operation has failed to do lack of space.\\
\hline
update\_mode & The update modes supported.  Valid values are:
        \begin{tightdefs}
        \item[00b] - unspecified
        \item[01b] - Only non-modal updates are supported
        \item[10b] - Only modal updates are supported
        \item[11b] - Both modal and non-modal updates are supported
        \end{tightdefs}\\
\hline
supports\_delete\_sdr & If true, the repository supports deleting individual
        \acs{SDR}s one at a time.\\
\hline
supports\_partial \_add\_sdr & If true, the repository supports the partial
        add command.\\
\hline
supports\_reserve\_sdr & If true, the repository supports using reservations.\\
\hline
supports\_get\_sdr \_repository \_allocation & If true, the repository allows
        allocation information to be fetched with the Get SDR Repository
        Allocation Info command.\\
\hline
dynamic\_population & If true, the \acs{IPMI} \emph{system} can dynamically
        change the
        contents of the SDR repository.  This may only be true for device
        SDR repositories.  Although main SDR repositories can dynamically
        change, it is not the system that does this, it is the user.\\
\hline
\end{longtable}

The following call can be used to tell whether sensors are available
on specific \acs{LUN}s.
\begin{verbatim}
int ipmi_sdr_get_lun_has_sensors(ipmi_sdr_info_t *sdr,
                                 unsigned int    lun,
                                 int             *val);
\end{verbatim}

\subsection{Handling a \acs{SDR} Repository}

Once you have an SDR repository, you can fetch individual SDRs from it
by the record id, type, or index.  To find out the number of SDRs
in the repository, use:
\begin{verbatim}
int ipmi_get_sdr_count(ipmi_sdr_info_t *sdr,
                       unsigned int    *count);
\end{verbatim}

Fetching the \acs{SDR}s by index is probably the most useful function;
it treats the repository as an array and lets you fetch items,
starting at zero.  The call is:
\begin{verbatim}
int ipmi_get_sdr_by_index(ipmi_sdr_info_t *sdr,
                          int             index,
                          ipmi_sdr_t      *return_sdr);
\end{verbatim}
If you are interested in a specific record number, you can fetch it
with:
\begin{verbatim}
int ipmi_get_sdr_by_type(ipmi_sdr_info_t *sdr,
                         int             type,
                         ipmi_sdr_t      *return_sdr);
\end{verbatim}
If you want to find the first \acs{SDR} of a given type, use the
following call:
\begin{verbatim}
int ipmi_get_sdr_by_type(ipmi_sdr_info_t *sdr,
                         int             type,
                         ipmi_sdr_t      *return_sdr);
\end{verbatim}
To get all the \acs{SDR}s, use the following:
\begin{verbatim}
int ipmi_get_all_sdrs(ipmi_sdr_info_t *sdr,
                      int             *array_size,
                      ipmi_sdr_t      *array);
\end{verbatim}
Your passed in array will be filled with the SDR data.  The int
pointed to by \verb=array_size= must be set to the number of available
elements in \verb=array=.  It will be modified to be the actual
number of \acs{SDR}s put into the array.  If the array is not big
enough to hold all the \acs{SDR}s, the call will fail and have no
effect.

%---------------------------------------------------------------------
\chapter{Entities}
\label{chap-entities}

Though you might not know it from a cursory reading of the \ac{IPMI}
spec, entities are an important part of IPMI.  They define what a
sensor (and in OpenIPMI, a control) monitors (or controls).  They are,
in essence, the physical parts of the system.  For instance, if a
system has a temperature sensor on the processor and another
temperature sensor on the main board, the temperature sensors will be
attached to the processor entity and board entity, respectively.  This
way, you can tell what the sensor monitors.

Entities are defined by two numbers, the entity id and the entity
instance.  The entity id defines the type of thing, such as a power
supply, processor, board, or memory.  The entity instance defines the
instance of the thing.  For instance, a system may have 4 DIMMs.  Each
of these DIMMs would be the same entity id (memory), but they would
each have a different instance.  From now on these are referred to as
($<$entity id$>$,$<$entity instance$>$).  For example, entity (3,1)
would be the first processor in the system.

\ac{IPMI} defines two types of entities: system-relative and
device-relative.  System-relative entities are unique throughout the
entire system (the domain, in OpenIPMI terms).  Thus if sensors on
different \acs{MC}s referred entity (3,1), they would all be referring
to exactly the same physical thing.  System-relative entity instances
are defined to be less than 96.

Device-relative entities are unique on the management controller that
controls them.  These entity's instances are numbered 96-128.  These
are referred to using their channel and IPMB address in the form
r($<$channel$>$,$<$IPMB$>$,$<$entity id$>$,$<$entity instance$>$-96).  For
instance, if an \acs{MC} at address C0h had a sensor on channel 0 that
monitored entity id 3, instance 97, that would be r(0,C0,3,1)

Entities may or may not have specific information describing them.
Entities that do have specific information describing them have device
locator records.

Entity IDs defined by \ac{IPMI} are:

\begin{longtable}{|l|p{0.30\textwidth}|p{0.50\textwidth}|}
\hline
\bfseries{\#} & \bfseries{Name} & \bfseries{description}\\
\hline
 0 & UNSPECIFIED & The entity id is not used.\\
\hline
 1 & OTHER & Something else?\\
\hline
 2 & UNKOWN & It's hard to understand why the entity id wouldn't be
        known, but this is defined by the spec.\\
\hline
 3 & PROCESSOR & A processor\\
\hline
 4 & DISK & A disk or disk bay\\
\hline
 5 & PERIPHERAL & A peripheral bay\\
\hline
 6 & SYSTEM\_MANAGEMENT \_MODULE & A separate board for system management\\
\hline
 7 & SYSTEM\_BOARD & The main system board\\
\hline
 8 & MEMORY\_MODULE & A memory module (a DIMM, for instance)\\
\hline
 9 & PROCESSOR \_MODULE & A device that holds processors, if they are not
        mounted on the system board.  This would generally be a socket.\\
\hline
10 & POWER\_SUPPLY & The main power supplies for the system use this.\\
\hline
11 & ADD\_IN\_CARD & A plug-in card in a system, a PCI card for instance.\\
\hline
12 & FRONT\_PANEL \_BOARD & A front panel display and/or control panel.\\
\hline
13 & BACK\_PANEL\_BOARD & A rear panel display and/or control panel.\\
\hline
14 & POWER\_SYSTEM \_BOARD & A board that power supplies plug in to\\
\hline
15 & DRIVE\_BACKPLANE & A board that disk drives plug in to\\
\hline
16 & SYSTEM\_INTERNAL \_EXPANSION\_BOARD & A board that contains expansion
        slots.  A PCI riser board, for instance.\\
\hline
17 & OTHER\_SYSTEM \_BOARD & Some other board in the system.\\
\hline
18 & PROCESSOR\_BOARD & A separate board that holds one or more processors.\\
\hline
19 & POWER\_UNIT & A logical grouping for a set of power supplies\\
\hline
20 & POWER\_MODULE & Used for internal DC-to-DC converters, like one that
        is on a board.  Note that you would \emph{not} use this for the
        main power supply in a system, even it it was a DC-to-DC converter.\\
\hline
21 & POWER\_MANAGEMENT \_BOARD & A board for managing and distributing
        power in the system\\
\hline
22 & CHASSIS\_BACK \_PANEL\_BOARD & A rear board in a chassis.\\
\hline
23 & SYSTEM\_CHASSIS & The main chassis in the system.\\
\hline
24 & SUB\_CHASSIS & A sub-unit of the main chassis.\\
\hline
25 & OTHER\_CHASSIS \_BOARD & Some other board that doesn't fit the
        given categories.\\
\hline
26 & DISK\_DRIVE\_BAY & A sub-chassis that holds a set of disk drives.\\
\hline
27 & PERIPHERAL\_BAY & A sub-chassis that holds a set of peripherals.\\
\hline
28 & DEVICE\_BAY & A sub-chassis that holds a set of devices.  The
        difference between a peripheral and a device is not known.\\
\hline
29 & FAN\_COOLING & A fan or other cooling device.\\
\hline
30 & COOLING\_UNIT & A group of fans or other cooling devices.\\
\hline
31 & CABLE \_INTERCONNECT & A cable routing device.\\
\hline
32 & MEMORY\_DEVICE & A replaceable memory device, like a DIMM.  This should
        not be used for individual memory chips, but for the board that
        holds the memory chips.\\
\hline
33 & SYSTEM\_MANAGEMENT \_SOFTWARE & The meaning of this is unknown.\\
\hline
34 & BIOS & The BIOS running on the system.\\
\hline
35 & OPERATING\_SYSTEM & The operating system running on the system.\\
\hline
36 & SYSTEM\_BUS & The main interconnect bus in a system.\\
\hline
37 & GROUP & A generic grouping of entities if no physical thing groups
        them but they need to be groups.\\
\hline
38 & REMOTE\_MGMT \_COMM\_DEVICE & A communication device used for
        remote management.\\
\hline
39 & EXTERNAL \_ENVIRONMENT & The environment outside the chassis.  For
        instance, a temperature sensor outside the chassis that monitored
        external temperature would use this.  Different instances may be
        used to specify different regions outside the box.\\
\hline
40 & BATTERY & A battery\\
\hline
41 & PROCESSING\_BLADE & A single-board computer, generally a board that
        has one or more processors, memory, etc. that plugs into a
        backplane.\\
\hline
42 & CONNECTIVITY\_SWITCH & A network switch that plugs into a system
        to provide connectivity between independent processors in a
        system.\\
\hline
43 & PROCESSOR\_MEMORY \_MODULE & ?\\
\hline
44 & IO\_MODULE & ?\\
\hline
45 & PROCESSOR\_IO \_MODULE & ?\\
\hline
46 & MGMT\_CONTROLLER \_FIRMWARE & The firmware running on an \ac{MC}.\\
\hline
\end{longtable}

\section{Discovering Entities}
In OpenIPMI, the entities in a system are part of the domain.  As
OpenIPMI scans \acs{SDR}s it finds, it will create the entities
referenced in those SDRs.  The user can discover the entities in a
domain in two ways: iterating or registering callbacks.

Iterating the entities in a domain simply involves calling the
iterator function with a callback function:

\begin{verbatim}
static void
handle_entity(ipmi_entity_t *entity, void *cb_data)
{
  my_data_t *my_data = cb_data;
  /* Process the entity here */
}

void
iterate_entities(ipmi_domain_t *domain, my_data_t *my_data)
{
  int rv;
  rv = ipmi_domain_iterate_entities(domain, handle_entity, my_data);
  if (rv)
    handle_error();
}
\end{verbatim}

This is relatively simple to do, but you will not be able to know
immediately when new entities are added to the system.  To know that,
you must register a callback function as follows:

\begin{verbatim}
static void
handle_entity(enum ipmi_update_e op,
              ipmi_domain_t *domain,
              ipmi_entity_t *entity,
              void *cb_data)
{
  my_data_t *my_data = cb_data;
  /* Process the entity here */
}

void
handle_new_domain(ipmi_domain_t *domain, my_data_t *my_data)
{
  int rv;
  rv = ipmi_domain_add_entity_update_handler(domain, handle_entity, my_data);
  if (rv)
    handle_error();
}
\end{verbatim}

You should call the function to add an entity update handler when the
domain is reported up (or even before); that way you will not miss any
entities.

\section{Entity Containment and OpenIPMI}

Entities may be contained inside other entities.  For instance, a
chassis may contain a board, and a board may have a processor on it.
This is expressed in specific entity \acs{SDR}s.  OpenIPMI represents
this by entities having children and parents.

To discover the parents of an entity, they may be iterated.  It seems
possible for an entity to have more than one parent; there is no
direct prohibition of this in \acs{IPMI}, although it would be a
little wierd.  To iterate the parents, use the following call:
\begin{verbatim}
typedef void (*ipmi_entity_iterate_parent_cb)(ipmi_entity_t *ent,
                                              ipmi_entity_t *parent,
                                              void          *cb_data);
void ipmi_entity_iterate_parents(ipmi_entity_t                 *ent,
                                 ipmi_entity_iterate_parent_cb handler,
                                 void                          *cb_data);
\end{verbatim}

Similarly, an entity may have children, but it is certain that more
than one child is allowed.  To iterate entities children, use the
following call:
\begin{verbatim}
typedef void (*ipmi_entity_iterate_child_cb)(ipmi_entity_t *ent,
                                             ipmi_entity_t *child,
                                             void          *cb_data);
void ipmi_entity_iterate_children(ipmi_entity_t                *ent,
                                  ipmi_entity_iterate_child_cb handler,
                                  void                         *cb_data);
\end{verbatim}

To discover if an entity is a child (has parent entities) or is a
parent (has child entities), you may use the following calls:
\begin{verbatim}
int ipmi_entity_get_is_child(ipmi_entity_t *ent);
int ipmi_entity_get_is_parent(ipmi_entity_t *ent);
\end{verbatim}

\section{Entity Presence}

An entity identified in an \acs{SDR} may or may not be present in the
system.  \acs{IPMI} specifies an algorithm for detecting whether an
entity is present.  Unfortunately, this algorithm is extremely
complicated. The algorithm is given in stages:
\begin{itemize}
\item If the entity has a presence sensor attached (sensor type 25h)
  or a bit in some sensor that is attached to it that shows presence
  (sensor type 21h bit 02h, sensor type 08h bit 00h, or sensor type
  29h bit 02h), that sensor should always be present and will tell if
  the entity is present.  A presence sensor or bit will override all
  other entity detection methods; it directly tells if the entity is
  present or not.
\item If a \acs{FRU} device for the entity is specified and is
  operational, then the entity is present.
\item The entity is present if at least one sensor is available and
  scanning is enabled on that sensor.
\item The entity is present if the entity is a parent entity and at
  least one of its children is present.
\item Otherwise the entity is not present.
\end{itemize}

Entity presence may also affect whether the sensors attached to the
entity are present.  The sensor \acs{SDR}s have a flag that specifies
whether the sensor is present even if the entity is not present.

\subsection{Entity Presence in OpenIPMI}
OpenIPMI handles detection of entity presence for the user.  If you
have an entity pointer or entity id, you can directly query to see if
the entity is present using:
\begin{verbatim}
int ipmi_entity_is_present(ipmi_entity_t *ent);
int ipmi_entity_id_is_present(ipmi_entity_id_t id, int *present);
\end{verbatim}

If you need to know when an entity becomes present or absent, you may
use the following callback registration:
\begin{verbatim}
typedef int (*ipmi_entity_presence_change_cb)(ipmi_entity_t *entity,
                                              int           present,
                                              void          *cb_data,
                                              ipmi_event_t  *event);
int ipmi_entity_add_presence_handler(ipmi_entity_t                  *ent,
                                     ipmi_entity_presence_change_cb handler,
                                     void                           *cb_data);
int ipmi_entity_remove_presence_handler
(ipmi_entity_t                  *ent,
 ipmi_entity_presence_change_cb handler,
 void                           *cb_data);
\end{verbatim}
This is a standard event handler as defined in
section~\vref{sec-openipmi-events}.

\section{Entity Types and Info}
Entities come in four different flavors:
\begin{description}
\item[\acs{MC}] - An \acs{MC} entity is for a \acs{MC}.
\item[FRU] - This is for field-replaceable entities that are
  not \acs{MC}s.
\item[Generic] - Some other device on the \acs{IPMB} bus.
\item[Unknown] - This is for entities that do not have an \acs{SDR}
  record to identify them.  These entities are generally only
  referenced in sensor records or in entity association records.
\end{description}

The following call returns the entity type:
\begin{verbatim}
enum ipmi_dlr_type_e ipmi_entity_get_type(ipmi_entity_t *ent);
\end{verbatim}
Valid entity types are:
\begin{tightdefs}
\item[IPMI\_ENTITY\_UNKNOWN]
\item[IPMI\_ENTITY\_MC]
\item[IPMI\_ENTITY\_FRU]
\item[IPMI\_ENTITY\_GENERIC]
\end{tightdefs}

There are calls to fetch information about entities, but only certain
calls are available for certain entities.  All these calls have the
form:
\begin{verbatim}
int ipmi_entity_get_xxx(ipmi_entity_t *ent);
\end{verbatim}
where \verb=xxx= is the data item.  These will not return errors, they
will return undefined information if they are called on an entity that
does not support the specific data item.  The data items supported are:

\begin{longtable}{|p{.20\textwidth}|p{.56\textwidth}|c|c|c|c|}
\hline
\bfseries{Data Item} & \bfseries{Description} & \bfseries{M} & \bfseries{F}
  & \bfseries{G} & \bfseries{U}\\
\hline
is\_fru & This will be true if the item has \acs{FRU} information
        & x & x & x & x\\
\hline
entity\_id & This will be the entity id of the entity.
        & x & x & x & x\\
\hline
entity\_instance & This will be the entity instance of the entity.
        & x & x & x & x\\
\hline
device\_channel & This is the device channel for the entity.  It is
        only useful if the entity instance is device-relative.  See
        section~\ref{chap-entities} for more details.
        & x & x & x & x\\
\hline
device\_address & This is the \acs{IPMB} address for the entity.  It is
        only useful if the entity instance is device-relative.  See
        section~\ref{chap-entities} for more details.
        & x & x & x & x\\
\hline
presence\_sensor \_always\_there & If this is true, then the entity has
        a presence sensor or a presence bit sensor and that sensor is
        always present.
        & x & x & x & x\\
\hline
channel & The channel number for the entity.  This is different than
        device\_channel because it is the actual value from the \acs{SDR},
        not the value from the entity info.
        & x & x & x &  \\
\hline
lun & The \acs{LUN} from the SDR.
        & x & x & x &  \\
\hline
oem & The entity SDRs have an \acs{OEM} field that may be fetched with this
        call.  The meaning of this is system dependent.
        & x & x & x &  \\
\hline
access\_address & The \acs{IPMB} address of the \acs{MC} the entity is on
        or is represented by.
        &   & x & x &  \\
\hline
private\_bus\_id & The FRU information may be on an \acs{EEPROM} device on
        a private bus.  If so, 
        &   & x & x &  \\
\hline
device\_type & The type of \acs{I$^2$C} device.  This is really not very
        important, but these are defined in the IPMI spec.
        &   & x & x &  \\
\hline
device\_modifier & An extension to the device\_type field to further refine
        the device type.
        &   & x & x &  \\
\hline
slave\_address & The IPMB address of the device on the IPMB.
        & x &   & x &  \\
\hline
is\_logical\_fru & Tells if the FRU information on the FRU is accessed
        through an \ac{MC} (value is 1) or is access directly on the
        IPMB bus as a EEPROM (value is 0).
        &   & x &   &  \\
\hline
ACPI\_system\_power \_notify\_required & If true, ACPI system power state
        notification is required for the device.
        & x &   &   &  \\
\hline
ACPI\_device\_power \_notify\_required & If true, ACPI device power syste
        notification is required by the device.
        & x &   &   &  \\
\hline
controller\_logs\_init \_agent\_errors & If true, the \acs{MC} logs
        initialization errors.
        & x &   &   &  \\
\hline
log\_init\_agent\_errors \_accessing & If this is true, then the
        initialization agent will log any failures trying to set
        the event receiver for the device.
        & x &   &   &  \\
\hline
global\_init & Tells the initialization agent whether to initialize
        the controller's event receiver.  This is a two bit value:
        \begin{tightdefs}
        \item[00b] - Enable the controller's event receiver.
        \item[01b] - Disable the controller's event receiver by setting it
          to FFh.  This is generally to turn of a rogue controller or
          for debugging.
        \item[10b] - Do not initialize the controller's event receiver.
          this is generally for debugging.
        \item[11b] - reserved
        \end{tightdefs}
        & x &   &   &  \\
\hline
chassis\_device & The controller handles the chassis commands.
        & x &   &   &  \\
\hline
bridge & The controller handles bridge commands.  This generally means it
        supports \acs{ICMB}.
        & x &   &   &  \\
\hline
IPMB\_event \_generator & The controller generates events on the \acs{IPMB}.
        & x &   &   &  \\
\hline
IPMB\_event\_receiver & The controller can receive events on the \acs{IPMB}.
        & x &   &   &  \\
\hline
FRU\_device \_inventory & The controller supports \acs{FRU} inventory commands.
        & x &   &   &  \\
\hline
SEL\_device & The controller supports a \acs{SEL} device for storing events.
        & x &   &   &  \\
\hline
SDR\_repository \_device & The controller supports a main \acs{SDR} repository.
        & x &   &   &  \\
\hline
sensor\_device & The controller has sensors, it supports the sensor commands.
        & x &   &   &  \\
\hline
get\_address\_span & The number of additional consecutive slave addresses
        used by the device.  For instance, if the address is C0h and this
        value is zero, then it is only at C0h.  If this value was one, then
        it would be at C0h and C2h.
        &   &   & x &  \\
\hline
\end{longtable}

In addition, a string value for the entity id may be fetched.  This is
not quite the same as the entity id, because \acs{OEM} code may set
this string to a different value than the default, especially for OEM
entity ids.  The function is:

\begin{verbatim}
char *ipmi_entity_get_entity_id_string(ipmi_entity_t *ent);
\end{verbatim}

The id (the string name in the SDR) can also be fetched using the
following calls:

\begin{verbatim}
int ipmi_entity_get_id_length(ipmi_entity_t *ent);
enum ipmi_str_type_e ipmi_entity_get_id_type(ipmi_entity_t *ent);
int ipmi_entity_get_id(ipmi_entity_t *ent, char *id, int length);
\end{verbatim}

See section~\ref{appendix-ipmi-strings} for details on this.

\section{Sensor and Controls in an Entity}
In OpenIPMI, entities contain sensors and controls.  If a sensor or
control is associated with an entity, that sensor or control will be
contained inside the entity in OpenIPMI.

To find the sensors in an entity, you can iterate them using the
function:
\begin{verbatim}
typedef void (*ipmi_entity_iterate_sensor_cb)(ipmi_entity_t *ent,
                                              ipmi_sensor_t *sensor,
                                              void          *cb_data);
void ipmi_entity_iterate_sensors(ipmi_entity_t                 *ent,
                                 ipmi_entity_iterate_sensor_cb handler,
                                 void                          *cb_data);
\end{verbatim}
The ``handler'' function will be called with each sensor in the
entity.  Controls have a similar function:
\begin{verbatim}
typedef void (*ipmi_entity_iterate_control_cb)(ipmi_entity_t  *ent,
                                               ipmi_control_t *control,
                                               void           *cb_data);
void ipmi_entity_iterate_controls(ipmi_entity_t                  *ent,
                                  ipmi_entity_iterate_control_cb handler,
                                  void                           *cb_data);
\end{verbatim}

So, for instance, if you wanted to print the name and entity id string
of every sensor in an entity, you might have code that looks like:
\begin{verbatim}
static void
handle_sensor(ipmi_entity_t *ent,
              ipmi_sensor_t *sensor,
              void          *cb_data)
{
    char *name;
    int  length = ipmi_sensor_get_id_length(sensor);
    int  allocated = 0;

    if (length == 0)
        name = "empty name";
    else {
        name = malloc(length+1);
        if (!name) {
            /* Handle error */
            return;
        }
        allocated = 1;
        length = ipmi_sensor_get_id(sensor, name, length);
    }
    printf("Sensor %s\n", name);
    if (allocated)
        free(name);
}

void
print_sensors(ipmi_entity_t *entity)
{
    ipmi_entity_iterate_sensors(entity, handle_sensor, NULL);
}
\end{verbatim}

However, you probably want to know about the sensors and controls as
soon as they are created or destroyed.  To do this, you can add
callback functions to the entity to call you whenever a sensor or
control is added to the entity or deleted from the entity.  The
following functions allow the user to watch sensors in a domain:
\begin{verbatim}
typedef void (*ipmi_entity_sensor_cb)(enum ipmi_update_e op,
                                      ipmi_entity_t      *ent,
                                      ipmi_sensor_t      *sensor,
                                      void               *cb_data);
int ipmi_entity_add_sensor_update_handler(ipmi_entity_t         *ent,
                                          ipmi_entity_sensor_cb handler,
                                          void                  *cb_data);
int ipmi_entity_remove_sensor_update_handler(ipmi_entity_t         *ent,
                                             ipmi_entity_sensor_cb handler,
                                             void                  *cb_data);
\end{verbatim}
Likewise, the following function are for controls:
\begin{verbatim}
typedef void (*ipmi_entity_control_cb)(enum ipmi_update_e op,
                                       ipmi_entity_t      *ent,
                                       ipmi_control_t     *control,
                                       void               *cb_data);
int ipmi_entity_add_control_update_handler(ipmi_entity_t          *ent,
                                           ipmi_entity_control_cb handler,
                                           void                   *cb_data);
int ipmi_entity_remove_control_update_handler(ipmi_entity_t          *ent,
                                              ipmi_entity_control_cb handler,
                                              void                   *cb_data);
\end{verbatim}
The add functions should generally be called in the callback that
reports the new entity, that way you will not miss any controls or
sensors as they are added.  On removal, both the handler and the
cb\_data values must match the values in the add handler, the cb\_data
value is not use for a callback but to find the specific item to
remove.

As an example, the following code reports the sensor name and whether
it was added, removed, or changed:
\begin{verbatim}
static void
handle_sensor(enum ipmi_update_e op,
              ipmi_entity_t      *ent,
              ipmi_sensor_t      *sensor,
              void               *cb_data)
{
    char *name;
    int  length = ipmi_sensor_get_id_length(sensor);
    int  allocated = 0;

    if (length == 0)
        name = "empty name";
    else {
        name = malloc(length+1);
        if (!name) {
            /* Handle error */
            return;
        }
        allocated = 1;
        length = ipmi_sensor_get_id(sensor, name, length);
    }
    printf("Sensor %s\n", name);
    if (allocated)
        free(name);
}

void
print_sensors(ipmi_entity_t *entity)
{
    ipmi_entity_iterate_sensors(entity, handle_sensor, NULL);
}
\end{verbatim}

\section{Entity Hot-Swap}

OpenIPMI supports the notion of an entity being hot-swapped.  It
supports a complete state machine that allows insertion to be
detected, requests to power on the entity and requests to power off
the entity.  These requests generally come from the user in the form
of a switch or something of that nature.  It also supports a subset of
the hot-swap state machine if all these features are not available.

Unfortunately, IPMI does not have this concept, so this must be added
by OEM code.  Several systems that support hot-swap are available in
OpenIPMI, including the Motorola MXP (see
appendix~\vref{app-motorola-mxp}) and chassis that adhere to the PICMG
\acs{ATCA} standard (see appendix~\vref{app-atca}).

Not all entities are hot-swappable.  If an entity is hot-swappable,
the function:
\begin{verbatim}
int ipmi_entity_hot_swappable(ipmi_entity_t *ent);
\end{verbatim}
will return true.

\subsection{Hot-Swap State}
OpenIPMI supports eight hot-swap states:
\begin{tightdefs}
\item IPMI\_HOT\_SWAP\_NOT\_PRESENT
\item IPMI\_HOT\_SWAP\_INACTIVE
\item IPMI\_HOT\_SWAP\_ACTIVATION\_REQUESTED
\item IPMI\_HOT\_SWAP\_ACTIVATION\_IN\_PROGRESS
\item IPMI\_HOT\_SWAP\_ACTIVE
\item IPMI\_HOT\_SWAP\_DEACTIVATION\_REQUESTED
\item IPMI\_HOT\_SWAP\_DEACTIVATION\_IN\_PROGRESS
\item IPMI\_HOT\_SWAP\_OUT\_OF\_CON
\end{tightdefs}
These may be converted to a string name with the function:
\begin{verbatim}
char *ipmi_hot_swap_state_name(enum ipmi_hot_swap_states state);
\end{verbatim}

Figure~\vref{fig-simple-hot-swap-state-machine} shows a simple
hot-swap state machine for an entity that only supports presence.  In
effect, the entity is either not present or present.
\begin{figure}
\begin{center}
\includegraphics[width=.4\textwidth]{SimpleHotSwap.eps}
\end{center}
\caption{\label{fig-simple-hot-swap-state-machine}Simple Hot-Swap
  state machine}
\end{figure}

Figure~\vref{fig-complex-hot-swap-state-machine} shows a more complex
hot-swap state machine.  This would be used for an entity that
supported some type of power control (the entity can be present but
inactive).
\begin{figure}
\begin{center}
\includegraphics[width=\textwidth]{ComplexHotSwap.eps}
\end{center}
\caption{\label{fig-complex-hot-swap-state-machine}Complex Hot-Swap
  state machine}
\end{figure}
Upon insertion, the entity will move from not present to inactive.  If
the entity supports some type of activation request, it will move from
inactive to activation requested when that occurs.  If it does not
support an activation request, it will move to either activation in
progress (if the activation requires some time to occur) or directly
to active when the entity is activated.  The move from activation
requested to activation in progress or active occurs when the entity
is activated.

The entity will move to deactivation requested if the entity supports
that and the operator requests a deactivation.  In active or
deactivation requested, the entity will move to deactivation in
progress (or directly to inactive if deactivation is immediate) upon
the entity being deactivated.  Although it is not shown in the
diagram, the activation in progress can go to the deactivation states
just like the active state; it confused the diagram too much to show
this.

Note that any state can go to not present.  This is called a suprise
extraction; it occurs if the operator does not follow the hot-swap
extraction procedure and just pulls the board.  The state may also go
from any state to out of communication.  This occurs if the board is
present (or the board presence cannot be detected) and the system
looses communication with the entity.  If communication is restored,
the entity goes to the current state it is in.  Some systems may
support some manual means to move the entity's state to not present.

When a hot-swap device is inserted, it may or may not be automatically
activated.  This depends on the policies and capabilities of the
chassis where the device is inserted.  The device may be deactivated
automatically upon a request if that policy is supported by the
system.

The following function will allow the current hot-swap state to be
fetched:
\begin{verbatim}
typedef void (*ipmi_entity_hot_swap_state_cb)(ipmi_entity_t             *ent,
                                              int                       err,
                                              enum ipmi_hot_swap_states state,
                                              void                   *cb_data);
int ipmi_entity_get_hot_swap_state(ipmi_entity_t                 *ent,
                                   ipmi_entity_hot_swap_state_cb handler,
                                   void                          *cb_data);
\end{verbatim}

\subsection{Hot-Swap Events}

It is possible to register to receive hot-swap changes when the occur.
The following functions do the registration and deregistraction of a
hot-swap handler:
\begin{verbatim}
typedef int (*ipmi_entity_hot_swap_cb)(ipmi_entity_t             *ent,
                                       enum ipmi_hot_swap_states last_state,
                                       enum ipmi_hot_swap_states curr_state,
                                       void                      *cb_data,
                                       ipmi_event_t              *event);
int ipmi_entity_add_hot_swap_handler(ipmi_entity_t           *ent,
                                     ipmi_entity_hot_swap_cb handler,
                                     void                    *cb_data);
int ipmi_entity_remove_hot_swap_handler(ipmi_entity_t           *ent,
                                        ipmi_entity_hot_swap_cb handler,
                                        void                    *cb_data);
\end{verbatim}
This is a standard event handler as described in
section~\vref{sec-openipmi-events}

\subsection{Hot-Swap Activation and Deactivation}

Devices that have the ability to control power and request power up or
removal have some special handling that may be required.  Note that
some systems may only support a subset of these operations, reference
the documentation for the system for more details.

When a device is inserted that has these capabilities, there is
generally some way to signal that the device is ready to be powered
up.  In \acs{ATCA}, for instance, the operator will insert the card and the
entity for the card will go from not present to inactive state.  When
the operator closes the lock-latch, that signals the system to go to
activation requested state.

If a device is in the inactive state, the management software using
OpenIPMI can use the following function to force it into activation
requested state:
\begin{verbatim}
int ipmi_entity_set_activation_requested(ipmi_entity_t  *ent,
                                         ipmi_entity_cb done,
                                         void           *cb_data);
\end{verbatim}
This can occur if an entity has been moved to the inactive state by
the management software then the entity needs to be powered up again.
If an entity is sitting in the inactive state but does not support
this, then this call will return \verb=ENOSYS= and the entity can be
moved directly to active state.

To move an entity to active state (either from inactive or activation
requested state), use the following function:
\begin{verbatim}
int ipmi_entity_activate(ipmi_entity_t  *ent,
                         ipmi_entity_cb done,
                         void           *cb_data);
\end{verbatim}
This will power the entity up and move it to active state.

Deactivation is similar, but not quite the same.  The operator
directly working on the device can request a removal using some
mechanism.  In \acs{ATCA}, for instance, the operator can open the lock
latch on the card and the card entity will move from active to
deactivation requested state.  Note that unlike activation, there is
no way for system management software to request a move to
deactivation requested state.  It's not really required, since it can
request that the entity go directly to inactive state.

To move from either active (or really any state in the activation
process) or deactivation requested state to inactive state, the
function:
\begin{verbatim}
int ipmi_entity_deactivate(ipmi_entity_t  *ent,
                           ipmi_entity_cb done,
                           void           *cb_data);
\end{verbatim}
is used.

\subsection{Auto Activation and Deactivation}
Some systems allow the system management software to specify a policy
to execute when a device is inserted or a removal is requested.
Basically, the time from an activate request to when an activation is
automatically started can be specified.  The time from a deactivate
request to when an deactivation is automatically started can be
specified.  The following functions can be used to read and update
these times:
\begin{verbatim}
int ipmi_entity_get_auto_activate_time(ipmi_entity_t       *ent,
                                       ipmi_entity_time_cb handler,
                                       void                *cb_data);
int ipmi_entity_set_auto_activate_time(ipmi_entity_t  *ent,
                                       ipmi_timeout_t auto_act,
                                       ipmi_entity_cb done,
                                       void           *cb_data);
int ipmi_entity_get_auto_deactivate_time(ipmi_entity_t       *ent,
                                         ipmi_entity_time_cb handler,
                                         void                *cb_data);
int ipmi_entity_set_auto_deactivate_time(ipmi_entity_t  *ent,
                                         ipmi_timeout_t auto_deact,
                                         ipmi_entity_cb done,
                                         void           *cb_data);
\end{verbatim}
The timeouts are standard OpenIPMI time values, which are in
nanoseconds.  These will return \verb=ENOSYS= if the operation is not
supported.  They will return \verb=EINVAL= if the time is out of
range.  To disable auto-activation and deactiviation, the time may be
set to \verb=IPMI_TIMEOUT_FOREVER=.  To cause the transitions to occur
immediately, set the value to \verb=IPMI_TIMEOUT_NOW=.

\section{\acs{FRU} Data}

OpenIPMI supports fetching all the \acs{FRU} data supported by the
IPMI spec, as well as \acs{SPD} data in DRAMs.  It also supports
plugins for handling other types of \acs{FRU} data that can be
provided for \acs{OEM} data.  It is able to fetch and modify all the
standard data and all the custom data stored in multi-records and has
a multirecord decoder plugin interface with the standard multirecords
implements, along with some \acs{ATCA} record decoders.  \acs{SPD} data (and
other data types, unless they provide their own interfaces) can only
be decoded.  Standard \acs{FRU} data specified by the \acs{IPMI} spec
can be decoded and written.

\subsection{Reading \acs{FRU} Data}

The \acs{FRU} data interface has two separate interfaces fetching data
data from a \acs{FRU} data object.  One is a generic interface that
works with all \acs{FRU} data type, including \acs{SPD} or \acs{OEM}
data.  The other is an \acs{IPMI}-specified FRU interface that only works
with the FRU data format specified by \acs{IPMI}.

\subsubsection{Generic \acs{FRU} Data Interface}
\label{generic-fru-data-interface}

The generic \acs{FRU} interface represents the \acs{FRU} data as a
tree-structured hierarchy of data.  Each level of the tree has a
``node''.  The fields in a node are indexed by number and may contain
both data elements and sub-nodes.

Two types of nodes exist.  A record node is a set of named fields.
The ``name'' of each field will be returned and the ``intval'' when
the node itself is fetched will be $-1$.  An array node contains a set
of unnamed elements.  The ``name'' of each field will be returned as
\verb=NULL= and the ``intval'' will be the number of elements in the
array.

The nodes are refcounted.  If you are given a node, you must free the
node using \verb=ipmi_fru_put_node()= when you are done with it.

To fetch the root node of a \acs{FRU} data object, use the function:
\begin{verbatim}
int ipmi_fru_get_root_node(ipmi_fru_t      *fru,
			   const char      **name,
			   ipmi_fru_node_t **node);
\end{verbatim}
This function returns the name of the FRU, either ``SPD FRU'' or
``standard FRU'' or some other OEM name and the actual root node.  If
either of these is NULL, it will be ignored.  The root node is always
a record node.

To fetch individual fields from a record, use:
\begin{verbatim}
int ipmi_fru_node_get_field(ipmi_fru_node_t           *node,
			    unsigned int              index,
			    const char                **name,
			    enum ipmi_fru_data_type_e *dtype,
			    int                       *intval,
			    time_t                    *time,
			    double                    *floatval,
			    char                      **data,
			    unsigned int              *data_len,
			    ipmi_fru_node_t           **sub_node);
\end{verbatim}
The index is a contiguous range from zero that holds every field.  So
you can iterate through the indexes from 0 until it returns EINVAL to
find all the fields.  If a field is not present in the \acs{FRU} data,
this will return \verb=ENOSYS=.  Note that later fields may still be
present.

The \verb=name= returns the string name for the index.  Note that the
indexes may change between release, so don't rely on absolute numbers.
The names will remain the same, so you can rely on those.

The \verb=dtype= field will be set to the data type.  The following
values are returned:
\begin{description}
\item \texttt{IPMI\_FRU\_DATA\_INT} sets \verb=intval=
\item \texttt{IPMI\_FRU\_DATA\_TIME} sets \verb=time=
\item \texttt{IPMI\_FRU\_DATA\_ASCII} sets \verb=data= and \verb=data_len=
\item \texttt{IPMI\_FRU\_DATA\_BINARY} sets \verb=data= and \verb=data_len=
\item \texttt{IPMI\_FRU\_DATA\_UNICODE} sets \verb=data= and \verb=data_len=
\item \texttt{IPMI\_FRU\_DATA\_BOOLEAN} sets \verb=intval=
\item \texttt{IPMI\_FRU\_DATA\_FLOAT} sets \verb=floatval=
\item \texttt{IPMI\_FRU\_DATA\_SUB\_NODE} sets \verb=sub_node=.
  \verb=intval= will be -1 if it is not an array, or the array length if it
  is an array.
\end{description}
Note that if data is returned in \verb=data=, you must free the data
when you are done with \verb=ipmi_fru_data_free()=.

Any of the return values may be passed \verb=NULL= to ignore the data.

Printing all the \acs{FRU} data or searching for a data item by name
can easily be accomplished using recursion.

\subsubsection{\acs{IPMI}-specific \acs{FRU} Data Interface}

The generic interface should be used for applications that only read
the FRU data.  For applications that also write the data, another
interface is available that allows individual data items to be
specifically addressed and modified and the data areas of the \acs{FRU}
data to be modified, if they need to be resized, created, or deleted.

\paragraph{\acs{IPMI} \acs{FRU} Data Organization}

\acs{FRU} data is organized into areas, and the areas are organized into
fields.  The areas are:

\begin{description}
\item[internal\_use]
\item[chassis\_info]
\item[board\_info]
\item[product\_info]
\item[multi\_record]
\end{description}

An area may or may not be present.  An area, if present, may have
required fields and ``custom'' fields.  The required fields can be
fetched by name, the custom fields are fetched by index number.  Note
that you don't need to know anything about areas if you are just
fetching data from the \acs{FRU}, but you need to know about them to
modify FRU data.

There are a very large number of FRU variables and they are fairly
well defined in the \acs{IPMI} \acs{FRU} document; see that document
and the \verb=ipmiif.h= include file for details on the \acs{FRU}
data.

\paragraph{Fetching \acs{FRU} Data from a \acs{FRU}}

Some fields are integers, some are time values, and some are strings.
Each type has its own fetch type.  The integer and time values only
return the one value that is returned.

The string functions have a ``type'' function, a ``len'' function, and
a function to actually get the strings.  For instance:
\begin{verbatim}
int ipmi_fru_get_chassis_info_part_number_len(ipmi_entity_t *entity,
                                              unsigned int  *length);
int ipmi_fru_get_chassis_info_part_number_type(ipmi_entity_t        *entity,
                                               enum ipmi_str_type_e *type);
int ipmi_fru_get_chassis_info_part_number(ipmi_entity_t *entity,
                                          char          *str,
                                          unsigned int  *strlen);
\end{verbatim}
The ``len'' function returns the length of the string.  The ``type''
function returns the type of string per standard OpenIPMI string
handling.  See section~\vref{appendix-ipmi-strings} for more details.
The last function returns the actual string.  The integer that
\verb=strlen= points to must be set to the length of the \verb=str=
array.  Upon return, the integer that \verb=strlen= points to will
contain the actual length.  If there is not enough space for the whole
string, the beginning of the string that fills the array will be
copied in.  All these functions return an error; the only current
return is ENOSYS if the parameter is not present.

You may also fetch fru data (except for multi-records) through a
single general function.  It is a necessarily complex interface.
The function is:
\begin{verbatim}
int ipmi_fru_get(ipmi_fru_t                *fru,
                 int                       index,
                 char                      **name,
                 int                       *num,
                 enum ipmi_fru_data_type_e *dtype,
                 int                       *intval,
                 time_t                    *time,
                 char                      **data,
                 unsigned int              *data_len);
\end{verbatim}
The index is a contiguous range from zero that holds every FRU data
item.  So you can iterate through the indexes from 0 until it returns
EINVAL to find all the names.

The \verb=name= returns the string name for the index.  Note that the
indexes may change between release, so don't rely on absolute numbers.
The names will remain the same, so you can rely on those.

\verb=num= is a pointer to an integer with the index of the item to get
within the field. Some fields (custom records) have multiple items in
them. The first item will be at index zero, and the integer here will
be updated to reference the next item. When the last item is reached,
the integer will be updated to -1. For fields that don’t have multiple
items, this will not modify the value num points to, so you can use
that to detect if indexes are used for the item.

The \verb=dtype= field will be set to the data type.  If it is an
integer value, then \verb=intval= will be set to whatever the value
is.  If it is a time value, then the \verb=time= field will be filled
in.  If it is not, then a block of data will be allocated to hold the
field and placed into \verb=data=, the length of the data will be in
\verb=data_len=.  You must free the data when you are done with
\verb=ipmi_fru_data_free()=.

This function Returns \verb=EINVAL= if the index is out of range,
\verb=ENOSYS= if the particular index is not supported (the name will
still be set), or \verb=E2BIG= if the num is too big (again, the name
will be set).

Any of the return values may be passed \verb=NULL= to ignore the data.

\paragraph{Writing FRU Data to a FRU}

OpenIPMI supports writing FRU data.  This is a \emph{very} dangerous
operations and should not be done by general code.  There are no locks
on the FRU data, so multiple writers can easily corrupt the data.  But
for doing FRU data updates, OpenIPMI can be used to fetch, modify, and
write the FRU data assuming proper care is taken.

To write to the FRU, you must first fetch it by allocating it.  If the
FRU data currently in the fru is corrupt, you will get errors, but as
long as the data length of the FRU is non-zero you can still modify it
and write it back out.

After the FRU has been fetched, you may then modify the contents.
Remember that each field of a FRU is in an area.  To increase the size
of a field or add a new field, it's area must have enough space.

You may change the size of an area by increasing or decreasing its
length.  You may also add a new area, but it must be one of the
supported types.  You must, however, make sure there is enough empty
space to after the area.  OpenIPMI will not rearrange the areas to
make space, you have to do that yourself.  So you may have to change
the offset of an area (and other areas) to make space.  The following
functions are for working with areas:
\begin{verbatim}
int ipmi_fru_add_area(ipmi_fru_t   *fru,
                      unsigned int area,
                      unsigned int offset,
                      unsigned int length);
int ipmi_fru_delete_area(ipmi_fru_t *fru, int area);
int ipmi_fru_area_get_offset(ipmi_fru_t   *fru,
                             unsigned int area,
                             unsigned int *offset);
int ipmi_fru_area_get_length(ipmi_fru_t   *fru,
                             unsigned int area,
                             unsigned int *length);
int ipmi_fru_area_set_offset(ipmi_fru_t   *fru,
                             unsigned int area,
                             unsigned int offset);
int ipmi_fru_area_set_length(ipmi_fru_t   *fru,
                             unsigned int area,
                             unsigned int length);
int ipmi_fru_area_get_used_length(ipmi_fru_t *fru,
                                  unsigned int area,
                                  unsigned int *used_length);
\end{verbatim}
The \verb=used_length= variable tells how much of the length of the
FRU is actually used.  Note that area offsets and length must be
multiples of 8.

To change the value of a field, you will use functions of the form:
\begin{verbatim}
int ipmi_fru_set_chassis_info_type(ipmi_entity_t *entity,
                                   unsigned char type);
int ipmi_entity_set_chassis_info_part_number(ipmi_entity_t        *entity,
                                             enum ipmi_str_type_e *type);
                                             char                 *str,
                                             unsigned int         strlen);
int ipmi_fru_set_chassis_info_custom(ipmi_fru_t           *fru,
                                     unsigned int         num,
                                     enum ipmi_str_type_e type,
                                     char                 *str,
                                     unsigned int         len);
\end{verbatim}
These set the fields to the given values.  If you set a required field
to a \verb=NULL= string, it will clear the value of the string.  If
you set a multi-record or custom string to a \verb=NULL= string, it
will delete the record at the given number.

Like the \verb=ipmi_fru_get= function, the following functions allow
setting FRU variables by index:
\begin{verbatim}
int ipmi_fru_set_int_val(ipmi_fru_t *fru,
                         int        index,
                         int        num,
                         int        val);
int ipmi_fru_set_time_val(ipmi_fru_t *fru,
                          int        index,
                          int        num,
                          time_t     time);
int ipmi_fru_set_data_val(ipmi_fru_t                *fru,
                          int                       index,
                          int                       num,
                          enum ipmi_fru_data_type_e dtype,
                          char                      *data,
                          unsigned int              len);
\end{verbatim}
The \verb=num= field is ignored if the particular index does not
support more than one field (is not a custom field).  When adding, if
the \verb=num= field is a field that already exists, it will be
replaced or updated.  If \verb=num= is beyond the last element of the
particular item, a new item will be added onto the end, it will not be
added at the specific index.

To write the FRU data back out after you have modified it, use the
following function:
\begin{verbatim}
int ipmi_fru_write(ipmi_fru_t *fru, ipmi_fru_fetched_cb done, void *cb_data);
\end{verbatim}

\section{Entity \acs{SDR}s}
\label{sec-entity-sdrs}

TBD - write this

%---------------------------------------------------------------------
\chapter{Sensors}

Sensors, of course, are probably the most interesting part of
\ac{IPMI}.  Really, everything else is there so the sensors may be
known and monitored.  Unfortunately, sensors are also the most
complicated part of \ac{IPMI}.  OpenIPMI is really unable to hide a
lot of this complexity, it is passed on to the user, so expect to have
to do some reading and understanding.

\acs{IPMI} defines two basic different types of sensors.  Threshold
sensors monitor ``analog'' things like temperature, voltage, or fan
speed.  Discrete sensors monitor events or states, like entity
presence, software initialization progress, or if external power is
applied to the system.  Table~\ref{event-reading-type-codes} describes
the basic types of sensors.

\begin{longtable}{|p{0.2\textwidth}|l|p{0.65\textwidth}|}
\caption{Event/Reading Type Codes\label{event-reading-type-codes}}
\\ \hline
\bfseries{Value} & \bfseries{\#} & \bfseries{Description}\\
\endhead
\hline
\end{longtable}


\section{Sensor Events}
Both threshold and discrete sensors may generate events.  This is
optional, the \acs{SDR} for the sensor describes the sensor's event
support.

Some sensors support each individual bit or state being enabled or
disabled.  Others may only support events for the whole sensor being
enabled or disabled.  Still others may only support a global enable
for the entire \ac{MC}.

\section{Rearm}
``Rearm'' means setting the sensor so it will go off again.

TBD - write this.


\section{Threshold Sensors}

Threshold sensors report their readings in values from 0-255.
OpenIPMI makes every effort to convert this to a floating-point value
for you to use.  \acs{IPMI} defines standard ways to convert values
using various formulas.  OpenIPMI implements all these and provides
ways for \acs{OEM} functions to plug in to provide their own
converters.  If you have a sensor that cannot be represented using the
standard mechanisms, you need to get the \acs{OEM} algorithms for this
and implement them in an \acs{OEM} plug-in for the sensor.

\subsection{Threshold Sensor Events}
\label{sec-threshold-sensor-events}

You may have events on a threshold sensor by specifying values (called
thresholds) where you want the sensor to report an event.  Then you
can enable the events for the specific thresholds.  Not all sensors
support all thresholds, some cannot have their events enabled and
others cannot have them disabled.  The capabilities of a sensor may
all be queried by the user to determine what it can do.  When the
value of the sensor goes outside the threshold an event may be
generated.  An event may be generated when the value goes back into
the threshold.

Events for threshold sensors are mind-bogglingly complicated.  Each
threshold has four different possible events that can be supported.
Only two of them make sense to support for any given threshold,
thankfully.  And a sensor can have six different thresholds.

\acs{IPMI} supports events on going below (going low) the threshold
and going above the threshold (going high).  For each of those, it
supports an assertion and deassertion event.  Most sensors are either
a lower bound (and would thus support an eventgoing below the
threshold) or an upper bound (and would thus support an event going
above the threshold). Figure~\vref{fig-thresh} shows an upper and
lower threshold sensor.  When the value of an upper threshold sensor
goes above the threshold, that is an assertion going high.  When it
goes back below the threshold, that is a deassertion going high.  On a
lower threshold, going below the threshold is a assertion going low.
When the value goes back above the threshold, it is an deassertion
going low.
\begin{figure}
\includegraphics[width=\textwidth]{Thresh.eps}
\caption{\label{fig-thresh}Examples of thresholds}
\end{figure}

Each sensor may have six different thresholds:
\begin{tightdefs}
\item upper non-recoverable
\item upper critical
\item upper non-critical
\item lower non-critical
\item lower critical
\item lower non-recoverable
\end{tightdefs}
The meanings of these are not defined by \acs{IPMI}, but the meanings
are pretty obvious.  You may ask, though, why there are both upper and
lower thresholds and separate going high and going low events.  A
going low event is kind of silly on an upper threshold, for instance.
The reasoning is not in the spec, but it may be that there are sensors
where the ``middle'' of the range is not ok.  So for instance, it may
be ok if the temperature is above 100C or below 5C, but the range
between those values is not ok.  This is extremely unlikely, but this
type of structure allows it.

\subsection{Hysteresis}

Threshold sensors may have hysteresis, meaning that when the threshold
goes on above or below the specified value, the transition point where
the threshold goes off is somewhat below or above the given value.  For
instance, if you want a fan speed sensor to go off when it goes below
150 RPM, if the fan is hanging right around 150 RPM, the sensor may be
constantly sending you events as it goes slightly above and slightly
below 150 RPM, which is bad because it can overload the system
management software.  The hysteresis for the fan might be set at 10 rpm,
which means that if the speed goes below 150 RPM, then it must go above
160 RPM for the threshold to be disabled.  Hysteresis may be settable or
may be fixed for the sensor.

Figure~\vref{fig-hyst} shows an example of going high and going low
thresholds with hysteresis.  Notice that the deassertion events don't
get triggered right at the threshold, but as some point beyond the
threshold.
\begin{figure}
\includegraphics[width=\textwidth]{Hyst.eps}
\caption{\label{fig-hyst}Examples of hysteresis}
\end{figure}

There is only one pair of hysteresis values for a sensor.  That pair
is used for all thresholds in the sensor.  One of the members of the
pair is a positive threshold, meaning that is is applied to thresholds
that go over a specific value.  The value must go that much below the
threshold before the threshold goes back in range.  The other member is
a negative threshold, meaning that it is applied to thresholds that go
below a given value.  The value must go that much above the threshold
before the threshold goes back in range.

\section{Discrete Sensors}

Discrete sensors report their readings in a 16-bit bitmask, each bit
generally representing a discrete state.  For instance, consider the
slot/connector sensor.  Bit 0 tells if there is a fault.  Bit 2 tells
if a device is present in the slot.  Bit 5 tells if power is off on
the slot.  Each bit tells a completely independent state and they may
each be zero or one independently.

You enable events on the sensor by specifying which bits you want to
generate events.  Like threshold sensors, these events may or may not
be user-controllable.  The capabilities of the sensor may be fetched
by the user.

\begin{longtable}{|p{0.2\textwidth}|l|p{0.65\textwidth}|}
\caption{Sensor Types and Codes\label{sensor-type-codes}}
\\ \hline
\bfseries{Parameter} & \bfseries{\#} & \bfseries{Description}\\
\endhead
\hline
\end{longtable}

\section{\acs{IPMI} Commands Dealing with Sensors}

TBD - write this

\section{Using Sensors in OpenIPMI}
As mentioned before, \acs{IPMI} sensors are very complicated.
OpenIPMI attempts to hide as much of this complexity as it can, but it
can only do so much.

So starting at the beginning, the first thing you need to know about a
sensor is its type.  You fetch that with the function:
\begin{verbatim}
int ipmi_sensor_get_event_reading_type(ipmi_sensor_t *sensor);
\end{verbatim}
This returns a value from the following table.  The names in this
table are shortened, all these begin with
IPMI\_EVENT\_READING\_TYPE\_.  The values are:

\begin{longtable}{|p{.27\textwidth}|p{0.65\textwidth}|}
\hline
THRESHOLD & The sensor monitors an analog value.  All threshold sensors
        have this value.\\
\hline
DISCRETE\_USAGE & These are \acs{DMI}-based usage states.  Valid offsets
        are:
        \begin{tightdefs}
        \item[00h] - transition to idle
        \item[01h] - transition to active
        \item[02h] - transition to busy
        \end{tightdefs}\\
\hline
DISCRETE\_STATE & Monitors the value of a state.  Valid values are:
        \begin{tightdefs}
        \item[00h] - state deasserted
        \item[01h] - state asserted
        \end{tightdefs}\\
\hline
DISCRETE\_PREDICTIVE \_FAILURE & This is used to know if an entity is
        about to fail, but is still operations.  Valid values are:
        \begin{tightdefs}
        \item[00h] - predictive failure deasserted
        \item[01h] - predictive failure asserted
        \end{tightdefs}\\
\hline
DISCRETE\_LIMIT \_EXCEEDED & This is used to tell if a limit has been
        exceeded.  Valid values are:
        \begin{tightdefs}
        \item[00h] - limit not exceeded
        \item[01h] - limit exceeded
        \end{tightdefs}\\
\hline
DISCRETE \_PERFORMANCE\_MET & This is used to tell if system performance
        is meeting expectations.  Valid values are:
        \begin{tightdefs}
        \item[00h] - performance met
        \item[01h] - performance not met
        \end{tightdefs}\\
\hline
DISCRETE\_SEVERITY & This is used to know if an entity is in trouble
        or other state information.  Valid values are:
        \begin{tightdefs}
        \item[00h] - transition to ok
        \item[01h] - transition to non-critical from ok.
        \item[02h] - transition to critical from less critical.
        \item[03h] - transition to non-recoverable from less critical.
        \item[04h] - transition to non-critical from more critical.
        \item[05h] - transition to critical from non-recoverable.
        \item[06h] - transition to non-recoverable.\footnote{This state
          seems rather silly and is probably not used.}
        \item[07h] - monitor
        \item[08h] - informational
        \end{tightdefs}
        The actual meaning of these is not defined by the spec.\\
\hline
DISCRETE\_DEVICE \_PRESENCE & This is a presence sensor to know when
        an entity is present or not.  Note that OpenIPMI uses this for
        entity presence if it is available.  Valid values are:
        \begin{tightdefs}
        \item[00h] - entity not present
        \item[01h] - entity present
        \end{tightdefs}\\
\hline
DISCRETE\_DEVICE \_ENABLE & This tells if a device is enabled.  Valid
        values are:
        \begin{tightdefs}
        \item[00h] - device disabled
        \item[01h] - device enabled
        \end{tightdefs}\\
\hline
DISCRETE \_AVAILABILITY & This tells the current availability state of
        the device.  Valid values are:
        \begin{tightdefs}
        \item[00h] - transition to running
        \item[01h] - transition to in test
        \item[02h] - transition to power off
        \item[03h] - transition to on line
        \item[04h] - transition to off line
        \item[05h] - transition to off duty
        \item[06h] - transition to degraded
        \item[07h] - transition to power save
        \item[08h] - install error
        \end{tightdefs}\\
\hline
DISCRETE \_REDUNDANCY & This shows the redundancy state of an entity.  Valid
        values are:
        \begin{tightdefs}
        \item[00h] - Fully redundant, the entity has full redundancy.
        \item[01h] - Redundancy lost, this is reported if
          redundancy has been lost at all.
        \item[02h] - Redundance degraded, the system is still redundant
          but is missing some resources (like the system has four fans
          and only two are running).
        \item[03h] - Transition from fully redundant to non-redundant:
          sufficient resource.  The entity
          has lost redundancy but has sufficient resources to continue
          normal operation.
        \item[04h] - Transition from non-redundant:sufficient
          resources to non-redundant:insufficient resource.  The
          entity has lost enough resources to continue normal
          operation.
        \item[05h] - Transition from fully redundant to non-redundant:
          sufficient resource.  The entity
          has lost redundancy but has sufficient resources to continue
          normal operation.
        \item[06h] - Non-redundant:insufficient resources.  entity has
          lost redundancy and lost enough resources to continue normal
          operation.
        \item[07h] - Transition from redundant to redundancy degraded.
          The unit has lost some redundancy but is still redundant.
        \item[08h] - Transition from redundancy lost to redundancy
          degraded.  The entity had lost redundancy and has regained
          some redundancy, but is not fully redundant.
        \end{tightdefs}\\
\hline
DISCRETE\_ACPI\_POWER & The current ACPI power state of the system.  Valid
        values are:
        \begin{tightdefs}
        \item[00h] - D0 power state
        \item[01h] - D1 power state
        \item[02h] - D2 power state
        \item[03h] - D3 power state
        \end{tightdefs}\\
\hline
SENSOR\_SPECIFIC & This setting means that the offsets in the sensor are
        dependent on the sensor type.  This is only for discrete sensors.\\
\hline
\end{longtable}

Note that for some operations, threshold sensors and discrete sensor
have different functions, and some other functions work a little
differently.

To know the type of sensor, the function:
\begin{verbatim}
int ipmi_sensor_get_sensor_type(ipmi_sensor_t *sensor);
\end{verbatim}
returns the type.  The returns values for this are integer defines
that start with IPMI\_SENSOR\_TYPE\_ and have the specific values defined
in the following table.  Note that discrete sensors in this list have
define bit settings; those settings are also defined in this list.
\begin{longtable}{|p{0.27\textwidth}|p{0.65\textwidth}|}
\hline
TEMPERATURE & \\
\hline
VOLTAGE & \\
\hline
CURRENT & \\
\hline
FAN & \\
\hline
PHYSICAL\_SECURITY & The chassis was opened or accessed.
        \begin{tightdefs}
        \item[00h] - General chassis intrusion
        \item[01h] - Drive bay intrusion
        \item[02h] - I/O card area intrusion
        \item[03h] - Processor area intrusion
        \item[04h] - LAN cable is unplugged
        \item[05h] - Unauthorized dock/undock
        \item[06h] - Fan area intrusion (including unauthorized hot-plugs
          of fans).
        \end{tightdefs}\\
\hline
PLATFORM\_SECURITY &
        \begin{tightdefs}
        \item[00h] - The spec says ``Secure Mode (Front Panel Lockout)
          Violation attempt''.  The meaning of this is unknown.
        \item[01h] - User pre-boot password failure.
        \item[02h] - Setup pre-boot password failure.
        \item[03h] - Network pre-boot password failure.
        \item[04h] - Other pre-boot password failure.
        \item[05h] - Out-of-band pre-boot password failure.
        \end{tightdefs}\\
\hline
PROCESSOR & Various processor failures.  Most of these are very Intel processor
        centric, you may need to reference the processor manual for the
        meaning of the failure.
        \begin{tightdefs}
        \item[00h] - IERR
        \item[01h] - Thermal Trip
        \item[02h] - FRB1/BIST failure
        \item[03h] - FRB2/Hang in POST failure, if the failure is believed
          to be due to a processor failure.
        \item[04h] - FRB3/Processor Startup/Initialization failure (CPU
          didn't start).
        \item[05h] - Configuration Error
        \item[06h] - SMBIOS ``Uncorrectable CPU-complex error''
        \item[07h] - Processor presence detected
        \item[08h] - Processor disabled
        \item[09h] - Terminator presence detected
        \end{tightdefs}\\
\hline
POWER\_SUPPLY & 
        \begin{tightdefs}
        \item[00h] - Presence detected
        \item[01h] - Failure detected
        \item[02h] - Predictive failure.  This probably means that the
          power supply is still working but may fail soon.
        \item[03h] - AC lost
        \item[04h] - AC lost or out-of-range
        \item[05h] - AC present but out of range
        \end{tightdefs}\\
\hline
POWER\_UNIT & 
        \begin{tightdefs}
        \item[00h] - Power off
        \item[01h] - Power cycle
        \item[02h] - 240VA power down
        \item[03h] - Interlock power down
        \item[04h] - AC lost
        \item[05h] - Soft power control failure (unit did not response to
          request)
        \item[06h] - Failure detected
        \item[07h] - Predictive failure.  This probably means that the
          power unit is still working but may fail soon.
        \end{tightdefs}\\
\hline
COOLING\_DEVICE & \\
\hline
OTHER\_UNITS \_BASED\_SENSOR & The sensor is a threshold sensor, but not one
        specified directly by the spec.  The units can be fetched with
        the calls to get the units.\\
\hline
MEMORY & 
        \begin{tightdefs}
        \item[00h] - Correctable memory error
        \item[01h] - Uncorrectable memory error
        \item[02h] - Parity error
        \item[03h] - Memory scrub failed, probably stuck bit
        \item[04h] - Memory device disabled
        \item[05h] - Reached log limit for correctable memory errors
        \end{tightdefs}\\
\hline
DRIVE\_SLOT & \\
\hline
POWER\_MEMORY \_RESIZE & \\
\hline
SYSTEM\_FIRMWARE \_PROGRESS &  Information about the system firmware (BIOS).
        In an event, the event data 2 may give further information about
        the error.  See section~\ref{sec-event-data-info-for-events} for
        more info.
        \begin{tightdefs}
        \item[00h] - System firmware error (power-on-self-test error)
        \item[01h] - System firmware hang
        \item[02h] - System firmware progress
        \end{tightdefs}\\
\hline
EVENT\_LOGGING \_DISABLED & 
        \begin{tightdefs}
        \item[00h] - Correctable memory error logging disabled
        \item[01h] - Event logging has been disabled for the sensor
          specified in the event information.  In an event, event data
          provides more information about the event, see
          section~\ref{sec-event-data-info-for-events} for more info.
        \item[02h] - Log area cleared
        \item[03h] - All event logging disabled
        \end{tightdefs}\\
\hline
WATCHDOG\_1 & This is for IPMI version 0.9 and old 1.0 only.  Later 1.0 and
        newer specs use the watchdog 2 sensor type.
        \begin{tightdefs}
        \item[00h] - BIOS watchdog reset
        \item[01h] - OS watchdog reset
        \item[02h] - OS watchdog shutdown
        \item[03h] - OS watchdog power down
        \item[04h] - OS watchdog power cycle
        \item[05h] - OS watchdog NMI or diagnostic interrupt
        \item[06h] - OS watchdog expired, status only
        \item[07h] - OS watchdog pre-timeout interrupt, not NMI
        \end{tightdefs}\\
\hline
SYSTEM\_EVENT & 
        \begin{tightdefs}
        \item[00h] - System reconfigured
        \item[01h] - OEM system boot event
        \item[02h] - Undetermined system hardware failure
        \item[03h] - Entry added to the auxilliary log.  In an event,
          event data provides more information about the event, see
          section~\ref{sec-event-data-info-for-events} for more info.
        \item[04h] - PEF action.  In an event, event data provides
          more information about the event, see
          section~\ref{sec-event-data-info-for-events} for more info.
        \end{tightdefs}\\
\hline
CRITICAL\_INTERRUPT &
        \begin{tightdefs}
        \item[00h] - Front panel NMI/Diagnostic interrupt
        \item[01h] - Bus timeout
        \item[02h] - I/O channel check NMI
        \item[03h] - Software NMI
        \item[04h] - PCI PERR
        \item[05h] - PCI SERR
        \item[06h] - EISA fail safe timeout
        \item[07h] - Bus correctable error
        \item[08h] - Bus uncorrectable error
        \item[09h] - Fatal NMI (port 61h, bit 7)
        \end{tightdefs}\\
\hline
BUTTON & 
        \begin{tightdefs}
        \item[00h] - Power button pressed
        \item[01h] - Sleep button pressed
        \item[02h] - Reset button pressed
        \end{tightdefs}\\
\hline
MODULE\_BOARD & \\
\hline
MICROCONTROLLER \_COPROCESSOR & \\
\hline
ADD\_IN\_CARD & \\
\hline
CHASSIS & \\
\hline
CHIP\_SET & \\
\hline
OTHER\_FRU & \\
\hline
CABLE\_INTERCONNECT & \\
\hline
TERMINATOR & \\
\hline
SYSTEM\_BOOT \_INITIATED &
        \begin{tightdefs}
        \item[00h] - Power up
        \item[01h] - Hard reset
        \item[02h] - Warm reset
        \item[03h] - User requested PXE boot
        \item[04h] - Automatic boot to diagnostic
        \end{tightdefs}\\
\hline
BOOT\_ERROR & 
        \begin{tightdefs}
        \item[00h] - No bootable media
        \item[01h] - Non-bootable disk in drive
        \item[02h] - PXE server not found
        \item[03h] - Invalid boot sector
        \item[04h] - Timeout waiting for user selection of boot source
        \end{tightdefs}\\
\hline
OS\_BOOT & 
        \begin{tightdefs}
        \item[00h] - A: boot completed
        \item[00h] - C: boot completed
        \item[00h] - PXE boot completed
        \item[00h] - Diagnostic boot completed
        \item[00h] - CDROM boot completed
        \item[00h] - ROM boot completed
        \item[00h] - Boot completed, boot device not specified
        \end{tightdefs}\\
\hline
OS\_CRITICAL\_STOP &%
        \begin{tightdefs}
        \item[00h] - Stop during OS load or initialization
        \item[01h] - Stop during OS operation
        \end{tightdefs}\\
\hline
SLOT\_CONNECTOR & Note that ready for installation, ready for removal, and
        power states can transition together.  In an event, event data provides
        more information about the event, see
        section~\ref{sec-event-data-info-for-events} for more info.
        \begin{tightdefs}
        \item[00h] - Fault status
        \item[01h] - Identify status
        \item[02h] - Device installed (includes doc events)
        \item[03h] - Ready for device installation.  This generally means
          that the power is off.
        \item[04h] - Ready for device removal.
        \item[05h] - Power is off
        \item[06h] - Removal request.  This generally means that the user
          has asserted some mechanism that requests removal.
        \item[07h] - Interlock.  This is generally some mechanical device
          that disables power to the slot.  Assertion means that the
          disable is active.
        \item[08h] - Slot is disabled.
        \end{tightdefs}\\
\hline
SYSTEM\_ACPI \_POWER\_STATE & 
        \begin{tightdefs}
        \item[00h] - S0/G0 ``Working''
        \item[01h] - S1 ``Sleeping, system h/w and processor
          context maintained''
        \item[02h] - S2 ``Sleeping, processor context lost''
        \item[03h] - S3 ``Sleeping, system h/w and processor
          context lost, memory maintained''
        \item[04h] - S4 ``non-volatile sleep or suspend to disk''
        \item[05h] - S5/G2 ``soft off''
        \item[06h] - S4/S5 soft-off, particular S4/S5 state cannot be
          determined.
        \item[07h] - G3 ``Mechanical off''
        \item[08h] - Sleeping in an S1, S2, or S3 state, particular state
          cannot be determined.
        \item[09h] - G1 sleeping, S1-S4 state cannot be determined
        \item[0Ah] - S5 state entered by override
        \item[0Bh] - Legacy on state
        \item[0Ch] - Legacy off state
        \item[0Eh] - Unknown
        \end{tightdefs}\\
\hline
WATCHDOG\_2 & This is for newer IPMI 1.0 systems and later specs.  In an
        event, event data provides more information about the event, see
        section~\ref{sec-event-data-info-for-events} for more info.
        \begin{tightdefs}
        \item[00h] - Timer expired, status only, no action
        \item[01h] - Hard reset
        \item[02h] - Power down
        \item[03h] - Power cycle
        \item[08h] - Timer interrupts.
        \end{tightdefs}\\
\hline
PLATFORM\_ALERT & Used for monitoring the platform management firmware,
        status can be fetched and events generated on platform management
        actions.
        \begin{tightdefs}
        \item[00h] - Page sent
        \item[01h] - LAN alert sent
        \item[02h] - Event trap sent per IPMI PET specification
        \item[03h] - Event trap sent using OEM format
        \end{tightdefs}\\
\hline
ENTITY\_PRESENCE & This is the sensor used to tell if an entity is present
        or not.  This applied to the entity the sensor is attached to.
        \begin{tightdefs}
        \item[00h] - Entity is present
        \item[01h] - Entity is absent
        \item[02h] - Entity is present but disabled
        \end{tightdefs}\\
\hline
MONITOR\_ASIC\_IC & \\
\hline
LAN & 
        \begin{tightdefs}
        \item[00h] - LAN heartbeat lost
        \item[01h] - LAN heartbeat present
        \end{tightdefs}\\
\hline
MANAGEMENT \_SUBSYSTEM\_HEALTH & 
        \begin{tightdefs}
        \item[00h] - Sensor access degraded or unavailable
        \item[01h] - Controller access degraded or unavailable
        \item[02h] - Management controller offline
        \item[03h] - Management controller unavailable
        \end{tightdefs}\\
\hline
BATTERY & 
        \begin{tightdefs}
        \item[00h] - Battery is low
        \item[01h] - Battery failed
        \item[02h] - Battery is present.
        \end{tightdefs}\\
\hline
\end{longtable}

Strings are available from the sensor that describe the sensor type
and event reading type.  Note that these may be set to valid values
by OEM code even if the values are OEM, so these can be very
useful.
\begin{verbatim}
char *ipmi_sensor_get_sensor_type_string(ipmi_sensor_t *sensor);
char *ipmi_sensor_get_event_reading_type_string(ipmi_sensor_t *sensor);
\end{verbatim}

As well as the strings, the specific reading information from the above
table is also available, supply the sensor type and offset and a string
is returned.  The function is:
\begin{verbatim}
char *ipmi_sensor_reading_name_string(ipmi_sensor_t *sensor, int offset);
\end{verbatim}

\subsection{General Information About Sensors in OpenIPMI}

The following section applies to all sensor types.

\subsubsection{Sensor Entity Information}
Every sensor is associated with a specific entity, these calls let you
fetch the entity information.  The following calls return the numeric
entity id and instance:
\begin{verbatim}
int ipmi_sensor_get_entity_id(ipmi_sensor_t *sensor);
int ipmi_sensor_get_entity_instance(ipmi_sensor_t *sensor);
\end{verbatim}
Generally, though, that is note what you want.  You want the actual
entity object, which may be fetched with the following:
\begin{verbatim}
ipmi_entity_t *ipmi_sensor_get_entity(ipmi_sensor_t *sensor);
\end{verbatim}
Note that the entity is refcounted when the sensor is claimed, so the
entity will exist while you have a valid reference to a sensor it
contains.

\subsubsection{Sensor Name}
The SDR contains a string giving a name for the sensor.  This is
useful for printing out sensor information.  The functions to get
this are:
\begin{verbatim}
int ipmi_sensor_get_id_length(ipmi_sensor_t *sensor);
enum ipmi_str_type_e ipmi_sensor_get_id_type(ipmi_sensor_t *sensor);
int ipmi_sensor_get_id(ipmi_sensor_t *sensor, char *id, int length);
\end{verbatim}
See appendix~\ref{appendix-ipmi-strings} for more information about
these strings.

The function
\begin{verbatim}
int ipmi_sensor_get_name(ipmi_sensor_t *sensor, char *name, int length);
\end{verbatim}
returns a fully qualified name for the sensor with the entity name
prepended.  The name array is filled with the name, up to the length
given.  This is useful for printing string names for the sensor.

\subsubsection{Sensor Event Support in OpenIPMI}
\label{sec-sensor-event-support-in-openipmi}

Sensors may support event enables in different ways.  The following
function returns what type of event enable is supported:
\begin{verbatim}
int ipmi_sensor_get_event_support(ipmi_sensor_t *sensor);
\end{verbatim}

The return values are all prepended with IPMI\_EVENT\_SUPPORT\_,
values are:
\begin{longtable}{|p{0.27\textwidth}|p{0.65\textwidth}|}
\hline
PER\_STATE & Each individual state or threshold may individually have
        its events turned off and on.  This means that the individual
        thresholds and states may be individually enabled.\\
\hline
ENTIRE\_SENSOR & The entire sensor may have events enabled and disabled
        using the events\_enabled setting when setting the event
        enables.  Section~\ref{sec-sensor-event-states} describes this
        setting.\\
\hline
GLOBAL\_ENABLE & Events may only be enabled and disabled for the whole
        managment controller.  Events are disabled by setting the
        event receiver to 00h, or enabled by setting them to the proper
        event receiver.  See section~\ref{sec-global-event-enables}
        for more details.\\
\hline
NONE & The sensor does not support events.\\
\hline
\end{longtable}

Note that the more general event enables work and override the more
specific ones, so if, for instance, a sensor supports per-state event
enables, it will also support the entire sensor and global enables.
The entire sensor enable being off will override all per-state
enables.  The global enable will turn off all events from a management
controller no matter what other settings are present.

To receive events from a sensor, an event handler must be registered.
An event handler may also be dynamically removed.  The following
functions do this for discrete sensors:
\begin{verbatim}
typedef int (*ipmi_sensor_discrete_event_cb)(
    ipmi_sensor_t         *sensor,
    enum ipmi_event_dir_e dir,
    int                   offset,
    int                   severity,
    int                   prev_severity,
    void                  *cb_data,
    ipmi_event_t          *event);
int ipmi_sensor_add_discrete_event_handler(
    ipmi_sensor_t                 *sensor,
    ipmi_sensor_discrete_event_cb handler,
    void                          *cb_data);
int ipmi_sensor_remove_discrete_event_handler(
    ipmi_sensor_t                 *sensor,
    ipmi_sensor_discrete_event_cb handler,
    void                          *cb_data);
\end{verbatim}
The following functions do this for threshold sensors:
\begin{verbatim}
typedef int (*ipmi_sensor_threshold_event_cb)(
    ipmi_sensor_t               *sensor,
    enum ipmi_event_dir_e       dir,
    enum ipmi_thresh_e          threshold,
    enum ipmi_event_value_dir_e high_low,
    enum ipmi_value_present_e   value_present,
    unsigned int                raw_value,
    double                      value,
    void                        *cb_data,
    ipmi_event_t                *event);
int ipmi_sensor_add_threshold_event_handler(
    ipmi_sensor_t                  *sensor,
    ipmi_sensor_threshold_event_cb handler,
    void                           *cb_data);
int ipmi_sensor_remove_threshold_event_handler(
    ipmi_sensor_t                  *sensor,
    ipmi_sensor_threshold_event_cb handler,
    void                           *cb_data);
\end{verbatim}
This function should generally be registered in the entity callback
that reports the sensor being added, so that no events will be missed.
This is a standard event handler as defined in
section~\vref{sec-openipmi-events}.

\subsubsection{Sensor/Entity Existance Interaction}
Some sensors are present even if the entity they are attached to is
not present.  The following will return true if the entity should be
ignore if the entity is not present.  It will return false if the
sensor is present even when the entity is not present.

\begin{verbatim}
int ipmi_sensor_get_ignore_if_no_entity(ipmi_sensor_t *sensor);
\end{verbatim}

\subsubsection{Sensor States}
\label{sec-sensor-states}
When reading the value of a sensor or handling an even, a state data
structure is generally available in a read-only data structure.  This
tells the state of the various thresholds or bits in the sensor.  This
is an opaque data structure, you do not have access to any of the
contents.  The data structure is defined as:
\begin{verbatim}
typedef struct ipmi_states_s ipmi_states_t;
\end{verbatim}

To keep your own copy of a states data structure, you may allocate and
copy one using the following functions:
\begin{verbatim}
unsigned int ipmi_states_size(void);
void ipmi_copy_states(ipmi_states_t *dest, ipmi_states_t *src);
\end{verbatim}
This allows you to find the size and copy the information in one of
these structures.  For example, to make your own copy, do something
like:
\begin{verbatim}
my_states = malloc(ipmi_states_size());
if (!my_states)
  handle_error()
else
  ipmi_copy_states(my_states, states);
\end{verbatim}

Information about the whole sensor is available using the following
functions:
\begin{verbatim}
int ipmi_is_event_messages_enabled(ipmi_states_t *states);
int ipmi_is_sensor_scanning_enabled(ipmi_states_t *states);
int ipmi_is_initial_update_in_progress(ipmi_states_t *states);
\end{verbatim}
If event messages are enabled, then the sensor may generate events.
If scanning is enabled, then the sensor is ``turned on'' and working.
If initial update is in progress, the information from the sensor is
not valid since the sensor is still trying to get a valid reading.

\subsubsection{Sensor Event State Information}
\label{sec-sensor-event-states}

The event state structure is an opaque structure that is used to
control the event settings of a sensor, if it supports at least
individual sensor event control.  This is much like the state data
structure defined in section~\ref{sec-sensor-states}, but it is used
to control event settings instead of just get the current state.  The
data structure is defined as:
\begin{verbatim}
typedef struct ipmi_event_state_s ipmi_event_state_t;
\end{verbatim}
It is an opaque data structure, so you cannot directly access the
contents or directly declare one.

To create or keep your own copy of an event state data structure, you
may allocate and copy one using the following functions:
\begin{verbatim}
unsigned int ipmi_event_state_size(void);
void ipmi_copy_event_state(ipmi_event_state_t *dest, ipmi_event_state_t *src);
\end{verbatim}
This allows you to find the size and copy the information in one of
these structures.  For example, to make your own copy, do something
like:
\begin{verbatim}
my_states = malloc(ipmi_event_state_size());
if (!my_states)
  handle_error()
else
  ipmi_copy_event_state(my_states, states);
\end{verbatim}

If you want to create one, allocate it as above and initialize it with
\begin{verbatim}
void ipmi_event_state_init(ipmi_event_state_t *events);
\end{verbatim}
This clears all settings.  The following functions are then available
to set and get global items in the event state:
\begin{verbatim}
void ipmi_event_state_set_events_enabled(ipmi_event_state_t *events, int val);
int ipmi_event_state_get_events_enabled(ipmi_event_state_t *events);
void ipmi_event_state_set_scanning_enabled(ipmi_event_state_t *events,int val);
int ipmi_event_state_get_scanning_enabled(ipmi_event_state_t *events);
void ipmi_event_state_set_busy(ipmi_event_state_t *events, int val);
int ipmi_event_state_get_busy(ipmi_event_state_t *events);
\end{verbatim}
If events are enabled, then the sensor can generate events.  This acts
as an off switch for the whole sensor.  If events are enabled, and if
per-state event enables are supported, then the individual state
settings control which events are generated.  Scanning means watching
for events; if scanning is off then the sensor, in effect, is turned
off and will not report valid reading or generate events.  If busy is
true on a return from a query, then the sensor is currently in busy with
some operation and cannot be read.

See section~\ref{sec-discrete-sensor-events-in-openipmi} for discrete
sensors and section~\vref{sec-threshold-sensor-events-in-openipmi} for
threshold events for the details on setting the individual event
enables.

Note that once you have created an event state, you have to send it to
the sensor.  Just creating and setting the values doesn't do anything
directly to the sensor; it must be sent.  To send them, use one of the
following:
\begin{verbatim}
int ipmi_sensor_set_event_enables(ipmi_sensor_t         *sensor,
                                  ipmi_event_state_t    *states,
                                  ipmi_sensor_done_cb   done,
                                  void                  *cb_data);
int ipmi_sensor_enable_events(ipmi_sensor_t         *sensor,
                              ipmi_event_state_t    *states,
                              ipmi_sensor_done_cb   done,
                              void                  *cb_data);
int ipmi_sensor_disable_events(ipmi_sensor_t         *sensor,
                               ipmi_event_state_t    *states,
                               ipmi_sensor_done_cb   done,
                               void                  *cb_data);
\end{verbatim}
The ``set'' function will set the states to exactly what is set in the
event state structure.  The ``enable'' function will only enable the
states that are set in the event state structure.  The ``disable''
function will disable the events that are set in the event state
structure.  Note that the disable does \emph{not} disable the events
that are not set, it really disables the events that \emph{are} set.
All of these functions will set the event enable and scanning enable
to the values in the event state structure.

To query the current event state settings, use the following function:
\begin{verbatim}
typedef void (*ipmi_sensor_event_enables_cb)(ipmi_sensor_t      *sensor,
                                             int                err,
                                             ipmi_event_state_t *states,
                                             void               *cb_data);
int ipmi_sensor_get_event_enables(ipmi_sensor_t             *sensor,
                                  ipmi_event_enables_get_cb done,
                                  void                      *cb_data);
\end{verbatim}

Appendex~\vref{app-sample-prog-event-setup} contains a program that
demonstrates how to use many of the functions described in this
section.

\subsubsection{Rearm in OpenIPMI}

TBD - write this.

\begin{verbatim}
int ipmi_sensor_get_supports_auto_rearm(ipmi_sensor_t *sensor);

int ipmi_sensor_rearm(ipmi_sensor_t       *sensor,
                      int                 global_enable,
                      ipmi_event_state_t  *state,
                      ipmi_sensor_done_cb done,
                      void                *cb_data);
\end{verbatim}

\subsubsection{Initialization}
When a sensor is stored in the main SDR repository of a system, the
\acs{BMC} may initialize certain aspects of the sensor at power up.
The following fetch if these aspects are initialized at power up.
Note that ``pu'' means ``Power Up'' in the following names.

\begin{verbatim}
int ipmi_sensor_get_sensor_init_scanning(ipmi_sensor_t *sensor);
int ipmi_sensor_get_sensor_init_events(ipmi_sensor_t *sensor);
int ipmi_sensor_get_sensor_init_thresholds(ipmi_sensor_t *sensor);
int ipmi_sensor_get_sensor_init_hysteresis(ipmi_sensor_t *sensor);
int ipmi_sensor_get_sensor_init_type(ipmi_sensor_t *sensor);
int ipmi_sensor_get_sensor_init_pu_events(ipmi_sensor_t *sensor);
int ipmi_sensor_get_sensor_init_pu_scanning(ipmi_sensor_t *sensor);
\end{verbatim}

\subsection{Threshold Sensors in OpenIPMI}
As mentioned before, threshold sensors monitor analog values.  This
means that they have a lot of information about how to convert the
values from the raw readings (the 0-255 value returned from the
sensor) into useful readings, what thresholds are supported,
hysteresis settings, and a plethora of other settings.  Lots of things
can be set up for threshold sensors.

\subsubsection{Threshold Sensor Readings in OpenIPMI}
The reading of a threshold sensor is done with the following:
\begin{verbatim}
typedef void (*ipmi_sensor_reading_cb)(ipmi_sensor_t             *sensor,
                                       int                       err,
                                       enum ipmi_value_present_e value_present,
                                       unsigned int              raw_value,
                                       double                    val,
                                       ipmi_states_t             *states,
                                       void                      *cb_data);
int ipmi_sensor_get_reading(ipmi_sensor_t        *sensor,
                            ipmi_reading_done_cb done,
                            void                 *cb_data);
\end{verbatim}

Assuming there was no error, the \texttt{value\_present} field will be set
to one of the following:
\begin{description}
\item[IPMI\_NO\_VALUES\_PRESENT] - Neither the raw or the converted values
  are present.  Only the states are valid.  This will be the case for
  thresholds sensors that cannot have their value read.
\item[IPMI\_RAW\_VALUE\_PRESENT] - Only the raw value is present.
  This will be the case if there was no conversion algorithm available
  for the sensor.
\item[IPMI\_BOTH\_VALUES\_PRESENT] - Both the raw and converted values are
  present.
\end{description}

The current states of the various thresholds (whether they are out of
range or note) is returned in the \texttt{states} parameter.  To know
if a sensor sets a threshold state setting when the value is read, use
the following function:
\begin{verbatim}
int ipmi_sensor_threshold_reading_supported(ipmi_sensor_t      *sensor,
                                            enum ipmi_thresh_e thresh,
                                            int                *val);
\end{verbatim}
This may not mean that the threshold will generate events (although it
will almost certainly mean that, the spec is not clear on this).  It
is only defined to mean that the threshold is returned in the reading.

For threshold sensors, the function:
\begin{verbatim}
int ipmi_is_threshold_out_of_range(ipmi_states_t      *states,
                                   enum ipmi_thresh_e thresh);
\end{verbatim}
will return true if the given threshold is out of range and false if
not.

\subsubsection{Threshold Sensor Events in OpenIPMI}
\label{sec-threshold-sensor-events-in-openipmi}

Section~\vref{sec-sensor-event-support-in-openipmi} shows the general
support for events for all sensor types.  Threshold sensors have their
own special routines for handling the thresholds.

Thresholds in a sensor may be settable or fixed and may or may not be
able to be read.  The function
\begin{verbatim}
int ipmi_sensor_get_threshold_access(ipmi_sensor_t *sensor);
\end{verbatim}
returns the event threshold access support of the sensor, return values are
\begin{description}
\item[IPMI\_THRESHOLD\_ACCESS\_SUPPORT\_NONE] - The sensor does not support
  thresholds.
\item[IPMI\_THRESHOLD\_ACCESS\_SUPPORT\_READABLE] - The sensor
  supports thresholds and their values may be read with
  ipmi\_thresholds\_get, but cannot be written.
\item[IPMI\_THRESHOLD\_ACCESS\_SUPPORT\_SETTABLE] - The sensor supports
  thresholds and they may be read and written.
\item[IPMI\_THRESHOLD\_ACCESS\_SUPPORT\_FIXED] - The sensor supports
  thresholds and they are fixed and may not be read or changed.
  ipmi\_get\_default\_sensor\_thresholds should return the fixed
  values of this sensor.
\end{description}

In addition to this, individual thresholds may be readable or settable
individually.  To find this, the following functions will return true
if a specific threshold is readable or settable, and false if not:
\begin{verbatim}
int ipmi_sensor_threshold_settable(ipmi_sensor_t      *sensor,
                                   enum ipmi_thresh_e threshold,
                                   int                *val);
int ipmi_sensor_threshold_readable(ipmi_sensor_t      *sensor,
                                   enum ipmi_thresh_e threshold,
                                   int                *val);
\end{verbatim}
The specific threshold values in the enumeration are:
\begin{tightdefs}
\item IPMI\_LOWER\_NON\_CRITICAL
\item IPMI\_LOWER\_CRITICAL
\item IPMI\_LOWER\_NON\_RECOVERABLE
\item IPMI\_UPPER\_NON\_CRITICAL
\item IPMI\_UPPER\_CRITICAL
\item IPMI\_UPPER\_NON\_RECOVERABLE
\end{tightdefs}
The function
\begin{verbatim}
char *ipmi_get_threshold_string(enum ipmi_thresh_e val);
\end{verbatim}
converts the value to a string.

To actually get and set the thresholds for a sensor, a threshold data
structure is used.  This data structure is opaque.

To create or keep your own copy of a threshold data structure, you
may allocate and copy one using the following functions:
\begin{verbatim}
unsigned int ipmi_threshold_size(void);
void ipmi_copy thresholds(ipmi_thresholds_t *dest, ipmi_thresholds_t *src);
\end{verbatim}
This allows you to find the size and copy the information in one of
these structures.  For example, to make your own copy, do something
like:
\begin{verbatim}
my_th = malloc(ipmi_thresholds_size());
if (!my_th)
  handle_error()
else
  ipmi_copy_thresholds(my_th, th);
\end{verbatim}

If you want to create one, allocate it as above and initialize it with
\begin{verbatim}
void ipmi_thresholds_init(ipmi_thresholds_t *th);
\end{verbatim}
This clears all settings.  The following functions are then available
to set the various threshold values:
\begin{verbatim}
int ipmi_threshold_set(ipmi_thresholds_t  *th,
                       ipmi_sensor_t      *sensor,
                       enum ipmi_thresh_e threshold,
                       double             value);
int ipmi_threshold_get(ipmi_thresholds_t  *th,
                       enum ipmi_thresh_e threshold,
                       double             *value);
\end{verbatim}
These get and set the values in the data structure.  This does not
affect the actual sensor until you send the thresholds to the sensor.

To send a set of thresholds to a sensor, use the following function:
\begin{verbatim}
int ipmi_sensor_set_thresholds(ipmi_sensor_t       *sensor,
                               ipmi_thresholds_t   *thresholds,
                               ipmi_sensor_done_cb done,
                               void                *cb_data);
\end{verbatim}
To get the current threshold settings of a sensor, use:
\begin{verbatim}
typedef void (*ipmi_sensor_thresholds_cb)(ipmi_sensor_t     *sensor,
                                          int               err,
                                          ipmi_thresholds_t *th,
                                          void              *cb_data);
int ipmi_sensor_get_thresholds(ipmi_sensor_t      *sensor,
                               ipmi_thresh_get_cb done,
                               void               *cb_data);
\end{verbatim}

To find out which thresholds support events, the following can be used
to tell if a specific thresholds support a specific event:
\begin{verbatim}
int ipmi_sensor_threshold_event_supported(
    ipmi_sensor_t               *sensor,
    enum ipmi_thresh_e          threshold,
    enum ipmi_event_value_dir_e value_dir,
    enum ipmi_event_dir_e       dir,
    int                         *val);
\end{verbatim}
The \texttt{value\_dir} parameter specifies if the ``going low'' or ``going
high'' events are being queried.  Value for this are:
\begin{tightdefs}
\item IPMI\_GOING\_LOW
\item IPMI\_GOING\_HIGH
\end{tightdefs}
The \texttt{dir} parameter specifies if the ``assertion'' or ``deassertion''
 events are being queried.  Value for this are:
\begin{tightdefs}
\item IPMI\_ASSERTION
\item IPMI\_DEASSERTION
\end{tightdefs}
Using these, all the thresholds and directions may be iterated through
to find out what the sensor supports.  The functions
\begin{verbatim}
char *ipmi_get_value_dir_string(enum ipmi_event_value_dir_e val);
char *ipmi_get_event_dir_string(enum ipmi_event_dir_e val);
\end{verbatim}
converts the \texttt{value\_dir} and \texttt{dir} values to strings.

To actually enable or disable individual events for a sensor, an event
state structure must be created.  An event state structure is passed
in when the event state of a sensor is queried.  To set or clear
individual events in one of these structures, use the following:
\begin{verbatim}
void ipmi_threshold_event_clear(ipmi_event_state_t          *events,
                                enum ipmi_thresh_e          threshold,
                                enum ipmi_event_value_dir_e value_dir,
                                enum ipmi_event_dir_e       dir);
void ipmi_threshold_event_set(ipmi_event_state_t          *events,
                              enum ipmi_thresh_e          threshold,
                              enum ipmi_event_value_dir_e value_dir,
                              enum ipmi_event_dir_e       dir);
\end{verbatim}
To see if a specific event is set, use:
\begin{verbatim}
int ipmi_is_threshold_event_set(ipmi_event_state_t          *events,
                                enum ipmi_thresh_e          threshold,
                                enum ipmi_event_value_dir_e value_dir,
                                enum ipmi_event_dir_e       dir);
\end{verbatim}

\subsubsection{Threshold Sensor Units in OpenIPMI}

In \acs{IPMI}, the \acs{SDR} gives quite a bit of information about
what the converted value means.  The units are specified, unit
modifiers and rates, and whether the measurement is a percentage.

Unit come in three types, the normal unit, the rate unit (which give a
``per time'' modifiers) and a modifier unit (which gives whether the
measurement has a modifier unit, and whether it is a division or a
multiplication.

The units on a sensor are specified as a base unit, and optional
modifier unit and how that is used, and a rate unit.  The modifier
unit is specified in the same type as a base unit.  A boolean
specifying whether the value is a percentage is also available.

This may sound somewhat complicated, but it is not as bad as it
sounds.  In most cases only the base unit is used, the modifier unit
use is none (thus the modifier is turned off), the rate unit is none,
and it is not a percentage.  But you can use all of these.  For
instance, if a sensor measures percent of newton$\times$meters per second,
that would use all of these.  The base unit would be newtons, the
modifier unit use would be multiply, the modifier unit would be
meters, the rate unit would be per second, and the percentage would be
true.

The following functions return these units for a sensor:
\begin{verbatim}
enum ipmi_unit_type_e ipmi_sensor_get_base_unit(ipmi_sensor_t *sensor);
enum ipmi_unit_type_e ipmi_sensor_get_modifier_unit(ipmi_sensor_t *sensor);
enum ipmi_rate_unit_e ipmi_sensor_get_rate_unit(ipmi_sensor_t *sensor);
enum ipmi_modifier_unit_use_e ipmi_sensor_get_modifier_unit_use(
    ipmi_sensor_t *sensor);
int ipmi_sensor_get_percentage(ipmi_sensor_t *sensor);
\end{verbatim}
The following return string representations for the units:
\begin{verbatim}
char *ipmi_sensor_get_rate_unit_string(ipmi_sensor_t *sensor);
char *ipmi_sensor_get_base_unit_string(ipmi_sensor_t *sensor);
char *ipmi_sensor_get_modifier_unit_string(ipmi_sensor_t *sensor);
\end{verbatim}
Note that for OEM values, OEM code may set the strings even though the
unit enumerations return an invalid value.  So use the strings if you
can.

As a quick example, the following code will print out a value with all
the various units attached:
\begin{verbatim}
char *percent = "";
char *base;
char *mod_use = "";
char *modifier = "";
char *rate;

base = ipmi_sensor_get_base_unit_string(sensor);
if (ipmi_sensor_get_percentage(sensor))
    percent = "%";
switch (ipmi_sensor_get_modifier_unit_use(sensor)) {
case IPMI_MODIFIER_UNIT_NONE:
    break;
case IPMI_MODIFIER_UNIT_BASE_DIV_MOD:
    mod_use = "/";
    modifier = ipmi_sensor_get_modifier_unit_string(sensor);
    break;
case IPMI_MODIFIER_UNIT_BASE_MULT_MOD:
    mod_use = "*";
    modifier = ipmi_sensor_get_modifier_unit_string(sensor);
    break;
}
rate = ipmi_sensor_get_rate_unit_string(sensor);

printf("  value: %lf%s %s%s%s%s\n", val, percent,
           base, mod_use, modifier, rate);
\end{verbatim}

The modifier units uses in OpenIPMI are:
\begin{tightdefs}
\item IPMI\_MODIFIER\_UNIT\_NONE
\item IPMI\_MODIFIER\_UNIT\_BASE\_DIV\_MOD
\item IPMI\_MODIFIER\_UNIT\_BASE\_MULT\_MOD
\end{tightdefs}
The rate units are:
\begin{tightdefs}
\item IPMI\_RATE\_UNIT\_NONE
\item IPMI\_RATE\_UNIT\_PER\_US
\item IPMI\_RATE\_UNIT\_PER\_MS
\item IPMI\_RATE\_UNIT\_PER\_SEC
\item IPMI\_RATE\_UNIT\_MIN
\item IPMI\_RATE\_UNIT\_HOUR
\item IPMI\_RATE\_UNIT\_DAY
\end{tightdefs}
The normal units are:
\begin{tightdefs}
\item IPMI\_UNIT\_TYPE\_UNSPECIFIED
\item IPMI\_UNIT\_TYPE\_DEGREES\_C
\item IPMI\_UNIT\_TYPE\_DEGREES\_F
\item IPMI\_UNIT\_TYPE\_DEGREES\_K
\item IPMI\_UNIT\_TYPE\_VOLTS
\item IPMI\_UNIT\_TYPE\_AMPS
\item IPMI\_UNIT\_TYPE\_WATTS
\item IPMI\_UNIT\_TYPE\_JOULES
\item IPMI\_UNIT\_TYPE\_COULOMBS
\item IPMI\_UNIT\_TYPE\_VA
\item IPMI\_UNIT\_TYPE\_NITS
\item IPMI\_UNIT\_TYPE\_LUMENS
\item IPMI\_UNIT\_TYPE\_LUX
\item IPMI\_UNIT\_TYPE\_CANDELA
\item IPMI\_UNIT\_TYPE\_KPA
\item IPMI\_UNIT\_TYPE\_PSI
\item IPMI\_UNIT\_TYPE\_NEWTONS
\item IPMI\_UNIT\_TYPE\_CFM
\item IPMI\_UNIT\_TYPE\_RPM
\item IPMI\_UNIT\_TYPE\_HZ
\item IPMI\_UNIT\_TYPE\_USECONDS
\item IPMI\_UNIT\_TYPE\_MSECONDS
\item IPMI\_UNIT\_TYPE\_SECONDS
\item IPMI\_UNIT\_TYPE\_MINUTE
\item IPMI\_UNIT\_TYPE\_HOUR
\item IPMI\_UNIT\_TYPE\_DAY
\item IPMI\_UNIT\_TYPE\_WEEK
\item IPMI\_UNIT\_TYPE\_MIL
\item IPMI\_UNIT\_TYPE\_INCHES
\item IPMI\_UNIT\_TYPE\_FEET
\item IPMI\_UNIT\_TYPE\_CUBIC\_INCHS
\item IPMI\_UNIT\_TYPE\_CUBIC\_FEET
\item IPMI\_UNIT\_TYPE\_MILLIMETERS
\item IPMI\_UNIT\_TYPE\_CENTIMETERS
\item IPMI\_UNIT\_TYPE\_METERS
\item IPMI\_UNIT\_TYPE\_CUBIC\_CENTIMETERS
\item IPMI\_UNIT\_TYPE\_CUBIC\_METERS
\item IPMI\_UNIT\_TYPE\_LITERS
\item IPMI\_UNIT\_TYPE\_FL\_OZ
\item IPMI\_UNIT\_TYPE\_RADIANS
\item IPMI\_UNIT\_TYPE\_SERADIANS
\item IPMI\_UNIT\_TYPE\_REVOLUTIONS
\item IPMI\_UNIT\_TYPE\_CYCLES
\item IPMI\_UNIT\_TYPE\_GRAVITIES
\item IPMI\_UNIT\_TYPE\_OUNCES
\item IPMI\_UNIT\_TYPE\_POUNDS
\item IPMI\_UNIT\_TYPE\_FOOT\_POUNDS
\item IPMI\_UNIT\_TYPE\_OUNCE\_INCHES
\item IPMI\_UNIT\_TYPE\_GAUSS
\item IPMI\_UNIT\_TYPE\_GILBERTS
\item IPMI\_UNIT\_TYPE\_HENRIES
\item IPMI\_UNIT\_TYPE\_MHENRIES
\item IPMI\_UNIT\_TYPE\_FARADS
\item IPMI\_UNIT\_TYPE\_UFARADS
\item IPMI\_UNIT\_TYPE\_OHMS
\item IPMI\_UNIT\_TYPE\_SIEMENS
\item IPMI\_UNIT\_TYPE\_MOLES
\item IPMI\_UNIT\_TYPE\_BECQUERELS
\item IPMI\_UNIT\_TYPE\_PPM
\item IPMI\_UNIT\_TYPE\_reserved1
\item IPMI\_UNIT\_TYPE\_DECIBELS
\item IPMI\_UNIT\_TYPE\_DbA
\item IPMI\_UNIT\_TYPE\_DbC
\item IPMI\_UNIT\_TYPE\_GRAYS
\item IPMI\_UNIT\_TYPE\_SIEVERTS
\item IPMI\_UNIT\_TYPE\_COLOR\_TEMP\_DEG\_K
\item IPMI\_UNIT\_TYPE\_BITS
\item IPMI\_UNIT\_TYPE\_KBITS
\item IPMI\_UNIT\_TYPE\_MBITS
\item IPMI\_UNIT\_TYPE\_GBITS
\item IPMI\_UNIT\_TYPE\_BYTES
\item IPMI\_UNIT\_TYPE\_KBYTES
\item IPMI\_UNIT\_TYPE\_MBYTES
\item IPMI\_UNIT\_TYPE\_GBYTES
\item IPMI\_UNIT\_TYPE\_WORDS
\item IPMI\_UNIT\_TYPE\_DWORDS
\item IPMI\_UNIT\_TYPE\_QWORDS
\item IPMI\_UNIT\_TYPE\_LINES
\item IPMI\_UNIT\_TYPE\_HITS
\item IPMI\_UNIT\_TYPE\_MISSES
\item IPMI\_UNIT\_TYPE\_RETRIES
\item IPMI\_UNIT\_TYPE\_RESETS
\item IPMI\_UNIT\_TYPE\_OVERRUNS
\item IPMI\_UNIT\_TYPE\_UNDERRUNS
\item IPMI\_UNIT\_TYPE\_COLLISIONS
\item IPMI\_UNIT\_TYPE\_PACKETS
\item IPMI\_UNIT\_TYPE\_MESSAGES
\item IPMI\_UNIT\_TYPE\_CHARACTERS
\item IPMI\_UNIT\_TYPE\_ERRORS
\item IPMI\_UNIT\_TYPE\_CORRECTABLE\_ERRORS
\item IPMI\_UNIT\_TYPE\_UNCORRECTABLE\_ERRORS
\item IPMI\_UNIT\_TYPE\_FATAL\_ERRORS
\item IPMI\_UNIT\_TYPE\_GRAMS
\end{tightdefs}
The meanings of these values are not defined by the spec, but should
be fairly obvious.

\subsubsection{Threshold Sensor Hysteresis in OpenIPMI}

OpenIPMI allows hysteresis to be fetched form a sensor and written to
a sensor.  Unfortunately, OpenIPMI does not have a very good way to
represent the actual hysteresis value.  The trouble is that hysteresis
is not set per-threshold; it only has one hysteresis value that is
applied to all thresholds for a sensor.  This means that you cannot
set a floating-point offset for hysteresis because the same
floating-point hysteresis value may result in a different raw
hysteresis value for each sensor\footnote{This is due to the fact that
some sensors are non-linear.}.  This is one of the rare situations
where IPMI could have been a bit more flexible (usually it is too
flexible).  Because of this situation, the hysteresis value is set as
a raw value.

A separate positive and negative hysteresis can exist for a sensor.
The positive value is for the ``going higher'' thresholds, it is the
amount that must be subtracted from the threshold where the threshold
will go back in range.  The negative value is for the ``going lower''
thresholds, it is the amount that must be added to the threshold where
the threshold will go back in range.

To know what type of hysteresis a sensor supports, use:
\begin{verbatim}
int ipmi_sensor_get_hysteresis_support(ipmi_sensor_t *sensor);
\end{verbatim}
This returns one of the following values:
\begin{description}
\item[IPMI\_HYSTERESIS\_SUPPORT\_NONE] - The sensor does not support
  hysteresis.
\item[IPMI\_HYSTERESIS\_SUPPORT\_READABLE] - The sensor has hysteresis, but
  the value cannot be set.  It can be read.
\item[IPMI\_HYSTERESIS\_SUPPORT\_SETTABLE] - The sensor has hysteresis and
  the value can be both set and read.
\item[IPMI\_HYSTERESIS\_SUPPORT\_FIXED] - The sensor has hysteresis
  but the value cannot be read or set.  If the default hysteresis values
  are non-zero, then they are the fixed hysteresis for the sensor.  Otherwise
  the values are unknown.
\end{description}

The default hystersis can be read using:
\begin{verbatim}
int ipmi_sensor_get_positive_going_threshold_hysteresis(ipmi_sensor_t *sensor);
int ipmi_sensor_get_negative_going_threshold_hysteresis(ipmi_sensor_t *sensor);
\end{verbatim}
To fetch and set the current threshold values for a sensor (assuming
it support these operations), use:
\begin{verbatim}
typedef void (*ipmi_sensor__hysteresis_cb)(ipmi_sensor_t *sensor,
                                           int           err,
                                           unsigned int  positive_hysteresis,
                                           unsigned int  negative_hysteresis,
                                           void          *cb_data);
int ipmi_sensor_get_hysteresis(ipmi_sensor_t           *sensor,
                               ipmi_hysteresis_get_cb done,
                               void                   *cb_data);

int ipmi_sensor_set_hysteresis(ipmi_sensor_t       *sensor,
                               unsigned int        positive_hysteresis,
                               unsigned int        negative_hysteresis,
                               ipmi_sensor_done_cb done,
                               void                *cb_data);
\end{verbatim}

\subsubsection{Threshold Sensor Reading Information in OpenIPMI}

In addition to all this, \acs{IPMI} gives some more information about
the readings.  The following allow the user to get the accuracy and
tolerance of the readings from the sensor:
\begin{verbatim}
int ipmi_sensor_get_tolerance(ipmi_sensor_t *sensor,
                              int           val,
                              double        *tolerance);
int ipmi_sensor_get_accuracy(ipmi_sensor_t *sensor, int val, double *accuracy);
\end{verbatim}

The sensor also may have defined ranges and nominal readings.  If a
value of this type is specified, then the \texttt{\_specified}
functions below will return true and the specific value will be
available:
\begin{verbatim}
int ipmi_sensor_get_normal_min_specified(ipmi_sensor_t *sensor);
int ipmi_sensor_get_normal_min(ipmi_sensor_t *sensor, double *normal_min);

int ipmi_sensor_get_normal_max_specified(ipmi_sensor_t *sensor);
int ipmi_sensor_get_normal_max(ipmi_sensor_t *sensor, double *normal_max);

int ipmi_sensor_get_nominal_reading_specified(ipmi_sensor_t *sensor);
int ipmi_sensor_get_nominal_reading(ipmi_sensor_t *sensor,
                                    double *nominal_reading);
\end{verbatim}
The normal min and max give the standard operating range of a sensor.
The nominal reading is the ``normal'' value the sensor should read.

The sensor may also have absolute minimum and maximum values.  These
can be fetched with the following functions:
\begin{verbatim}
int ipmi_sensor_get_sensor_max(ipmi_sensor_t *sensor, double *sensor_max);
int ipmi_sensor_get_sensor_min(ipmi_sensor_t *sensor, double *sensor_min);
\end{verbatim}

\subsection{Discrete Sensors in OpenIPMI}

The value of a discrete sensor is its states, the value of its bits.
Each bit is a single independent states; the bits are not used
together to represent multi-bit values.

\subsubsection{Discrete Sensor Readings in OpenIPMI}

To read the value of a discrete sensor, use the following:
\begin{verbatim}
typedef void (*ipmi_sensor_states_cb)(ipmi_sensor_t *sensor,
                                      int           err,
                                      ipmi_states_t *states,
                                      void          *cb_data);
int ipmi_sensor_get_states(ipmi_sensor_t       *sensor,
                           ipmi_states_read_cb done,
                           void                *cb_data);
\end{verbatim}

The values are returned in the states object.  To know if a specific
state will be set in the states structure for a sensor, use the function:
\begin{verbatim}
int ipmi_discrete_event_readable(ipmi_sensor_t *sensor,
                                 int           event,
                                 int           *val);
\end{verbatim}
This will set val to if the bit for the given sensor will support
being read.

Once you know if the bit is supported, the function:
\begin{verbatim}
int ipmi_is_state_set(ipmi_states_t *states,
                      int           state_num);
\end{verbatim}
will return true if the given state (bit) is set and false if it is
not set.

\subsubsection{Discrete Sensor Events in OpenIPMI}
\label{sec-discrete-sensor-events-in-openipmi}

To know if a specific bit can cause an event to be sent by the sensor,
use the following function:
\begin{verbatim}
int ipmi_sensor_discrete_event_supported(ipmi_sensor_t         *sensor,
                                         int                   offset,
                                         enum ipmi_event_dir_e dir,
                                         int                   *val);
\end{verbatim}
The \texttt{val} will be set to whether the event is supported or not.

To actually enable or disable individual events for a sensor, an event
state structure must be created.  An event state structure is passed
in when the event state of a sensor is queried.  To set or clear
individual events in one of these structures, use the following:
\begin{verbatim}
void ipmi_discrete_event_clear(ipmi_event_state_t    *events,
                               int                   event_offset,
                               enum ipmi_event_dir_e dir);
void ipmi_discrete_event_set(ipmi_event_state_t    *events,
                             int                   event_offset,
                             enum ipmi_event_dir_e dir);
\end{verbatim}
To see if a specific event is set, use:
\begin{verbatim}
int ipmi_is_discrete_event_set(ipmi_event_state_t    *events,
                               int                   event_offset,
                               enum ipmi_event_dir_e dir);
\end{verbatim}

\section{Sensor \acs{SDR}s}
\label{sec-sensor-sdrs}

TBD - write this

%---------------------------------------------------------------------
\chapter{Controls and Miscellany}

\section{Controls}

Standard \acs{IPMI} has no provision for an output device besides a
few simple functions like reset and power.  However, many systems have
OEM extensions that allow control of lights, display panels, relays,
and a lot of other things.  OpenIPMI adds the concept of a
``control'', which is an output device.

Each control has a specific type, that is fetched with:
\begin{verbatim}
int ipmi_control_get_type(ipmi_control_t *control);
\end{verbatim}
It returns one of the following values:
\begin{description}
\item[IPMI\_CONTROL\_LIGHT] - A light of some time, like an LED or a lamp.
\item[IPMI\_CONTROL\_RELAY] - A relay output
\item[IPMI\_CONTROL\_DISPLAY] - A 2-D text display
\item[IPMI\_CONTROL\_ALARM] - Some type of audible or visible warning device
\item[IPMI\_CONTROL\_RESET] - A reset line to reset something.  This type
  allows the value to be set as either on or off.
\item[IPMI\_CONTROL\_POWER] - Control of the power of something.
\item[IPMI\_CONTROL\_FAN\_SPEED] - Control of the fan speed.
\item[IPMI\_CONTROL\_IDENTIFIER] - A general identifier for the entity in
  question.  This is things like a serial number, a board type, or things
  of that nature.  These may or may not be writable.
\item[IPMI\_CONTROL\_ONE\_SHOT\_RESET] - A reset line, but setting the value
  to one does a reset and release of reset, you cannot hold the device
  in reset with one of these.
\item[IPMI\_CONTROL\_OUTPUT] - A general output device like a digital output.
\item[IPMI\_CONTROL\_ONE\_SHOT\_OUTPUT] - A general one-shot output device.
\end{description}
The function:
\begin{verbatim}
char *ipmi_control_get_type_string(ipmi_control_t *control);
\end{verbatim}
returns a string representation of the control type for the control.

Some controls may have multiple objects that cannot be independently
controlled.  For example, if a message is sent to set the value of
three LEDs and it has one byte for each LED and no way to set ``only
set this one'', then there is no generally and guaranteed way to
independently control each LED.  In these cases, OpenIPMI represents
these as a control with multiple values.  When setting, all the values
must be specified.  When reading, all the values are returned.  To get
the number of values for a control, use the following function:
\begin{verbatim}
int ipmi_control_get_num_vals(ipmi_control_t *control);
\end{verbatim}

\subsubsection{Control Entity Information}
Every control is associated with a specific entity, these calls let you
fetch the entity information.  The following calls return the numeric
entity id and instance:
\begin{verbatim}
int ipmi_control_get_entity_id(ipmi_control_t *control);
int ipmi_control_get_entity_instance(ipmi_control_t *control);
\end{verbatim}
Generally, though, that is note what you want.  You want the actual
entity object, which may be fetched with the following:
\begin{verbatim}
ipmi_entity_t *ipmi_control_get_entity(ipmi_control_t *control);
\end{verbatim}
Note that the entity is refcounted when the control is claimed, so the
entity will exist while you have a valid reference to a control it
contains.

\subsection{Control Name}

Controls are given a name by the OEM code that creates them.  This is
useful for printing out control information.  The functions to get
this are:
\begin{verbatim}
int ipmi_control_get_id_length(ipmi_control_t *control);
enum ipmi_str_type_e ipmi_control_get_id_type(ipmi_control_t *control);
int ipmi_control_get_id(ipmi_control_t *control, char *id, int length);
\end{verbatim}
See appendix~\ref{appendix-ipmi-strings} for more information about
these strings.

The function
\begin{verbatim}
int ipmi_control_get_name(ipmi_control_t *control, char *name, int length);
\end{verbatim}
returns a fully qualified name for the control with the entity name
prepended.  The name array is filled with the name, up to the length
given.  This is useful for printing string names for the control.

\subsection{Controls and Events}

Controls may support events, much like sensors.  The function:
\begin{verbatim}
int ipmi_control_has_events(ipmi_control_t *control);
\end{verbatim}
tells if a control supports events.

To register/unregister for control events, use the functions:
\begin{verbatim}
typedef int (*ipmi_control_val_event_cb)(ipmi_control_t *control,
                                         int            *valid_vals,
                                         int            *vals,
                                         void           *cb_data,
                                         ipmi_event_t   *event);
int ipmi_control_add_val_event_handler(ipmi_control_t            *control,
                                       ipmi_control_val_event_cb handler,
                                       void                      *cb_data);
int ipmi_control_remove_val_event_handler(ipmi_control_t            *control,
                                          ipmi_control_val_event_cb handler,
                                          void                      *cb_data);
\end{verbatim}
In the callback, not all values may be present.  The \verb=valid_vals=
parameter is an array of booleans telling if specific values are
present.  If an item in that array is true, then the corresponding
value in the \verb=vals= array is a valid value.  This is a standard
event handler as defined in section~\vref{sec-openipmi-events}.

\subsection{Basic Type Controls}
\label{sec-basic-type-controls}
This section describes the more ``normal'' controls, that generally
have a single value that is a binary or some type of direct setting.
These take an integer value per control for their setting.  These
control types are:
\begin{description}
\item[relay]
\item[alarm]
\item[reset]
\item[power]
\item[fan speed]
\item[one-shot reset]
\item[output]
\item[one-shot output]
\end{description}

To set the value of one of these controls, use the following:
\begin{verbatim}
int ipmi_control_set_val(ipmi_control_t     *control,
                         int                *val,
                         ipmi_control_op_cb handler,
                         void               *cb_data);
\end{verbatim}
Pass in an array of integers for the values, the length of which
should be the number of values the control supports.  To get the value
of a control, use:
\begin{verbatim}
typedef void (*ipmi_control_val_cb)(ipmi_control_t *control,
                                    int            err,
                                    int            *val,
                                    void           *cb_data);
int ipmi_control_get_val(ipmi_control_t      *control,
                         ipmi_control_val_cb handler,
                         void                *cb_data);
\end{verbatim}
The \texttt{val} returns is an array of integers, the length is the
number of values the control supports.

\subsection{Light}
\label{controls-light}

Lights come in two flavors.  Some lights have absolute control of the
color, on time, and off time.  OpenIPMI call these ``setting'' lights.
Other lights have fixed functions; they have a few settings that have
fixed color and on/off values.  OpenIPMI calles these ``transition''
lights.  Both types are fully supported.

To know if a light control is a setting or transition light, the
following function returns true for a setting light and false for a
transition light:
\begin{verbatim}
int ipmi_control_light_set_with_setting(ipmi_control_t *control);
\end{verbatim}

Lights can be different colors, and the interface allows the supported
colors to be check and set.  The supported colors are:
\begin{tightdefs}
\item IPMI\_CONTROL\_COLOR\_BLACK
\item IPMI\_CONTROL\_COLOR\_WHITE
\item IPMI\_CONTROL\_COLOR\_RED
\item IPMI\_CONTROL\_COLOR\_GREEN
\item IPMI\_CONTROL\_COLOR\_BLUE
\item IPMI\_CONTROL\_COLOR\_YELLOW
\item IPMI\_CONTROL\_COLOR\_ORANGE
\end{tightdefs}

\subsubsection{Setting Light}

Setting lights are managed with an abstract data structure:
\begin{verbatim}
typedef struct ipmi_light_setting_s ipmi_light_setting_t;
\end{verbatim}
This is a standard OpenIPMI opaque data structure.  Like most other
data structures of this type, this does not directly modify the light,
this is used to transmit the settings to a light and to receive the
settings from a light.  To allocate/free these, use the following:
\begin{verbatim}
ipmi_light_setting_t *ipmi_alloc_light_settings(unsigned int count);
void ipmi_free_light_settings(ipmi_light_setting_t *settings);
\end{verbatim}
A function is also available to duplicate these objects:
\begin{verbatim}
ipmi_light_setting_t *ipmi_light_settings_dup(ipmi_light_setting_t *settings);
\end{verbatim}

Each light setting has the settings for all lights for the control.
If you allocate a light setting, you must pass in the number of lights
the control manages.  You can also fetch this from the setting using:
\begin{verbatim}
unsigned int ipmi_light_setting_get_count(ipmi_light_setting_t *setting);
\end{verbatim}

Setting type lights have the concept of ``local control''.  When a
light is in local control, the light is managed by the system it runs
on.  If local control is turned off, then the light can be directly
managed.  For instance, the system may have an LED that when under
local control displays disk activity.  However, it may be possible for
the management system to take over that LED and use it for another
purpose.  Local control is set and modified in a setting using the
functions:
\begin{verbatim}
int ipmi_light_setting_in_local_control(ipmi_light_setting_t *setting,
                                        int                  num,
                                        int                  *lc);
int ipmi_light_setting_set_local_control(ipmi_light_setting_t *setting,
                                         int                  num,
                                         int                  lc);
\end{verbatim}
The \verb=num= parameter is the light number to set (which of the
lights the control managers).  The \verb=lc= parameter is the local
control control setting.  These return error values if the parameters
are out of range.  If local control is not supported, this is
generally ignored.

To know if a light supports a specific color, the function:
\begin{verbatim}
int ipmi_control_light_is_color_supported(ipmi_control_t *control,
                                          unsigned int   color);
\end{verbatim}
To set the color in a setting and extract the color from a setting, use:
\begin{verbatim}
int ipmi_light_setting_get_color(ipmi_light_setting_t *setting, int num,
                                 int *color);
int ipmi_light_setting_set_color(ipmi_light_setting_t *setting, int num,
                                 int color);
\end{verbatim}

These types of lights also support on and off times.  The on and off
times are directly set, so the user has direct control of this.  Note
that on and off times may be approximate.  To set or get the on and off
times in a setting, use:
\begin{verbatim}
int ipmi_light_setting_get_on_time(ipmi_light_setting_t *setting, int num,
                                   int *time);
int ipmi_light_setting_set_on_time(ipmi_light_setting_t *setting, int num,
                                   int time);
int ipmi_light_setting_get_off_time(ipmi_light_setting_t *setting, int num,
                                    int *time);
int ipmi_light_setting_set_off_time(ipmi_light_setting_t *setting, int num,
                                    int time);
\end{verbatim}
The times are specified in milliseconds.

To fetch the current settings of a light control, use:
\begin{verbatim}
typedef void (*ipmi_light_settings_cb)(ipmi_control_t       *control,
                                       int                  err,
                                       ipmi_light_setting_t *settings,
                                       void                 *cb_data);
int ipmi_control_get_light(ipmi_control_t         *control,
                           ipmi_light_settings_cb handler,
                           void                   *cb_data);
\end{verbatim}
Once you receive the settings, use the get functions to get the data
you want from it.  Note that the \verb=settings= parameter is freed by
the system; if you want to keep the settings around you should
duplicate them.

To set the settings of a light control, first create and configure a
light setting object, then pass it to:
\begin{verbatim}
int ipmi_control_set_light(ipmi_control_t       *control,
                           ipmi_light_setting_t *settings,
                           ipmi_control_op_cb   handler,
                           void                 *cb_data);
\end{verbatim}

\subsubsection{Transition Light}

For a transition light control, each control has one or more lights.
Each light is an lightable device, but all the lights in a control are
changed together.  To get the number of lights supported by a control,
use:
\begin{verbatim}
int ipmi_control_get_num_vals(ipmi_control_t *control);
\end{verbatim}

Each light has a number of values that it may be set to.  The value is
what is passed to \verb=set_control=.  See
section~\vref{sec-basic-type-controls} for details on how to use
\verb=set_control=.  To find the number of values for a light, use
\begin{verbatim}
int ipmi_control_get_num_light_values(ipmi_control_t *control, light);
\end{verbatim}

Each value of a light has a number of transitions that it may go
through.  Each transition has a color and a time when that colors
runs.

This all sounds complicated, but it is really fairly simple.
Suppose a control has two lights.  Say light 0 is a red led.  Light
0 has 4 values: off, 100ms on and 900ms off, 900ms on and 100ms
off, and always on.  For value 0, it will have one transition and the
color will be black (time is irrelevant with one transition).  For
value 1, it will have two transitions, the first has a color of
black and a time of 900 and the second has a color of red and a
time of 100.  Likewise, value 2 has two transitions, the first is
black with a time of 100 and the second is red with a value of 900.
Value 4 has one transition with a red color.

To get the number of transitions in a value, call the function:
\begin{verbatim}
int ipmi_control_get_num_light_transitions(ipmi_control_t *control,
                                           unsigned int   light,
                                           unsigned int   value);
\end{verbatim}
For each transition, use the following functions to fetch the color
and time for that transition:
\begin{verbatim}
int ipmi_control_get_light_color(ipmi_control_t *control,
                                 unsigned int   light,
                                 unsigned int   value,
                                 unsigned int   transition);
int ipmi_control_get_light_color_time(ipmi_control_t *control,
                                      unsigned int   light,
                                      unsigned int   value,
                                      unsigned int   transition);
\end{verbatim}

\subsection{Display}

The function of a display is TBD until the author of OpenIPMI gets a
system that supports one :-).

\subsection{Identifier}

An identifier control holds some type of information about the system,
the specific type of something, a serial number or other identifier,
or things of that nature.  They are represented as an array of bytes.

To find the maximum number of bytes a control may be set to or will
return, use the function:
\begin{verbatim}
unsigned int ipmi_control_identifier_get_max_length(ipmi_control_t *control);
\end{verbatim}

To set and get the value of a control, use:
\begin{verbatim}
typedef void (*ipmi_control_identifier_val_cb)(ipmi_control_t *control,
                                               int            err,
                                               unsigned char  *val,
                                               int            length,
                                               void           *cb_data);
int ipmi_control_identifier_get_val(ipmi_control_t                 *control,
                                    ipmi_control_identifier_val_cb handler,
                                    void                           *cb_data);
int ipmi_control_identifier_set_val(ipmi_control_t     *control,
                                    unsigned char      *val,
                                    int                length,
                                    ipmi_control_op_cb handler,
                                    void               *cb_data);
\end{verbatim}

\subsection{Chassis Controls}
The \acs{IPMI} standard supports two basic controls if the system
supports chassis control.  OpenIPMI automatically detects these and
creates controls for them.  The controls created are created on the
chassis entity id (id 23.1) and are named:

\noindent\begin{tabularx}{\textwidth}{|l|X|}
\hline
reset & A one-shot reset that can reset the processor in the chassis.\\
\hline
power & A binary power control that can turn on and turn off power to a
        chassis.\\
\hline
\end{tabularx}

\section{Watchdog Timer}

TBD - determine if we really need watchdog timer support, write it and
document it if so.  Currently the OpenIPMI library does not support
the watchdog timer, but the Linux IPMI driver does support it through
the standard watchdog timer interface.

\section{Direct \acs{I$^2$C} Access}

%---------------------------------------------------------------------
\chapter{Events}
\label{events}

OpenIPMI automatically sets the event receiver.

\section{Event Format}
\label{event-format}

\section{Event Data Information for Specific Events}
\label{sec-event-data-info-for-events}

\begin{longtable}{|p{0.21\textwidth}|l|p{0.67\textwidth}|}
\hline
SYSTEM \_FIRMWARE \_PROGRESS & 00h &
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
 & 01h & Uses the same values as offset 00h.\\
 & 02h & 
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
\hline
EVENT\_LOGGING \_DISABLED & 01h &
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
\hline
SYSTEM\_EVENT & 03h &
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
 & 04h &
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
\hline
SLOT\_CONNECTOR & all &
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
\hline
WATCHDOG\_2 & all &
        \begin{tightdefs}
        \item[] - 
        \end{tightdefs}\\
\hline
\end{longtable}

\section{\acs{MC} Event Enables}
Note there is a section in the MC chapter about this.

\section{Coordinating Multiple Users of an \acs{SEL}}
\label{multiple-sel-users}
If multiple things are managing an SEL, such as two instances of a
redundant LAN application, you generally want both applications to be
able to see all events.  This means that they must coordinate deletion
of logs from the SEL.  Generally, you want an application to be able
to pull events from the SEL, store them in some other non-volatile
storage, and then delete the events from the SEL.

If two applications are doing this, you can have each application wait
for twice at least twice the SEL polling time and delete the event.
This give all applications a chance to polls the SEL and pull out the
events.  OpenIPMI will correctly handle situations where another
system has deleted an event from the SEL.

It is also possible to send the events between the systems and use the
timestamps and event numbers to detect redundant copies.  This is
obviously more complex, but covers situations where one system may
have been down for a time and needs copies of events it may have
missed.

%---------------------------------------------------------------------
\chapter{Other OpenIPMI Concerns}
\label{chap-other-openipmi-concerns}

\section{When Operations Happen}

As mentioned before, OpenIPMI has a very dynamic view of the domain.
It also reports things as it finds them, but the work on those things
is not necessarily ``done''.  OpenIPMI has no concept of anything
being ``done''; it views a domain as a dynamic entity that can change
over time.

In some cases, though, it may be useful to know when certain
operations complete.  The following call will tell you when the main
\ac{SDR} repository has been read.  You can call it after you create the
domain but before the domain has finished initialization; you can
register your own handler here:

\begin{verbatim}
int
ipmi_domain_set_main_SDRs_read_handler(ipmi_domain_t  *domain,
                                       ipmi_domain_cb handler,
                                       void           *cb_data)
\end{verbatim}

Likewise, when a \ac{MC} is reported the \acs{SDR}s and events have
not yet been read.  To register handlers for those, use:

\begin{verbatim}
int ipmi_mc_set_sdrs_first_read_handler(ipmi_mc_t      *mc,
                                        ipmi_mc_ptr_cb handler,
                                        void           *cb_data);
int ipmi_mc_set_sels_first_read_handler(ipmi_mc_t      *mc,
                                        ipmi_mc_ptr_cb handler,
                                        void           *cb_data);
\end{verbatim}

Note that you should almost certainly \emph{not} use these, unless you
absolutely have to.  In general, your software should handle the
dynamic nature of an \ac{IPMI} system dynamically.

%---------------------------------------------------------------------
\appendix

\chapter{Special \acs{IPMI} Formats}

\section{\acs{IPMI} strings}
\label{appendix-ipmi-strings}

IPMI uses a special format for storing strings.  It allows data to be
stored in four different formats.  The first byte describes the type
and length; the format is:
\begin{tightdefs}
\item[bits 0-4] - The number of bytes following this byte.  Note that
this is \emph{not} the number of characters in the string, it is the
number of bytes following.  The value of 11111b is reserved.
\item[bit 5] - reserved
\item[bits 6-7] - The string type.  Valid values are:
  \begin{tightdefs}
  \item[00h] - Unicode
  \item[01h] - BCD plus
  \item[02h] - 6-bit ASCII, packed
  \item[03h] - 8-bit ASCII and Latin 1.  In this case, a length of one is
    reserved.  The length may be zero, or it may be from 2 to 30, but may
    not be 1.
  \end{tightdefs}
\end{tightdefs}

The values and packing are defined in the IPMI spec.

TBD - add character values and packing information

\subsection{OpenIPMI and \acs{IPMI} strings}
OpenIPMI does most of the work of decoding the \acs{IPMI} strings.
Generally, to fetch a string, three functions are supported that
generally look something like:
\begin{verbatim}
int ipmi_xxx_get_id_length(ipmi_xxx_t *obj);
enum ipmi_str_type_e ipmi_xxx_get_id_type(ipmi_xxx_t *obj);
int ipmi_xxx_get_id(ipmi_xxx_t *obj, char *id, int length);
\end{verbatim}
Fetching the type allows you to tell what it is.  The type may be one of:
\begin{description}
\item[IPMI\_ASCII\_STR] - The value is in normal ASCII and Latin 1
\item[IPMI\_UNICODE\_STR] - The value is unicode encoded.
\item[IPMI\_BINARY\_STR] - The value is raw binary data.
\end{description}
Then you can get the length to know how long the value will be.  Then
fetch the actual id with the get id call; it will store the value in
the id passed in.  The get id call will return the number of bytes
copied into into the id string.  The size of the id string should be
passed in to the ``length'' field.  The number of bytes actually
copied will be returned by the call.  If the number of bytes is more
than the length of the id field, then only ``length'' bytes are filled
in.

\chapter{The Perl Interface}

OpenIPMI has interface code that let's Perl programs use OpenIPMI.
The interface works much like the C interface.  Some things are
simplified, but in general it is very similar.

The interface uses object-oriented programming in Perl, so you must
know how to do that in Perl.  It's pretty simple, really, but it's
somewhat strange if you already know another OO programming language.

As an example, to create a domain connection and read all the events,
you might use the following code:

\verbatimtabinput{\topdir/swig/perl/get_events}

Unfortunately, the documentation for the Perl interface is in the file
\verb=swig/OpenIPMI.i= along with the sources.  It will hopefully be
here in the future.

\chapter{Comparison with \acs{SNMP}}

\chapter{Comparison with \acs{HPI}}
\label{comparison-with-hpi}
OpenIPMI and HPI cover much of the same functionality.  Many of the
concepts are similar.  OpenIPMI was designed so that HPI could be
implemented on top of it, so they are not necessarily competing
technologies.

The only thing that HPI provides that OpenIPMI doesn't is a watchdog
interface.  Since that's really more a function of the OS and not
something useful for remote systems, OpenIPMI didn't implement this
and left that to the OS.

OpenIPMI provides access to the configuration information for LAN
interfaces, channel management, and user management.  HPI doesn't
provide this.  Indeed it couldn't because that type of thing is too
hard to abstract and too specific to IPMI.  So even if you use HPI,
you will need something like OpenIPMI to manage the IPMI-specific
things in your system.

Both HPI and OpenIPMI have the concept of a domain, entity, sensor,
and control.  For the most part, they are the same.  In theory the
domain concept of HPI is more general than OpenIPMI's.  In practice
they are usually the same.  Entities do not differ in concept, but
they are first-class objects in OpenIPMI.  In HPI they are a set of
numbers that identify a ``path'', but don't have actual data
associated with them and you cannot perform operations on them.

HPI adds a ``resource'' object that OpenIPMI doesn't really have.  An
RDR many of the things that entities do in OpenIPMI.  For instance,
hot-swap is on entities in OpenIPMI, but is on RDRs in HPI.  In
effect, HPI split the concept of an IPMI entity into two things, one
for identifying the things sensors and controls are attached to, and
one for the inventory data, hot-swap control, and some other things.
This split is artifical from IPMI's point of view; it makes no such
distinction.

The biggest conceptual difference between OpenIPMI and HPI is that
OpenIPMI is event-driven as described in
section~\vref{event-driven-systems}.  This means that it is possible
to create complex and live systems with OpenIPMI without using threads
or low-level polling.  This is not possible with HPI.  Event-driven
system are somewhat strange to use if you haven't used them before,
though.

HPI is a standard.  It can be used with non-IPMI systems.  These
things count for a lot.

%---------------------------------------------------------------------
\chapter{\acs{ATCA}}
\label{app-atca}
\acs{ATCA} is a standard specified by PICMG for highly available
hardware.  These are bus systems where a number of cards are plugged
into a backplane.  The backplane has redundant \acs{IPMB} management
busses and can have redundant \acs{BMC}s.  In \acs{ATCA}, the
\acs{BMC} is called the ``Shelf Manager'' (this is not quite correct,
but close enough for this discussion).  The individual management
controllers on a board are called ``\acs{IPMC}s.''  Something that connects
to the Shelf Managers is called a ``System Manager.''

The OpenIPMI library will auto-detect an \acs{ATCA} system and configure
itself properly.

Unlike the \acs{IPMI} spec, the \acs{ATCA} spec is fairly well written and
easy to understand.  Reading it is highly recommended if you are
programming on an \acs{ATCA} system.

OpenIPMI maps the \acs{ATCA} system into a fairly standard \acs{IPMI}
configuration.  This is relatively transparent because \acs{ATCA} was
designed to work with the \acs{IPMI} spec and \acs{IPMI}-specified
operations are used when possible.  The entire shelf is represented as
entity 23.1.  Each of the boards will appear as contained inside
entity 23.1.

\section{Management Redundancy in \acs{ATCA}}
In general the redundancy in \acs{ATCA} is done by the \acs{ATCA}
system itself and is mostly invisible to the System Manager.  Though
there are multiple \acs{IPMB} busses, it looks like one except for
reporting of errors.  And the Shelf Managers will make the system look
like one IP address even if one Shelf Manager fails.

ECN002 of the \acs{ATCA} spec added the capability to supply all the
management IP addresses on an ATCA system.  OpenIPMI will
automatically detect this capability and create a port for each IP
address.  This port's info will show ATCA\_aux as the interface type.
The port cannot be activated, but reporting of the port's state tells
you if the port is up or down.  Note that ports can change
dynamically; if a port change comes in with an ENOENT error, that port
has been deleted.  You should check the port information each time the
port changes, as the ports may be reordered or reconfigured.

\section{Hot Swap in \acs{ATCA}}
The full standard OpenIPMI hot-swap state machine is implemented for
\acs{ATCA} systems and is fully operation.

\section{\acs{ATCA} \acs{FRU} Data}
OpenIPMI has decoders to decode all the standard \acs{ATCA} \acs{FRU}
data.  It uses the standard interface as defined in
section~\vref{generic-fru-data-interface}.  OpenIPMI will fetch the
\acs{ATCA} \acs{FRU} data for its own internal use, but the \acs{ATCA}
\acs{FRU} data is not fetched in a way that is visible to the user
because it does not appear in the standard locations for \acs{IPMI}
\acs{FRU}s.  The \acs{ATCA} spec defines how the user can find the
\acs{FRU} data; once the location is found the data can be fetched
using \verb=ipmi_fru_alloc()=.

\section{Special \acs{ATCA} Sensors}
All hot-swappable \acs{ATCA} entities have their own hot-swap sensor.
OpenIPMI will detect this sensor automatically and set it up properly.
It will report this sensor to the user, but the user \emph{must not}
modify the configuration of the sensor or it may mess up the hot-swap
state machine.  Use the hot-swap state machine instead of this sensor.

\acs{ATCA} specified other sensors, but the OpenIPMI \acs{ATCA} code
does not use these internally.

\section{Special \acs{ATCA} Shelf Controls}

OpenIPMI will create one control for ECN002 and later versions.  It is
a single control with all the power feeds defined in the power map.
The current value of each feed is in the control.  It is named
``power\_feeds'' and is attached to the shelf entity (23.1).

\section{Special \acs{ATCA} IPMC Controls}
\acs{ATCA} specifies a standard way to control LEDs on the board, and
it has a defined reset operation.

The LED controls appear as standard OpenIPMI light controls that use
setting controls, see the section~\vref{controls-light} for more
information on how to control these.  The first LED is always the blue
hot-swap LED and is named ``blue led''.  The other LEDs are labeled
``led 1'', ``led 2'', etc.

The reset control is named ``cold reset'' and can be used to reset the
main processor on the board.  If your board is \acs{ATCA} ECN002
compliant, it will have a way to detect additional controls:
\begin{description}
\item[warm reset]
\item[graceful reboot]
\item[diagnostic interrupt]
\end{description}
The operation of these is board-dependent.

Note that even though you could directly control the power on an
\acs{ATCA} board, you should not.  Use the hot-swap state machine.

In addition, an address control named ``address' is created for each
IPMC that has the address info: site type, site number, hardware
address, ipmb address, in that order.

\section{Chassis Controls and \acs{ATCA}}
The Shelf Manager is supposed to have the standard chassis controls
specified by \acs{IPMI} for power and reset.  \emph{Be very careful using
these.}  They affect the entire shelf.  So if you turn off the power
with the chassis power control, it will turn of \emph{every} board in
the shelf.

\section{\acs{AMC}}
\acs{AMC} was designed to work transparently with the \acs{ATCA} spec.
The \acs{IPMC} that manages the \acs{AMC} modules will represent the
\acs{AMC} modules to the shelf and system manager transparently, so in
general the user doesn't have to do anything special.  The \acs{AMC}s
will appear as hot-swap capable entities contained within their host
board's entity.

It may be necessary to directly communicate with the \acs{AMC}
modules.  From an OpenIPMI driver connection, you must send the
message using an \verb=ipmi_ipmb_addr= with channel 7 and the slave
address set to the \acs{IPMB} address of the \acs{AMC} module.  This
works transparently in the driver.\footnote{Note that some systems do
not correctly implement this due to a misunderstanding in the
\acs{AMC} spec.  The \acs{AMC} spec talks about using message tracking
to route messages from the \acs{IPMB} to the \acs{AMC}s.  It does
\emph{not} talk about using message tracking going from the system
interfaces to the \acs{AMC}s.  The \acs{IPMI} spec is quite clear that
\emph{only} untracked messages are used from the system interface.  If
you cannot talk to your \acs{AMC} board from the \acs{IPMI} driver, it may
be that the board does not properly handle untracked messages.}

Communicating directly to the \acs{AMC} over a LAN interface is more
complex.  You must format a send message command yourself, but only
the last level of the send message.  You would format a complete send
message command to channel 7 and the \acs{IPMB} address of the
\acs{AMC} module.  You then send this message using an
\verb=ipmi_ipmb_addr=, with the channel set to 0 and using the
\acs{IPMB} address of the \acs{IPMC} as the slave address.  You must
use message tracking.  Then the OpenIPMI library will format the
message properly to get it to the \acs{IPMC}.  Your send message
command will then be processed by the \acs{IPMC} and the message will
be routed to the \acs{AMC}.  The \acs{IPMC} takes care of handling the
response and returning it to you through the shelf manager.  This is
rather complex, but should be a seldom-used operation.  And if anyone
wants to make it simpler, patches are always appreciated.

%---------------------------------------------------------------------
\chapter{Motorola MXP}
\label{app-motorola-mxp}

%---------------------------------------------------------------------
\chapter{Intel Servers}
\label{app-intel-servers}

Many Intel server systems have an alarm panel and a relay output that
can be monitored and controlled through \acs{IPMI}.  This will appear under
entity 12.1 (Alarm Panel) and will be named ``alarm''.  It takes an
8-bit setting.  The meanings of the bits are:

\begin{longtable}{|l|p{0.8\textwidth}|}
\hline
7 &  Reserved, always write 1\\
\hline
6 &  LED colors, 1 = amber (default), 0 = red.  Note that the colors were
        added in some later firmware versions, not in all, and the
        colors may not affect all LEDs.\\
\hline
5 & Minor Relay bit, 0 = on, 1=off.  This is a read only bit and should
        always be written 1.\\
\hline
4 & Major Relay bit, 0 = on, 1=off.  This is a read only bit and should
        always be written 1.\\
\hline
3 & Minor LED bit, 0 = on, 1=off\\
\hline
2 & Major LED bit, 0 = on, 1=off\\
\hline
1 & Critical LED bit, 0 = on, 1=off\\
\hline
0 & Power LED bit, 0 = on, 1=off\\
\hline
\end{longtable}

%---------------------------------------------------------------------
\chapter{Sample Program Showing Basic Operations}
\label{app-sample-prog-basic}
The following program shows basic setup, registration, and registering
to handle new entitys, sensors, and controls as they are created.
Some basic information is dumped.

\verbatimtabinput{\topdir/sample/sample.c}

%---------------------------------------------------------------------
\chapter{Sample Program Showing Event Setup}
\label{app-sample-prog-event-setup}
The following program show how to set up events.  For every sensor
that is detected, it will turn on all events that the sensor supports.
\verbatimtabinput{\topdir/sample/sample3.c}

%---------------------------------------------------------------------
\chapter{Command Receiver Program}
\label{recv-cmd-prog}
\verbatimtabinput{\topdir/doc/recv_cmd.c}

%---------------------------------------------------------------------
\chapter{Connection Handling Interface (ipmi\_conn.h)}
\label{ipmi-conn-h}
\verbatimtabinput{\topdir/include/OpenIPMI/ipmi_conn.h}

%---------------------------------------------------------------------
\chapter{OS Handler Interface (os\_handler.h)}
\label{os-handler-h}
\verbatimtabinput{\topdir/include/OpenIPMI/os_handler.h}

\bibliographystyle{plain}
\bibliography{ipmi}
\backmatter
\end{document}
