<?Pub UDT _bookmark _target?><?Pub EntList amp nbsp gt lt ndash hyphen?><?Pub CX solbook(book(title()bookinfo()part(2)part(title()partintro()?><chapter id="loading-15035"><title>Compiling, Loading, Packaging,
and Testing Drivers</title><highlights><para>This chapter describes the procedure for driver development, including
code layout, compilation, packaging, and testing.</para><itemizedlist><para>This chapter provides information on the following subjects:</para><listitem><para><olink targetptr="loading-112" remap="internal">Driver Code Layout</olink></para>
</listitem><listitem><para><olink targetptr="loading-1" remap="internal">Preparing for Driver Installation</olink></para>
</listitem><listitem><para><olink targetptr="loading-85890" remap="internal">Installing, Updating, and
Removing Drivers</olink></para>
</listitem><listitem><para><olink targetptr="loading-9" remap="internal">Loading and Unloading Drivers</olink></para>
</listitem><listitem><para><olink targetptr="loading-32" remap="internal">Driver Packaging</olink></para>
</listitem><listitem><para><olink targetptr="loading-17" remap="internal">Criteria for Testing Drivers</olink></para>
</listitem>
</itemizedlist>
</highlights><sect1 id="fcaqh"><title>Driver Development Summary</title><para>This chapter and the following two chapters, <olink targetptr="debug-60" remap="internal">Chapter&nbsp;22,
Debugging, Testing, and Tuning Device Drivers</olink> and <olink targetptr="coding-practices" remap="internal">Chapter&nbsp;23, Recommended Coding Practices</olink>,
provide detailed information on developing a device driver.</para><orderedlist><para>Take the following steps to build a device driver:</para><listitem><para>Write, compile, and link the new code.</para><para>See <olink targetptr="loading-112" remap="internal">Driver Code Layout</olink> for the conventions on
naming files. Use a C compiler to compile the driver. Link the driver using <olink targetdoc="group-refman" targetptr="ld-1" remap="external"><citerefentry><refentrytitle>ld</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink>. See <olink targetptr="loading-29" remap="internal">Compiling and Linking the Driver</olink> and <olink targetptr="loading-16" remap="internal">Module Dependencies</olink>.</para>
</listitem><listitem><para>Create the necessary hardware configuration files.</para><para>Create
a hardware configuration file unique to the device called <emphasis>xx</emphasis><filename>.conf</filename> where <emphasis>xx</emphasis> is the prefix for the device.
This file is used to update the <olink targetdoc="group-refman" targetptr="driver.conf-4" remap="external"><citerefentry><refentrytitle>driver.conf</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink> file. See <olink targetptr="loading-4" remap="internal">Writing a Hardware Configuration File</olink>. For a
pseudo device driver, create a <olink targetdoc="group-refman" targetptr="pseudo-4" remap="external"><citerefentry><refentrytitle>pseudo</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink> file.</para>
</listitem><listitem><para>Copy the driver to the appropriate module directory.</para><para>See <olink targetptr="loading-5" remap="internal">Copying the Driver to a Module Directory</olink>.</para>
</listitem><listitem><para>Install the device driver using <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink>.</para><para>Installing the
driver with <command>add_drv</command> is usually done as part of a postinstall
script. See <olink targetptr="loading-7" remap="internal">Installing Drivers with add_drv</olink>.
Use the <olink targetdoc="group-refman" targetptr="update-drv-1m" remap="external"><citerefentry><refentrytitle>update_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command to make any changes to the driver. See <olink targetptr="loading-31" remap="internal">Updating Driver Information</olink>.</para>
</listitem><listitem><para>Load the driver.</para><para>The driver can be loaded automatically
by accessing the device. See <olink targetptr="loading-9" remap="internal">Loading and Unloading
Drivers</olink> and <olink targetptr="loading-13" remap="internal">Package Postinstall</olink>.
Drivers can also be loaded by using the <olink targetdoc="group-refman" targetptr="modload-1m" remap="external"><citerefentry><refentrytitle>modload</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command. The <command>modload</command> command
does not call any routines in the module and therefore is useful for testing.
See <olink targetptr="eupvm" remap="internal">Loading and Unloading Test Modules</olink>.</para>
</listitem><listitem><para>Test the driver.</para><para>Drivers should be rigorously
tested in the following areas:</para><itemizedlist><listitem><para><olink targetptr="loading-18" remap="internal">Configuration Testing</olink></para>
</listitem><listitem><para><olink targetptr="loading-19" remap="internal">Functionality Testing</olink></para>
</listitem><listitem><para><olink targetptr="loading-20" remap="internal">Error Handling</olink></para>
</listitem><listitem><para><olink targetptr="loading-12" remap="internal">Testing Loading and Unloading</olink></para>
</listitem><listitem><para><olink targetptr="loading-21" remap="internal">Stress, Performance, and Interoperability
Testing</olink></para>
</listitem><listitem><para><olink targetptr="loading-22" remap="internal">DDI/DKI Compliance Testing</olink></para>
</listitem><listitem><para><olink targetptr="loading-23" remap="internal">Installation and Packaging Testing</olink></para>
</listitem>
</itemizedlist><para>For additional driver-specific testing, see <olink targetptr="loading-24" remap="internal">Testing
Specific Types of Drivers</olink>.</para>
</listitem><listitem><para>Remove the driver if necessary.</para><para>Use the <olink targetdoc="group-refman" targetptr="rem-drv-1m" remap="external"><citerefentry><refentrytitle>rem_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command to
remove a device driver. See <olink targetptr="loading-36" remap="internal">Removing the Driver</olink> and <olink targetptr="loading-14" remap="internal">Package Preremove</olink>.</para>
</listitem>
</orderedlist>
</sect1><sect1 id="loading-112"><title>Driver Code Layout</title><itemizedlist><para>The code for a device driver is usually divided into the following files:</para><listitem><para>Header files (<literal>.h</literal> files)</para>
</listitem><listitem><para>Source files (<literal>.c</literal> files)</para>
</listitem><listitem><para>Optional configuration file (<filename>driver.conf</filename> file)</para>
</listitem>
</itemizedlist><sect2 id="loading-33"><title>Header Files</title><itemizedlist><para><indexterm><primary>header files for device drivers</primary></indexterm><indexterm><primary>device drivers</primary><secondary>header files</secondary></indexterm>Header
files provide the following definitions:</para><listitem><para>Data structures specific to the device, such as a structure
representing the device registers</para>
</listitem><listitem><para>Data structures defined by the driver for maintaining state
information</para>
</listitem><listitem><para>Defined constants, such as those representing the bits of
the device registers</para>
</listitem><listitem><para>Macros, such as those defining the static mapping between
the minor device number and the instance number</para>
</listitem>
</itemizedlist><para>Some of the header file definitions, such as the state structure, might
be needed only by the device driver. This information should go in <emphasis>private</emphasis> header files that are only included by the device driver itself.</para><para>Any information that an application might require, such as the I/O control
commands, should be in <emphasis>public</emphasis> header files. These files
are included by the driver and by any applications that need information about
the device.</para><para>While there is no standard for naming private and public files, one
convention is to name the private header file <filename><replaceable>xx</replaceable>impl.h</filename> and the public header file <filename><replaceable>xx</replaceable>io.h</filename>.</para>
</sect2><sect2 id="loading-34"><title>Source Files</title><itemizedlist><para><indexterm><primary>source files for device drivers</primary></indexterm><indexterm><primary>device drivers</primary><secondary>source files</secondary></indexterm><indexterm><primary>device drivers</primary><secondary>module configuration</secondary></indexterm>A C source file (a <filename>.c</filename> file) for a device
driver has the following responsibilities:</para><listitem><para>Contains the data declarations and the code for the entry
points of the driver</para>
</listitem><listitem><para>Contains the <literal>#include</literal> statements that are
needed by the driver</para>
</listitem><listitem><para>Declares <literal>extern</literal> references</para>
</listitem><listitem><para>Declares local data</para>
</listitem><listitem><para>Sets up the <literal>cb_ops</literal> and <literal>dev_ops</literal> structures</para>
</listitem><listitem><para>Declares and initializes the module configuration section,
that is, the <olink targetdoc="group-refman" targetptr="modlinkage-9s" remap="external"><citerefentry><refentrytitle>modlinkage</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> and <olink targetdoc="group-refman" targetptr="modldrv-9s" remap="external"><citerefentry><refentrytitle>modldrv</refentrytitle><manvolnum>9S</manvolnum></citerefentry></olink> structures</para>
</listitem><listitem><para>Makes any other necessary declarations</para>
</listitem><listitem><para>Defines the driver entry points</para>
</listitem>
</itemizedlist>
</sect2><sect2 id="loading-15"><title>Configuration Files</title><para><indexterm><primary><literal>driver.conf</literal> files</primary><see>hardware configuration files</see></indexterm><indexterm><primary>hardware configuration files</primary></indexterm>In general, the configuration file for a driver
defines all of the properties that the driver needs. Entries in the driver
configuration file specify possible device instances that the driver can probe
for existence. Driver global properties can be set in the driver's configuration
file. See the <olink targetdoc="refman4" targetptr="driver.conf-4" remap="external"><citerefentry><refentrytitle>driver.conf</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink> man page for more information.</para><para>Driver configuration files are required for devices that are not self-identifying.</para><para>Driver configuration files are optional for self-identifying devices
(SID). For self-identifying devices, the configuration file can be used to
add properties into SID nodes.</para><itemizedlist><para>The following properties are examples of properties that are <emphasis>not</emphasis> set
in the driver configuration file:</para><listitem><para>Drivers that use the SBus peripheral bus generally get property
information from the SBus card. In cases where additional properties are needed,
the driver configuration file can contain properties that are defined by <olink targetdoc="refman4" targetptr="sbus-4" remap="external"><citerefentry><refentrytitle>sbus</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink>.</para>
</listitem><listitem><para>The properties of a PCI bus can generally be derived from
the PCI configuration space. In cases where private driver properties are
needed, the driver configuration file can contain properties that are defined
by <olink targetdoc="refman4" targetptr="pci-4" remap="external"><citerefentry><refentrytitle>pci</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink>.</para>
</listitem><listitem><para>Drivers on the ISA bus can use additional properties that
are defined by <olink targetdoc="refman4" targetptr="isa-4" remap="external"><citerefentry><refentrytitle>isa</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink>.</para>
</listitem>
</itemizedlist>
</sect2>
</sect1><sect1 id="loading-1"><title>Preparing for Driver Installation</title><orderedlist><para>The following steps precede installation of a driver:</para><listitem><para>Compile the driver.</para>
</listitem><listitem><para>Create a configuration file if necessary.</para>
</listitem><listitem><para>Identify the driver module to the system through either of
the following alternatives:</para><itemizedlist><listitem><para>Match the driver's name to the name of the device node.</para>
</listitem><listitem><para>Use either <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> or <olink targetdoc="group-refman" targetptr="update-drv-1m" remap="external"><citerefentry><refentrytitle>update_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> to inform
the system of the module names.</para>
</listitem>
</itemizedlist>
</listitem>
</orderedlist><para>The system maintains a one-to-one association between the name of the
driver module and the name of the <literal>dev_info</literal> node. For example,
consider a <literal>dev_info</literal> node for a device that is named <literal>mydevice</literal>. The device <literal>mydevice</literal> is handled by a driver
module that is also named <literal>mydevice</literal>. The <literal>mydevice</literal> module
resides in a subdirectory that is called <filename>drv</filename>, which is
in the module path. The module is in <filename>drv/mydevice</filename> if
you are using a 32-bit kernel. The module is in <filename>drv/sparcv9/mydevice</filename> if
you are using a 64-bit SPARC kernel. The module is in <filename>drv/amd64/mydevice</filename> if you are using a 64-bit x86 kernel.</para><itemizedlist><para>If the driver is a STREAMS network driver, then the driver name must
meet the following constraints:</para><listitem><para>Only alphanumeric characters (a-z, A-Z, 0-9), plus the underscore
('_'), are allowed.</para>
</listitem><listitem><para>Neither the first nor the last character of the name can be
a digit.</para>
</listitem><listitem><para>The name cannot exceed 16 characters in length. Names in the
range of 3-8 characters in length are preferable.</para>
</listitem>
</itemizedlist><para>If the driver must manage <literal>dev_info</literal> nodes with different
names, the <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> utility
can create aliases. The <literal>-i</literal> flag specifies the names of
other <literal>dev_info</literal> nodes that the driver handles. The <command>update_drv</command> command can also modify aliases for an installed device driver.</para><sect2 id="loading-29"><title>Compiling and Linking the Driver</title><indexterm><primary>compiling drivers</primary>
</indexterm><indexterm><primary>linking drivers</primary>
</indexterm><indexterm><primary>loading drivers</primary>
</indexterm><indexterm><primary>device drivers</primary><seealso>compiling drivers</seealso>
</indexterm><indexterm><primary>device drivers</primary><seealso>linking drivers</seealso>
</indexterm><indexterm><primary>device drivers</primary><seealso>loading drivers</seealso>
</indexterm><indexterm><primary>Sun Studio</primary>
</indexterm><indexterm><primary><command>cc</command> command</primary>
</indexterm><indexterm><primary><command>ld</command> command</primary>
</indexterm><indexterm><primary>GCC</primary>
</indexterm><indexterm><primary><command>gcc</command> command</primary>
</indexterm><para>You need to compile each driver source file and link the resulting object
files into a driver module. The Solaris OS is compatible with both the Sun
Studio C compiler  and the GNU C compiler from the Free Software Foundation,
Inc. The examples in this section use the Sun Studio C compiler unless otherwise
noted. For information on the Sun Studio C compiler, see the <olink targetdoc="cug" remap="external"><citetitle remap="book">Sun Studio 12: C User&rsquo;s Guide</citetitle></olink> and
the <ulink url="http://developers.sun.com/sunstudio/documentation/" type="text">Sun
Studio Documentation</ulink> on the Sun Developer Network web site. For more
information on compile and link options, see the <olink targetdoc="stdrefman" remap="external"><citetitle remap="book">Sun Studio Man Pages</citetitle></olink>. The GNU C compiler
is supplied in the <filename>/usr/sfw</filename> directory. For information
on the GNU C compiler, see <ulink url="http://gcc.gnu.org/" type="url"></ulink> or
check the man pages in <filename>/usr/sfw/man</filename>.</para><para>The example below shows a driver that is called <replaceable>xx</replaceable> with
two C source files. A driver module that is called  <replaceable>xx</replaceable> is
generated. The driver that is created in this example is for a 32-bit kernel.
You must use <command>ld</command> <option>r</option> even if your driver
has only one object module.</para><screen>% <userinput>cc -D_KERNEL -c <replaceable>xx</replaceable>1.c</userinput>
% <userinput>cc -D_KERNEL -c <replaceable>xx</replaceable>2.c</userinput>
% <userinput>ld -r -o <replaceable>xx</replaceable> <replaceable>xx</replaceable>1.o <replaceable>xx</replaceable>2.o</userinput></screen><para><indexterm><primary sortas="KERNEL"><literal>_KERNEL</literal> symbol</primary></indexterm><indexterm><primary><function>ASSERT</function> macro</primary></indexterm><indexterm><primary><literal>DEBUG</literal> symbol</primary></indexterm>The
<literal>_KERNEL</literal> symbol must be defined to indicate that
this code defines a kernel module. No other symbols should be defined, except
for driver private symbols. The <literal>DEBUG</literal> symbol can be defined
to enable any calls to <olink targetdoc="refman9f" targetptr="assert-9f" remap="external"><citerefentry><refentrytitle>ASSERT</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>.</para><para>If you are compiling for a 64-bit SPARC architecture using Sun Studio
9, Sun Studio 10, or Sun Studio 11, use the <option>xarch=v9</option> option:</para><screen>% <userinput>cc -D_KERNEL -xarch=v9 -c <replaceable>xx</replaceable>.c</userinput></screen><para>If you are compiling for a 64-bit SPARC architecture using Sun Studio
12, use the <option>m64</option> option:</para><screen>% <userinput>cc -D_KERNEL -m64 -c <replaceable>xx</replaceable>.c</userinput></screen><para>If you are compiling for a 64-bit x86 architecture using Sun Studio
10 or Sun Studio 11, use both the <option>xarch=amd64</option> option and
the <option>xmodel=kernel</option> option:</para><screen>% <userinput>cc -D_KERNEL -xarch=amd64 -xmodel=kernel -c <replaceable>xx</replaceable>.c</userinput></screen><para>If you are compiling for a 64-bit x86 architecture using Sun Studio
12, use the <option>m64</option> option, the <option>xarch=sse2a</option> option,
and the <option>xmodel=kernel</option> option:</para><screen>% <userinput>cc -D_KERNEL -m64 -xarch=sse2a -xmodel=kernel -c <replaceable>xx</replaceable>.c</userinput></screen><note><para>Sun Studio 9 does not support 64-bit x86 architectures. Use Sun
Studio 10, Sun Studio 11, or Sun Studio 12 to compile and debug drivers for
64-bit x86 architectures.</para>
</note><para>After the driver is stable, you might want to add optimization flags
to build a production quality driver. See the <command>cc</command>(1) man
page in <olink targetdoc="stdrefman" remap="external"><citetitle remap="book">Sun Studio Man Pages</citetitle></olink> for specific information on optimizations in the
Sun Studio C compiler.</para><para>Global variables should be treated as <literal>volatile</literal> in
device drivers. The <literal>volatile</literal> tag is discussed in greater
detail in <olink targetptr="codingpractices-1" remap="internal">Declaring a Variable Volatile</olink>.
Use of the flag depends on the platform. See the man pages.</para>
</sect2><sect2 id="loading-16"><title>Module Dependencies</title><para>If the driver module depends on symbols exported by another kernel module,
the dependency can be specified by the <option>dy</option> and <option>N</option> options
of the loader, <olink targetdoc="refman1" targetptr="ld-1" remap="external"><citerefentry><refentrytitle>ld</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink>.
If the driver depends on a symbol exported by <literal>misc/mySymbol</literal>,
the example below should  be used to create the driver binary.</para><screen>% <userinput>ld -dy -r -o <replaceable>xx</replaceable> <replaceable>xx</replaceable>1.o <replaceable>xx</replaceable>2.o -N misc/mySymbol</userinput></screen>
</sect2><sect2 id="loading-4"><title>Writing a Hardware Configuration File</title><para><indexterm id="loading-ix576"><primary>loading drivers</primary><secondary>hardware configuration file</secondary></indexterm><indexterm id="loading-ix578"><primary>hardware configuration files</primary></indexterm>If
a device is non-self-identifying, the kernel might require a hardware
configuration file for that device. If the driver is called
<replaceable>xx</replaceable>, the hardware configuration file for the driver
should be called <replaceable>xx</replaceable><filename>.conf</filename>.</para><para>On the x86 platform, device information is now supplied by the booting
system. Hardware configuration files should no longer be needed, even for
non-self-identifying devices.</para><para>See the
<olink targetdoc="group-refman" targetptr="driver.conf-4" remap="external"><citerefentry><refentrytitle>driver.conf</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink>,
<olink targetdoc="group-refman" targetptr="pseudo-4" remap="external"><citerefentry><refentrytitle>pseudo</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink>,
<olink targetdoc="group-refman" targetptr="sbus-4" remap="external"><citerefentry><refentrytitle>sbus</refentrytitle><manvolnum>4</manvolnum></citerefentry></olink>,
<olink targetdoc="group-refman" targetptr="scsi-free-consistent-buf-9f" remap="external"><citerefentry><refentrytitle>scsi_free_consistent_buf</refentrytitle><manvolnum>9F</manvolnum></citerefentry></olink>,
and <olink targetdoc="group-refman" targetptr="update-drv-1m" remap="external"><citerefentry><refentrytitle>update_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink>
man pages for more information on hardware configuration files.</para><para>Arbitrary properties can be defined in hardware configuration files.
Entries in the configuration file are in the form <replaceable>property</replaceable>=<replaceable>value</replaceable>, where <replaceable>property</replaceable> is the property
name and <replaceable>value</replaceable> is its initial value. The configuration
file approach enables devices to be configured by changing the property values.</para>
</sect2>
</sect1><sect1 id="loading-85890"><title>Installing, Updating, and Removing Drivers</title><para>Before a driver can be used, the system must be informed that the driver
exists. The <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> utility
must be used to correctly install the device driver. After a driver is installed,
that driver can be loaded and unloaded from memory without using the <command>add_drv</command> command.</para><sect2 id="loading-5"><title>Copying the Driver to a Module Directory</title><indexterm id="loading-ix579"><primary>loading modules</primary>
</indexterm><indexterm id="loading-ix580"><primary>module directory</primary>
</indexterm><indexterm id="loading-ix581"><primary>kernel</primary><secondary>module directory</secondary>
</indexterm><itemizedlist><para>Three conditions determine a device driver module's path:</para><listitem><para>The platform that the driver runs on</para>
</listitem><listitem><para>The architecture for which the driver is compiled</para>
</listitem><listitem><para>Whether the path is needed at boot time</para>
</listitem>
</itemizedlist><para>Device drivers reside in the following locations:</para><variablelist><varlistentry><term><literal>/platform/`uname -i`</literal><filename>/kernel/drv</filename></term><listitem><para>Contains 32-bit drivers that run only on a specific platform.</para>
</listitem>
</varlistentry><varlistentry><term><literal>/platform/`uname -i`</literal><filename>/kernel/drv/sparcv9</filename></term><listitem><para>Contains 64-bit drivers that run only on a specific SPARC-based
platform.</para>
</listitem>
</varlistentry><varlistentry><term><literal>/platform/`uname -i`</literal><filename>/kernel/drv/amd64</filename></term><listitem><para>Contains 64-bit drivers that run only on a specific x86-based
platform.</para>
</listitem>
</varlistentry><varlistentry><term><literal>/platform/`uname -m`</literal><filename>/kernel/drv</filename></term><listitem><para>Contains 32-bit drivers that run only on a specific family
of platforms.</para>
</listitem>
</varlistentry><varlistentry><term><literal>/platform/`uname -m`</literal><filename>/kernel/drv/sparcv9</filename></term><listitem><para>Contains 64-bit drivers that run only on a specific family
of SPARC-based platforms.</para>
</listitem>
</varlistentry><varlistentry><term><literal>/platform/`uname -m`</literal><filename>/kernel/drv/amd64</filename></term><listitem><para>Contains 64-bit drivers that run only on a specific family
of x86-based platforms.</para>
</listitem>
</varlistentry><varlistentry><term><filename>/usr/kernel/drv</filename></term><listitem><para>Contains 32-bit drivers that are independent of platforms.</para>
</listitem>
</varlistentry><varlistentry><term><filename>/usr/kernel/drv/sparcv9</filename></term><listitem><para>Contains 64-bit drivers on SPARC-based systems that are independent
of platforms.</para>
</listitem>
</varlistentry><varlistentry><term><filename>/usr/kernel/drv/amd64</filename></term><listitem><para>Contains 64-bit drivers on x86-based systems that are independent
of platforms.</para>
</listitem>
</varlistentry>
</variablelist><para>To install a 32-bit driver, the driver and its configuration file must
be copied to a <filename>drv</filename> directory in the module path. For
example, to copy a driver to <filename>/usr/kernel/drv</filename>, type:</para><screen>$ <userinput>su</userinput>
# <userinput>cp <replaceable>xx</replaceable> /usr/kernel/drv</userinput>
# <userinput>cp <replaceable>xx</replaceable>.conf /usr/kernel/drv</userinput></screen><para>To install a SPARC driver, copy the driver to a <filename>drv/sparcv9</filename> directory
in the module path. Copy the driver configuration file to the <filename>drv</filename> directory
in the module path. For example, to copy a driver to <literal>/usr/kernel/drv</literal>,
you would type:</para><screen>$ <userinput>su</userinput>
# <userinput>cp <replaceable>xx</replaceable> /usr/kernel/drv/sparcv9</userinput>
# <userinput>cp <replaceable>xx</replaceable>.conf /usr/kernel/drv</userinput></screen><para>To install a 64-bit x86 driver, copy the driver to a <filename>drv/amd64</filename> directory
in the module path. Copy the driver configuration file to the <filename>drv</filename> directory
in the module path. For example, to copy a driver to <literal>/usr/kernel/drv</literal>,
you would type:</para><screen>$ <userinput>su</userinput>
# <userinput>cp <replaceable>xx</replaceable> /usr/kernel/drv/amd64</userinput>
# <userinput>cp <replaceable>xx</replaceable>.conf /usr/kernel/drv</userinput></screen><note><para><indexterm><primary>hardware configuration files</primary><secondary>where to place</secondary></indexterm><indexterm><primary sortas="conf files"><filename>.conf</filename> files</primary><see>hardware configuration files</see></indexterm>All driver configuration files (<literal>.conf</literal> files) must go in the <filename>drv</filename> directory in the
module path. The <filename>.conf</filename> files cannot go into any subdirectory
of the <filename>drv</filename> directory.</para>
</note>
</sect2><sect2 id="loading-7"><title>Installing Drivers with <command>add_drv</command></title><indexterm id="loading-ix583"><primary>loading drivers</primary><secondary><command>add_drv</command> command</secondary>
</indexterm><indexterm id="loading-ix584"><primary><command>add_drv</command> command</primary><secondary>description of</secondary>
</indexterm><para>Use the <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command
to install the driver in the system. If the driver installs successfully,<command>add_drv</command> runs <olink targetdoc="group-refman" targetptr="devfsadm-1m" remap="external"><citerefentry><refentrytitle>devfsadm</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> to
create the logical names in the <filename>/dev</filename> directory.</para><screen># <userinput>add_drv <replaceable>xx</replaceable></userinput></screen><para>In this case, the device identifies itself as <replaceable>xx</replaceable>.
The device special files have default ownership and permissions (<literal>0600</literal> <literal>root</literal> <literal>sys</literal>).  The <command>add_drv</command> command
also allows additional names for the device (aliases) to be specified. See
the <command>add_drv</command>(1M) man page for information on adding aliases
and setting file permissions explicitly.</para><note><para>Do not use the <command>add_drv</command> command to install a
STREAMS module. See the <olink targetdoc="streams" remap="external"><citetitle remap="book">STREAMS Programming Guide</citetitle></olink> for details.</para>
</note><para><indexterm id="gglwu"><primary><command>devfsadm</command> command</primary></indexterm>If the driver creates minor nodes that do not represent terminal
devices such as disks, tapes, or ports, you can modify <filename>/etc/devlink.tab</filename> to cause <command>devfsadm</command> to create logical device
names in <filename>/dev</filename>. Alternatively, logical names can be created
by a program that is run at driver installation time.</para>
</sect2><sect2 id="loading-31"><title>Updating Driver Information</title><indexterm><primary>device drivers</primary><secondary>modifying information with <command>update_drv</command></secondary>
</indexterm><indexterm><primary><command>update_drv</command> command</primary><secondary>description of</secondary>
</indexterm><indexterm><primary>device drivers</primary><secondary>modifying permissions</secondary>
</indexterm><indexterm><primary>device drivers</primary><secondary>aliases</secondary>
</indexterm><indexterm><primary>minor device node</primary><secondary>modifying permissions of</secondary>
</indexterm><para>Use the <olink targetdoc="refman1m" targetptr="update-drv-1m" remap="external"><citerefentry><refentrytitle>update_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command to notify the system of any changes to an
installed device driver. By default, the system re-reads the driver configuration
file and reloads the driver binary module.</para>
</sect2><sect2 id="loading-36"><title>Removing the Driver</title><para>To remove a driver from the system, use the <olink targetdoc="group-refman" targetptr="rem-drv-1m" remap="external"><citerefentry><refentrytitle>rem_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command, and then delete
the driver module and configuration file from the module path. A driver cannot
be used again until that driver is reinstalled with <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink>. The removal
of a SCSI HBA driver requires a reboot to take effect.</para>
</sect2>
</sect1><sect1 id="loading-9"><title>Loading and Unloading Drivers</title><para>Opening a special file (accessing the device) that is associated with
a device driver causes that driver to be loaded. You can use the <olink targetdoc="refman1m" targetptr="modload-1m" remap="external"><citerefentry><refentrytitle>modload</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command to load the driver
into memory, but <command>modload</command> does not call any routines in
the module. The preferred method is to open the device.</para><para>Normally, the system automatically unloads device drivers when the device
is no longer in use. During development, you might want to use <olink targetdoc="refman1m" targetptr="modunload-1m" remap="external"><citerefentry><refentrytitle>modunload</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> to unload
the driver explicitly. In order for <command>modunload</command> to be successful,
the device driver must be inactive. No outstanding references to the device
should exist, such as through <olink targetdoc="refman2" targetptr="open-2" remap="external"><citerefentry><refentrytitle>open</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink> or <olink targetdoc="refman2" targetptr="mmap-2" remap="external"><citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink>.</para><para><indexterm id="gglvi"><primary><command>modunload</command> command</primary><secondary>description of</secondary></indexterm><indexterm><primary>unloading drivers</primary></indexterm>The <command>modunload</command> command takes
a runtime-dependent <literal>module_id</literal> as an argument. To find the <literal>module_id</literal>, use <command>grep</command> to search the output of <olink targetdoc="refman1m" targetptr="modinfo-1m" remap="external"><citerefentry><refentrytitle>modinfo</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> for the driver name in question.
Check in the first column.</para><screen># <userinput>modunload -i <replaceable>module-id</replaceable></userinput></screen><para>To unload all currently unloadable modules, specify module ID zero:</para><screen># <userinput>modunload -i 0</userinput></screen><para>In addition to being inactive, the driver must have working <olink targetdoc="group-refman" targetptr="detach-9e" remap="external"><citerefentry><refentrytitle>detach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> and  <olink targetdoc="group-refman" targetptr="u-fini-9e" remap="external"><citerefentry><refentrytitle>_fini</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> routines
for <olink targetdoc="group-refman" targetptr="modunload-1m" remap="external"><citerefentry><refentrytitle>modunload</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> to
succeed.</para>
</sect1><sect1 id="loading-32"><title>Driver Packaging</title><para><indexterm><primary>device drivers</primary><secondary>packaging</secondary></indexterm><indexterm><primary>packaging</primary></indexterm>The normal
delivery vehicle for software is to create a package that contains all of
the software components. A package provides a controlled mechanism for installation
and removal of all the components of a software product. In addition to the
files for using the product, the package includes control files for installing
and uninstalling the application. The postinstall and preremove installation
scripts are two such control files.</para><sect2 id="loading-13"><title>Package Postinstall</title><para>After a package with a driver binary is installed onto a system, the <olink targetdoc="group-refman" targetptr="add-drv-1m" remap="external"><citerefentry><refentrytitle>add_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command must
be run. The <command>add_drv</command> command completes the installation
of the driver. Typically, <command>add_drv</command> is run in a postinstall
script, as in the following example.</para><programlisting>#!/bin/sh
#
#       @(#)postinstall 1.1

PATH="/usr/bin:/usr/sbin:${PATH}"
export PATH

#
# Driver info
#
DRV=&lt;driver-name&gt;
DRVALIAS="&lt;company-name&gt;,&lt;driver-name&gt;"
DRVPERM='* 0666 root sys'

ADD_DRV=/usr/sbin/add_drv

#
# Select the correct add_drv options to execute.
# add_drv touches /reconfigure to cause the
# next boot to be a reconfigure boot.
#
if [ "${BASEDIR}" = "/" ]; then
    #
    # On a running system, modify the
    # system files and attach the driver
    #
    ADD_DRV_FLAGS=""
else     
    #
    # On a client, modify the system files
    # relative to BASEDIR
    #
    ADD_DRV_FLAGS="-b ${BASEDIR}"
fi       
 
#
# Make sure add_drv has not been previously executed
# before attempting to add the driver.
#
grep "^${DRV} " $BASEDIR/etc/name_to_major &gt; /dev/null 2&gt;&amp;1
if [ $? -ne 0 ]; then
    ${ADD_DRV} ${ADD_DRV_FLAGS} -m "${DRVPERM}" -i "${DRVALIAS}" ${DRV}
    if [ $? -ne 0 ]; then
        echo "postinstall: add_drv $DRV failed\n" &gt;&amp;2
        exit 1
    fi
fi
exit 0</programlisting>
</sect2><sect2 id="loading-14"><title>Package Preremove</title><para>When removing a package that includes a driver, the <olink targetdoc="refman1m" targetptr="rem-drv-1m" remap="external"><citerefentry><refentrytitle>rem_drv</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command  must be run prior
to removing the driver binary and other components.  The following example
demonstrates a preremove script that uses the <command>rem_drv</command> command
for driver removal.</para><programlisting>#!/bin/sh
#
#       @(#)preremove  1.1
 
PATH="/usr/bin:/usr/sbin:${PATH}"
export PATH
 
#
# Driver info
#
DRV=&lt;driver-name&gt;
REM_DRV=/usr/sbin/rem_drv
 
#
# Select the correct rem_drv options to execute.
# rem_drv touches /reconfigure to cause the
# next boot to be a reconfigure boot.
#
if [ "${BASEDIR}" = "/" ]; then
    #
    # On a running system, modify the
    # system files and remove the driver
    #
    REM_DRV_FLAGS=""
else     
    #
    # On a client, modify the system files
    # relative to BASEDIR
    #
    REM_DRV_FLAGS="-b ${BASEDIR}"
fi
 
${REM_DRV} ${REM_DRV_FLAGS} ${DRV}
 
exit 0</programlisting>
</sect2>
</sect1><sect1 id="loading-17"><title>Criteria for Testing Drivers</title><para><indexterm><primary>device drivers</primary><secondary>testing</secondary></indexterm><indexterm><primary>testing</primary><secondary>device drivers</secondary></indexterm>Once a device driver is functional, that driver should be thoroughly
tested prior to distribution. Besides testing the features in traditional
UNIX device drivers, Solaris drivers require testing power management features,
such as dynamic loading and unloading of drivers.</para><sect2 id="loading-18"><title>Configuration Testing</title><indexterm><primary>testing</primary><secondary>configurations</secondary>
</indexterm><para>A driver's ability to handle multiple device configurations is an important
part of the test process. Once the driver is working on a simple, or default,
configuration, additional configurations should be tested. Depending on the
device, configuration testing can be accomplished by changing jumpers or DIP
switches. If the number of possible configurations is small, all configurations
should be tried. If the number is large, various classes of possible configurations
should be defined, and a sampling of configurations from each class should
be tested. Defining these classes depends on the potential interactions among
the different configuration parameters. These interactions are a function
of the type of the device and the way in which the driver was written.</para><para>For each device configuration, the basic functions must be tested, which
include loading, opening, reading, writing, closing, and unloading the driver.
Any function that depends upon the configuration deserves special attention.
For example, changing the base memory address of device registers is not likely
to affect the behavior of most driver functions. If a driver works well with
one address, that driver is likely to work as well with a different address.
On the other hand, a special I/O control call might have different effects
depending on the particular device configuration.</para><para>Loading the driver with varying configurations ensures that the  <olink targetdoc="group-refman" targetptr="probe-9e" remap="external"><citerefentry><refentrytitle>probe</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> and  <olink targetdoc="group-refman" targetptr="attach-9e" remap="external"><citerefentry><refentrytitle>attach</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> entry points
can find the device at different addresses. For basic functional testing,
using regular UNIX commands such as  <olink targetdoc="group-refman" targetptr="cat-1" remap="external"><citerefentry><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> or  <olink targetdoc="group-refman" targetptr="dd-1m" remap="external"><citerefentry><refentrytitle>dd</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> is
usually sufficient for character devices. Mounting or booting might be required
for block devices.</para>
</sect2><sect2 id="loading-19"><title>Functionality Testing</title><para><indexterm><primary>testing</primary><secondary>functionality</secondary></indexterm>After a driver has been completely tested for configuration, all
of  the driver's functionality should be thoroughly tested. These tests require
exercising the operation of all of the driver's entry points.</para><para>Many drivers require custom applications to test functionality. However,
basic drivers for devices such as disks, tapes, or asynchronous boards can
be tested using standard system utilities. All entry points should be tested
in this process, including  <olink targetdoc="group-refman" targetptr="devmap-9e" remap="external"><citerefentry><refentrytitle>devmap</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, <olink targetdoc="group-refman" targetptr="chpoll-9e" remap="external"><citerefentry><refentrytitle>chpoll</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, and <olink targetdoc="group-refman" targetptr="ioctl-9e" remap="external"><citerefentry><refentrytitle>ioctl</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink>, if applicable. The <function>ioctl</function> tests might be quite different for each driver. For nonstandard
devices, a custom testing application is generally required.</para>
</sect2><sect2 id="loading-20"><title>Error Handling</title><para><indexterm><primary>device drivers</primary><secondary>error handling</secondary></indexterm><indexterm><primary>error handling</primary></indexterm>A driver
might perform correctly in an ideal environment but fail in cases of errors,
such as erroneous operations or bad data. Therefore, an important part of
driver testing is the testing of the driver's error handling.</para><para>All possible error conditions of a driver should be exercised, including
error conditions for actual hardware malfunctions. Some hardware error conditions
might be difficult to induce, but an effort should be made to force or to
simulate such errors if possible. All of these conditions could be encountered
in the field. Cables should be removed or be loosened, boards should be removed,
and erroneous user application code should be written to test those error
paths. See also <olink targetptr="gevsi" remap="internal">Chapter&nbsp;13, Hardening Solaris
Drivers</olink>.</para><caution role="electrical"><para>Be sure to take proper electrical precautions
when testing.</para>
</caution>
</sect2><sect2 id="loading-12"><title>Testing Loading and Unloading</title><para>Because a driver that does not load or unload can force unscheduled
downtime, loading and unloading must be thoroughly tested.</para><para>A script like the following example should suffice:</para><programlisting>#!/bin/sh
cd &lt;location_of_driver&gt;
while [ 1 ]
do
    modunload -i 'modinfo | grep " &lt;driver_name&gt; " | cut -cl-3' &amp;
    modload &lt;driver_name&gt; &amp;
done</programlisting>
</sect2><sect2 id="loading-21"><title>Stress, Performance, and Interoperability Testing</title><para>To help ensure that a driver performs well, that driver should be subjected
to vigorous stress testing. For example, running single threads through a
driver does not test  locking logic or conditional variables that have to
wait. Device operations should be performed by multiple processes at once
to cause several threads to execute the same code simultaneously.</para><para>Techniques for performing simultaneous tests depend upon the driver.
Some drivers  require special testing applications, while starting several
UNIX commands in the background is suitable for others. Appropriate testing
depends upon where the particular driver uses locks and condition variables.
Testing a driver on a multiprocessor machine is more likely to expose problems
than testing on a single-processor machine.</para><para>Interoperability between drivers must also be tested, particularly because
different devices can share interrupt levels. If possible, configure another
device at the same interrupt level as the one being tested. A stress test
can determine whether the driver correctly claims its own interrupts and operates
according to expectations. Stress tests should be run on both devices at once.
Even if the devices do not share an interrupt level, this test can still be
valuable. For example, consider a case in which serial communication devices
experience errors when a network driver is tested. The same problem might
be causing the rest of the system to encounter interrupt latency problems
as well.</para><para>Driver performance under these stress tests should be measured using
UNIX performance-measuring tools. This type of testing can be as simple as
using the  <olink targetdoc="group-refman" targetptr="time-1" remap="external"><citerefentry><refentrytitle>time</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> command
along with commands to be used in the stress tests.</para>
</sect2><sect2 id="loading-22"><title>DDI/DKI Compliance Testing</title><para><indexterm><primary>DDI-compliant drivers</primary><secondary>compliance testing</secondary></indexterm><indexterm><primary>testing</primary><secondary>DDI compliance</secondary></indexterm>To ensure compatibility with later releases
and reliable support for the current release, every driver should be DDI/DKI
compliant. Check that only kernel routines in <olink targetdoc="refman9f" remap="external"><citetitle remap="book">man pages section 9: DDI and DKI Kernel Functions</citetitle></olink> and <olink targetdoc="refman9e" remap="external"><citetitle remap="book">man pages section 9: DDI and DKI Driver Entry Points</citetitle></olink> and data structures in <olink targetdoc="refman9s" remap="external"><citetitle remap="book">man pages section 9: DDI and DKI Properties and Data Structures</citetitle></olink> are used.</para>
</sect2><sect2 id="loading-23"><title>Installation and Packaging Testing</title><para><indexterm><primary>testing</primary><secondary>installation and packaging</secondary></indexterm>Drivers are delivered to customers in <emphasis>packages</emphasis>.
A package can be added or be removed from the system using a standard mechanism
(see the <olink targetdoc="packinstall" remap="external"><citetitle remap="book">Application Packaging Developer&rsquo;s Guide</citetitle></olink>).</para><para>The ability of a user to add or remove the package from a system should
be tested.  In testing, the package should be both installed and removed from
every type of media to be used for the release. This testing should include
several system configurations. Packages must not make unwarranted assumptions
about the directory environment of the target system. Certain valid assumptions,
however, can be made about where standard kernel files are kept. Also test
adding and removing of packages on newly installed machines that have not
been modified for a development environment. A common packaging error is for
a package to rely on a tool or file that is used in development only. For
example, no tools from the Source Compatibility package, <filename>SUNWscpu</filename>,
should be used in driver installation programs.</para><para>The driver installation must be tested on a minimal Solaris system without
any optional packages.</para>
</sect2><sect2 id="loading-24"><title>Testing Specific Types of Drivers</title><para><indexterm><primary>tape drivers</primary><secondary>testing</secondary></indexterm>This section provides some suggestions about how to test certain
types of standard devices.</para><sect3 id="loading-25"><title>Tape Drivers</title><indexterm><primary>testing</primary><secondary>tape drivers</secondary>
</indexterm><para>Tape drivers should be tested by performing several archive and restore
operations. The  <olink targetdoc="group-refman" targetptr="cpio-1" remap="external"><citerefentry><refentrytitle>cpio</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> and <olink targetdoc="group-refman" targetptr="tar-1" remap="external"><citerefentry><refentrytitle>tar</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> commands can be used for this
purpose.   Use the  <olink targetdoc="group-refman" targetptr="dd-1m" remap="external"><citerefentry><refentrytitle>dd</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> command
to write an entire disk partition to tape. Next, read back the data, and write
the data to another partition of the same size. Then compare the two copies.
The  <olink targetdoc="group-refman" targetptr="mt-1" remap="external"><citerefentry><refentrytitle>mt</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> command
can exercise most of the I/O controls that are specific to tape drivers. See
the <olink targetdoc="group-refman" targetptr="mtio-7i" remap="external"><citerefentry><refentrytitle>mtio</refentrytitle><manvolnum>7I</manvolnum></citerefentry></olink> man
page. Try to use all the options. These three techniques can test the error-handling
capabilities of tape drivers:</para><itemizedlist><listitem><para>Remove the tape and try various operations</para>
</listitem><listitem><para>Write-protect the tape and try a write</para>
</listitem><listitem><para>Turn off power in the middle of different operations</para>
</listitem>
</itemizedlist><para>Tape drivers typically implement exclusive-access <olink targetdoc="refman9e" targetptr="open-9e" remap="external"><citerefentry><refentrytitle>open</refentrytitle><manvolnum>9E</manvolnum></citerefentry></olink> calls. These <function>open</function> calls
can be tested by opening a device and then having a second process try to
open the same device.</para>
</sect3><sect3 id="loading-26"><title>Disk Drivers</title><para><indexterm><primary>disk driver testing</primary></indexterm><indexterm><primary>testing</primary><secondary>disk drivers</secondary></indexterm>Disk
drivers should be tested in both the raw and block device modes.   For block
device tests, create a new file system on the device. Then try to mount the
new file system. Then try to perform multiple file operations.</para><note><para>The file system uses a page cache, so reading the same file over
and over again does not really exercise the driver. The page cache can be
forced to retrieve data from the device by memory-mapping the file with <olink targetdoc="group-refman" targetptr="mmap-2" remap="external"><citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry></olink>. Then use <olink targetdoc="group-refman" targetptr="msync-3c" remap="external"><citerefentry><refentrytitle>msync</refentrytitle><manvolnum>3C</manvolnum></citerefentry></olink> to invalidate the in-memory
copies.</para>
</note><para>Copy another (unmounted) partition of the same size to the raw device.
Then use a command such as  <olink targetdoc="group-refman" targetptr="fsck-1m" remap="external"><citerefentry><refentrytitle>fsck</refentrytitle><manvolnum>1M</manvolnum></citerefentry></olink> to
verify the correctness of the copy. The new partition can also be mounted
and then later compared to the old partition on a file-by-file basis.</para>
</sect3><sect3 id="loading-27"><title>Asynchronous Communication Drivers</title><para><indexterm><primary>asynchronous communication drivers</primary><secondary>testing</secondary></indexterm><indexterm><primary>testing</primary><secondary>asynchronous communication drivers</secondary></indexterm>Asynchronous
drivers can be tested at the basic level by setting up a <literal>login</literal> line
to the serial ports. A good test is to see whether a user can log in on this
line. To sufficiently test an asynchronous driver, however, all the I/O control
functions must be tested, with many interrupts at high speed. A test involving
a loopback serial cable and high data transfer rates can help determine the
reliability of the driver. You can run <olink targetdoc="refman1" targetptr="uucp-1c" remap="external"><citerefentry><refentrytitle>uucp</refentrytitle><manvolnum>1C</manvolnum></citerefentry></olink> over the line to provide some exercise.
However, because <command>uucp</command> performs its own error handling,
verify that the driver is not reporting excessive numbers of errors to the
 <command>uucp</command> process.</para><para>These types of devices are usually STREAMS-based. See the <olink targetdoc="streams" remap="external"><citetitle remap="book">STREAMS Programming Guide</citetitle></olink> for
more information.</para>
</sect3><sect3 id="loading-28"><title>Network Drivers</title><para><indexterm><primary>network drivers</primary><secondary>testing</secondary></indexterm><indexterm><primary>testing</primary><secondary>network drivers</secondary></indexterm>Network drivers can be tested using standard network utilities.
The <olink targetdoc="group-refman" targetptr="ftp-1" remap="external"><citerefentry><refentrytitle>ftp</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> and
 <olink targetdoc="group-refman" targetptr="rcp-1" remap="external"><citerefentry><refentrytitle>rcp</refentrytitle><manvolnum>1</manvolnum></citerefentry></olink> commands are
useful because the files can be compared on each end of the network. The driver
should be tested under heavy network loading, so that various commands can
be run by multiple processes.</para><itemizedlist><para>Heavy network loading includes the following conditions:</para><listitem><para>Traffic to the test machine is heavy.</para>
</listitem><listitem><para>Traffic among all machines on the network is heavy.</para>
</listitem>
</itemizedlist><para>Network cables should be unplugged while the tests are executing to
ensure that the driver recovers gracefully from the resulting error conditions.
Another important test is for the driver to receive multiple packets in rapid
succession, that is,  <emphasis>back-to-back</emphasis> packets. In this case,
a relatively fast host on a lightly loaded network should send multiple packets
in quick succession to the test machine. Verify that the receiving driver
does not drop the second and subsequent packets.</para><para>These types of devices are usually STREAMS-based. See the <olink targetdoc="streams" remap="external"><citetitle remap="book">STREAMS Programming Guide</citetitle></olink> for
more information.</para>
</sect3>
</sect2>
</sect1>
</chapter><?Pub *0000054560 0?>