Declarations and Structures

To inform the system that the module depends on SCSA routines, the
driver binary must be generated with the following command. See SCSA HBA Interfaces for more
information on SCSA routines.

% ld -r xx.o -o xx -N "misc/scsi"

The code samples are derived from a simplified isp driver for the QLogic
Intelligent SCSI Peripheral device. The isp driver supports WIDE SCSI, with up to
15 target devices and 8 logical units (LUNs) per target.

Per-Command Structure

An HBA driver usually needs to define a structure to maintain state for
each command submitted by a target driver. The layout of this per-command structure
is entirely up to the device driver writer. The layout needs to reflect
the capabilities and features of the hardware and the software algorithms that are
used in the driver.

The following structure is an example of a per-command structure. The remaining code
fragments of this chapter use this structure to illustrate the HBA interfaces.

Entry Points for Module Initialization

This section describes the entry points for operations that are performed by SCSI
HBA drivers.

The following code for a SCSI HBA driver illustrates a representative dev_ops(9S)
structure. The driver must initialize the devo_bus_ops field in this structure to NULL. A
SCSI HBA driver can provide leaf driver interfaces for special purposes, in which
case the devo_cb_ops field might point to a cb_ops(9S) structure. In this example, no
leaf driver interfaces are exported, so the devo_cb_ops field is initialized to
NULL.

_init() Entry Point (SCSI HBA Drivers)

The _init(9E) function initializes a loadable module. _init() is called before any other routine
in the loadable module.

In a SCSI HBA, the _init() function must call scsi_hba_init(9F) to
inform the framework of the existence of the HBA driver before calling
mod_install(9F). If scsi_hba__init() returns a nonzero value,_init() should return this value. Otherwise, _init()
must return the value returned by mod_install(9F).

The driver should initialize any required global state before calling mod_install(9F).

If mod_install() fails, the _init() function must free any global resources allocated.
_init() must call scsi_hba_fini(9F) before returning.

The following example uses a global mutex to show how to allocate
data that is global to all instances of a driver. The code declares
global mutex and soft-state structure information. The global mutex and soft state are initialized
during _init().

_fini() Entry Point (SCSI HBA Drivers)

The _fini(9E) function is called when the system is about to try to
unload the SCSI HBA driver. The _fini() function must call mod_remove(9F)
to determine whether the driver can be unloaded. If mod_remove() returns 0, the module
can be unloaded. The HBA driver must deallocate any global resources allocated
in _init(9E). The HBA driver must also call scsi_hba_fini(9F).

Autoconfiguration Entry Points

Associated with each device driver is a dev_ops(9S) structure, which enables the kernel to
locate the autoconfiguration entry points of the driver. A complete description of these
autoconfiguration routines is given in Chapter 6, Driver Autoconfiguration. This section describes only those entry points associated
with operations performed by SCSI HBA drivers. These entry points include attach(9E)
and detach(9E).

attach() Entry Point (SCSI HBA Drivers)

The attach(9E) entry point for a SCSI HBA driver performs several tasks when
configuring and attaching an instance of the driver for the device. For a
typical driver of real devices, the following operating system and hardware concerns must
be addressed:

Soft-state structure

DMA

Transport structure

Attaching an HBA driver

Register mapping

Interrupt specification

Interrupt handling

Create power manageable components

Report attachment status

Soft-State Structure

When allocating the per-device-instance soft-state structure, a driver must clean up carefully if
an error occurs.

DMA

The HBA driver must describe the attributes of its DMA engine by
properly initializing the ddi_dma_attr_t structure.

The driver, if providing DMA, should also check that its hardware is installed
in a DMA-capable slot:

if (ddi_slaveonly(dip) == DDI_SUCCESS) {
return (DDI_FAILURE);
}

Transport Structure

The driver should further allocate and initialize a transport structure for this instance.
The tran_hba_private field is set to point to this instance's soft-state structure. The
tran_tgt_probe field can be set to NULL to achieve the default behavior, if
no special probe customization is needed.

If a high-level handler is required, the driver should be coded to
provide such a handler. Otherwise, the driver must be able to fail the
attach. See Handling High-Level Interrupts for a description of high-level interrupt handling.

Create Power Manageable Components

With power management, if the host bus adapter only needs to power
down when all target adapters are at power level 0, the HBA driver
only needs to provide a power(9E) entry point. Refer to Chapter 12, Power Management. The HBA driver
also needs to create a pm-components(9P) property that describes the components that the
device implements.

Nothing more is necessary, since the components will default to idle, and the
power management framework's default dependency processing will ensure that the host bus adapter
will be powered up whenever an target adapter is powered up. Provided that
automatic power management is enabled automatically, the processing will also power down the
host bus adapter when all target adapters are powered down ().

Report Attachment Status

Finally, the driver should report that this instance of the device is attached
and return success.