A Little Bit About cfgadm(1M)
By haa on Jun 14, 2005
If you happened to be taking a look at the commands in usr/src/cmd, you might notice "cfgadm - configuration administration." cfgadm is a command line interface through which dynamically reconfigurable hardware is manipulated on Solaris and now OpenSolaris. Dynamically reconfigurable hardware? That's fancy talk for things like hot pluggable PCI slots, hot swappable SCSI disks, USB slots, and on the midrange and high end SPARC servers, memory, CPUs, I/O devices, and entire system boards. A plugin architecture is used to handle different types of hardware. In usr/src/lib/cfgadm_plugins you can find the plugin directories which include scsi, usb, and pci. These contain directories such as i386, amd64, sparc, and sparcv9 which indicate a version of the plugin is built for the named architecture. For example, the USB plugin is built for all of those, but the sbd (system board) plugin is only built for sparc and sparcv9. That's 32-bit and 64-bit SPARC respectively. Currently, cfgadm is compiled as a 32-bit application, therefore it will just be using the 32-bit plugins.
cfgadm's interface is based on an abstraction centered around attachment points. A reconfigurable hardware device is displayed as an attachment point with a receptacle and occupant. All the work required to display the status of or manipulate an attachment point is handled by a plugin. Running cfgadm as root without any options will list all the attachment points. Check out the cfgadm(1M) man page for all the command line options. Plugins also have man pages, for example, cfgadm_scsi(1M). In the plugin man pages, you should find documentation on how to pass plugin specific options to cfgadm.
At home, I've got an old old 300MHz x86 Celeron box which is running Solaris 10. Running cfgadm as root on this box yields
root@x86solaris #cfgadm Ap_Id Type Receptacle Occupant Condition usb0/1 unknown empty unconfigured ok usb0/2 unknown empty unconfigured ok
The cfgadm_usb(1M) man page explains that this means the computer has one USB controller with two ports--neither of which have anything plugged into them. The two ports have Ap_Id's (attachment point identifiers) usb0/1 and usb0/2.
After plugging in a USB mouse:
root@x86solaris #cfgadm Ap_Id Type Receptacle Occupant Condition usb0/1 usb-mouse connected configured ok usb0/2 unknown empty unconfigured ok
After plugging in my monitor/USB hub with keyboard and mouse attached:
root@x86solaris #cfgadm Ap_Id Type Receptacle Occupant Condition usb0/1 usb-hub connected configured ok usb0/1.1 usb-hub connected configured ok usb0/1.1.1 usb-mouse connected configured ok usb0/1.1.2 unknown empty unconfigured ok usb0/1.1.3 usb-device connected configured ok usb0/1.2 unknown empty unconfigured ok usb0/1.3 unknown empty unconfigured ok usb0/1.4 unknown empty unconfigured ok usb0/2 unknown empty unconfigured ok
root@x86solaris #ldd /usr/sbin/cfgadm libcfgadm.so.1 => /usr/lib/libcfgadm.so.1 libc.so.1 => /lib/libc.so.1 libdevinfo.so.1 => /lib/libdevinfo.so.1 libnvpair.so.1 => /lib/libnvpair.so.1 libnsl.so.1 => /lib/libnsl.so.1 libmp.so.2 => /lib/libmp.so.2 libmd5.so.1 => /lib/libmd5.so.1 libscf.so.1 => /lib/libscf.so.1 libdoor.so.1 => /lib/libdoor.so.1 libuutil.so.1 => /lib/libuutil.so.1 libm.so.2 => /lib/libm.so.2
To list all the attachment points on the system, cfgadm calls into libcfgadm, then libcfgadm uses libdevinfo to get a snapshot of the device tree. It then walks the device tree and attempts to find a suitable plugin for each device node in the tree. If a suitable plugin is found, the plugin is used to get the status of the attachment point. This happens in the list_common() routine inside libcfgadm. di_init(3DEVINFO) is used to get the device tree snapshot and di_walk_minor(3DEVINFO) is used to walk the tree, calling the supplied routine do_list_common() on each minor node. Then, once control is handed off to the plugin, it can call into the kernel and talk to the driver.
I've fixed some bugs in the sbd cfgadm plugin so I'll give an example of how that plugin works. First, here's the output from cfgadm on a domain on one of our high end SPARC systems.
# cfgadm Ap_Id Type Receptacle Occupant Condition IO5 HPCI connected configured ok IO5_C3V0 pci-pci/hp connected configured ok IO5_C3V1 unknown connected unconfigured unknown IO5_C5V0 pci-pci/hp connected configured ok IO5_C5V1 pci-pci/hp connected configured ok SB5 V3CPU connected configured ok SB6 V3CPU connected configured ok c0 scsi-bus connected configured unknown c1 scsi-bus connected configured unknown c2 scsi-bus connected unconfigured unknown c3 scsi-bus connected unconfigured unknown # cfgadm -a SB6 Ap_Id Type Receptacle Occupant Condition SB6 V3CPU connected configured ok SB6::cpu0 cpu connected configured ok SB6::cpu1 cpu connected configured ok SB6::cpu2 cpu connected configured ok SB6::cpu3 cpu connected configured ok SB6::memory memory connected configured ok
The SB5, SB6, and IO5 attachment points represent system boards which are handled by the sbd plugin. Without getting into too much detail about domains and system boards, running "cfgadm -c disconnect SB6" on this system will start Solaris off on a quest to remove board SB6 from the system bus. This capability is a large part of Solaris' Dynamic Reconfiguration (DR) feature. The sbd plugin is going to schedule a sequence of operations required to transition the board board from being configured and in use by Solaris, to having the board (and all its resident CPUs and memory) be completely isolated from Solaris and ready to be powered down. The plugin uses an ordered list of commands, which are defined in ap.h. The function ap_seq_get() looks at the current status of the board and determines the first and last command that should be executed in sequence from the list. ap_seq_exec() is where the plugin iterates through the command list and for many of the commands, such as CMD_DISCONNECT, ap_ioctl() is called. So this is where the plugin calls into the kernel, letting the DR driver handle the work required to get Solaris off the CPUs and memory being disconnected.