$Id: design.xml,v 1.6 2005/02/23 01:15:06 martins Exp $
Copyright © 2004, 2005 IBM Corporation
Table of Contents
The Linux lsvpd package is a partial reimplementation, for Linux®, of some AIX® hardware inventory and configuration commands. The focus is on providing some of the same serviceability features when running Linux on IBM® pSeries® hardware as is provided by AIX. The main function is to list Vital Product Data (VPD) about hardware components, including systems, adapters and devices, in a variety of ways.
This documentation contains design and implementation notes for the Linux lsvpd package. This documentation is aimed at developers who are attempting to update the package. Installation notes are in a different document.
Commands in the package belong to one of two categories: data collection (or scanning) and querying.
Information about hardware is collected and stored in a database under /var/lib/lsvpd/db-DATE-TIME (formerly /var/lib/lsvpd/device-tree, with some supplementary information stored in other subdirectories of /var/lib/lsvpd). There is generally a symbolic link /var/lib/lsvpd/db pointing the the most recent database - so we will use this name to refer to the database in this document. Currently there is only a single data collection command called update-lsvpd-db, which is invoked at boot time and can also be run manually at any time. update-lsvpd-db's main job is to construct linux,vpd directories, containing VPD, for use by the querying commands.
It is assumed that under Linux 2.4 there will be no hotplug events that the lsvpd package needs to know about. Under Linux 2.6 this will change, so finer grain data collection will need to be implemented.
The query commands find VPD and other information in the database and present it in a variety of formats. These commands include the following:
The database under /var/lib/lsvpd/db has two subdirectories: bus andlinux. The bus directory contains a bus view of the system's hardware, while the linux directory contains the operating system's view of adapters, devices and miscellaneous useful information. Devices and adapters are cross linked between the two directories. Supplementary information that used to be stored in (other) subdirectories of /var/lib/lsvpd is now stored in relevant directories of the adapters and devices.
On machines with an Open Firmware device-tree, such as pSeries, the bus directory contains a device-tree subdirectory, which is a copy of /proc/device-tree augmented with linux,vpd nodes (and cross-links).
On other machines with sysfs, the bus directory is populated with information from sysfs and then augmented as above.
The following observations and requirements influenced the choice of bash as the primary implementation language:
Helper utilities that can't be implemented in bash, and are not otherwise available, are implemented in C. This allows small, efficient executables to be produced, which is appropriate for certain early-boot environments, such as in an initramfs.
At this point in time, much of the functionality is being migrated to larger C programs. This is to allow lsvpd to realistically cope with hotplug. Eventually the whole package will be rewritten in C.
The main commands in the lsvpd package, written in bash, are written in a modular manner. This allows their complexity to be more easily managed and allows features to be added depending on (possibly architecture-dependent) operating system features and availability of other commands or packages.
There are several subdirectories of modules:
At the simplest level, modules work by redefining shell functions that are defined in previously loaded modules. Default modules contain stubs or versions of functions with minimal functionality. Modules that are loaded later may then define more sophisticated versions of those functions, depending on the available functionality.
To avoid a plethora of case statements, a function multiplexing scheme has been implemented. A multiplexed function is declared like this:
make_multiplexed add_device
Initially, this causes any calls to this function, such as
add_device scsi 0:0:0:1
to fail silently, since the add_device function has been declared but not defined.
Subsequent modules can then define individual implementation functions that are called according to the first argument that is passed to add_device. For example, if an implementation called add_device_scsi is defined, it will be called when the first argument is scsi, as in the above example. If the first argument does not coincide with a defined implementation, then the implementation add_device_DEFAULT will be called, if it is defined. Otherwise silent failure occurs. This allows modules to incrementally introduce functionality for different device types.
Note that if a module wishes to replace a number of implementations with a ..._DEFAULT implementation, it will also need to use set -f to remove unwanted implementations. Alternatively, if a module is able to provide all implementations using a single function, then it can simply define a new add_device function and completely override the multiplexing.