scsipi - SCSI/ATAPI middle-layer interface
#include <dev/scsipi/atapiconf.h>
#include <dev/scsipi/scsiconf.h>
void
scsipi_async_event(struct scsipi_channel *chan,
scsipi_async_event_t event, void *arg);
void
scsipi_channel_freeze(struct scsipi_channel *chan, int count);
void
scsipi_channel_thaw(struct scsipi_channel *chan, int count);
void
scsipi_channel_timed_thaw(void *arg);
void
scsipi_periph_freeze(struct scsipi_periph *periph, int count);
void
scsipi_periph_thaw(struct scsipi_periph *periph, int count);
void
scsipi_periph_timed_thaw(void *arg);
void
scsipi_done(struct scsipi_xfer *xs);
void
scsipi_printaddr(struct scsipi_periph *periph);
int
scsipi_target_detach(struct scsipi_channel *chan, int target, int lun,
int flags);
int
scsipi_thread_call_callback(struct scsipi_channel *chan,
void (*callback)(struct scsipi_channel *, void *), void *arg);
The scsipi system is the middle layer interface between SCSI/ATAPI host
bus adapters (HBA) and high-level SCSI/ATAPI drivers. This document
describes the interfaces provided by the scsipi layer towards the HBA
layer. An HBA has to provide a pointer to a struct scsipi_adapter and
one pointer per channel to a struct scsipi_channel. Once the SCSI or
ATAPI bus is attached, the scsipi system will scan the bus and allocate a
struct scsipi_periph for each device found on the bus. A high-level command
(command sent from the high-level SCSI/ATAPI layer to the low-level
HBA layer) is described by a struct scsipi_xfer.
A request is sent to the HBA driver though the adapt_request() callback.
The HBA driver signals completion (with or without errors) of the request
though scsipi_done(). scsipi knows the resources limits of the HBA (max
number of concurrent requests per adapter of channel, and per periph),
and will make sure the HBA won't receive more requests than it can handle.
The mid-layer can also handle QUEUE FULL and CHECK CONDITION events.
INITIALISATION [Toc] [Back]
An HBA driver has to allocate and initialize to 0 a struct scsipi_adapter
and fill in the following members:
struct device *adapt_dev pointer to the HBA's struct device
int adapt_nchannels number of channels (or busses) of the
adapter
int adapt_openings total number of commands the adapter can
handle (may be replaced by chan_openings,
see below)
int adapt_max_periph number of commands the adapter can handle
per device
The following callbacks should be provided through the struct
scsipi_adapter:
void (*adapt_request)(struct scsipi_channel *,
scsipi_adapter_req_t, void *)
mandatory
void (*adapt_minphys)(struct buf *)
mandatory
int (*adapt_ioctl)(struct scsipi_channel *, u_long, caddr_t, int,
struct proc *)
optional
int (*adapt_enable)(struct device *, int)
optional, set to NULL if not used
int (*adapt_getgeom)(struct scsipi_periph *, struct disk_parms *,
u_long)
optional, set to NULL if not used
int (*adapt_accesschk)(struct scsipi_periph *, struct
scsipi_inquiry_pattern *)
optional, set to NULL if not used
The HBA driver has to allocate and initialize to 0 one struct
scsipi_channel per channel and fill in the following members:
struct scsipi_adapter *chan_adapter
Pointer to the HBA's struct scsipi_adapter
struct scsipi_bustype *chan_bustype
should be initialized to either bus_atapi or
bus_scsi, both defined in the scsipi code.
int chan_channel channel number (starting at 0)
int chan_flags channel flags:
SCSIPI_CHAN_OPENINGS Use per-channel max
number of commands
chan_openings instead
of per-adapter
adapt_openings
SCSIPI_CHAN_CANGROW This channel can grow
its chan_openings or
adapt_openings on
request (via the
adapt_request() callback)
SCSIPI_CHAN_NOSETTLE Do not wait SCSI_DELAY
seconds for devices to
settle before probing
(usually used by
adapters that provide
an "abstracted" view
of the bus).
int chan_openings total number of commands the adapter can
handle for this channel (used only if the
SCSIPI_CHAN_OPENINGS flag is set)
chan_max_periph number of commands per device the adapter
can handle on this channel (used only if the
SCSIPI_CHAN_OPENINGS flag is set)
int chan_ntargets number of targets
int chan_nluns number of LUNs per target
int chan_id adapter's ID on this channel
int chan_defquirks default device quirks. Quirks are defined
in <dev/scsipi/scsipiconf.h> and are usually
set in the middle layer based on the
device's inquiry data. For some kinds of
adapters it may be convenient to have a set
of quirks applied to all devices, regardless
of the inquiry data.
The HBA driver attaches the SCSI or ATAPI bus (depending on the setting
of chan_bustype) by passing a pointer to the struct scsipi_channel to the
autoconf(4) machinery. The print function shall be either scsiprint() or
atapiprint().
OTHER DATA STRUCTURES [Toc] [Back]
When scanning the bus, the scsipi system allocates a struct scsipi_periph
for each device probed. The interesting fields are:
struct device *periph_dev
pointer to the device's struct device
struct scsipi_channel *periph_channel
pointer to the channel the device is connected
to
int periph_quirks device quirks, defined in
<dev/scsipi/scsipiconf.h>
int periph_target target ID, or drive number on ATAPI
int periph_lun LUN (currently not used on ATAPI)
A SCSI or ATAPI request is passed to the HBA through a struct
scsipi_xfer. The HBA driver has access to the following data:
struct callout xs_callout
callout for adapter use, usually for command timeout
int xs_control control flags (only flags of interest for HBA
drivers are described):
XS_CTL_POLL poll in the HBA driver for
request completion (most likely
because interrupts are disabled)
XS_CTL_RESET reset the device
XS_CTL_DATA_UIO xs_data points to a struct uio
buffer
XS_CTL_DATA_IN data is transferred from HBA to
memory
XS_CTL_DATA_OUT data is transferred from memory
to HBA
XS_CTL_DISCOVERY this xfer is part of a device
discovery done by the middle
layer
XS_CTL_REQSENSE xfer is a request sense
int xs_status status flags:
XS_STS_DONE xfer is done (set by scsipi_done())
XS_STS_PRIVATE mask of flags reserved for HBA's
use (0xf0000000)
struct scsipi_periph *xs_periph
periph doing the xfer
int timeout command timeout, in milliseconds. The HBA should
start the timeout at the time the command is
accepted by the device. If the timeout happens,
the HBA shall terminate the command through
scsipi_done() with a XS_TIMEOUT error
struct scsipi_generic *cmd
scsipi command to execute
int cmdlen len (in bytes) of the cmd buffer
u_char *data data buffer (this is either a dma or uio address)
int datalen data length (in bytes, zero if uio)
int resid difference between datalen and how much data was
really transferred
scsipi_xfer_result_t error
error value returned by the HBA driver to midlayer.
See description of scsipi_done() for valid
values
union {struct scsipi_sense_data scsi_sense; u_int32_t atapi_sense;}
sense
where to store sense info if error is XS_SENSE or
XS_SHORTSENSE
u_int8_t status
SCSI status; checked by middle layer when error is
XS_BUSY (the middle layer handles SCSI_CHECK and
SCSI_QUEUE_FULL)
u_int8_t xs_tag_type
SCSI tag type, set to 0 if untagged command
u_int8_t xs_tag_id
tag ID, used for tagged commands
FUNCTIONS AND CALLBACKS [Toc] [Back]
(*adapt_request)(struct scsipi_channel *chan, scsipi_adapter_req_t req,
void *arg)
Used by the mid-layer to transmit a request to the adapter.
req can be one of:
ADAPTER_REQ_RUN_XFER
request the adapter to send a command to the device.
arg is a pointer to the struct scsipi_xfer. Once the
xfer is complete the HBA driver shall call
scsipi_done() with updated status and error information.
ADAPTER_REQ_GROW_RESOURCES
ask the adapter to increase resources of the channel
(grow adapt_openings or chan_openings) if possible.
Support of this feature is optional. This request is
called from the kernel completion thread. arg must
be ignored.
ADAPTER_REQ_SET_XFER_MODE
set the xfer mode for a for I_T Nexus. This will be
called once all LUNs of a target have been probed.
arg points to a struct scsipi_xfer_mode defined as
follows:
int xm_target target for I_T Nexus
int xm_mode bitmask of device capabilities
int xm_period sync period
int xm_offset sync offset
xm_period and xm_offset shall be ignored for
ADAPTER_REQ_SET_XFER_MODE. xm_mode holds the following
bits:
PERIPH_CAP_SYNC
ST synchronous transfers
PERIPH_CAP_WIDE16
ST 16 bit wide transfers
PERIPH_CAP_WIDE32
ST 32 bit wide transfers
PERIPH_CAP_DT
DT transfers
PERIPH_CAP_TQING
tagged queueing
Whenever the xfer mode changes, the driver should
call scsipi_async_event() to notify the mid-layer.
adapt_request() may be called from interrupt context.
adapt_minphys()
pointer to the driver's minphys function. If the driver can
handle transfers of size MAXPHYS, this can point to minphys().
adapt_ioctl()
ioctl function for the channel. The only ioctl supported at
this level is SCBUSIORESET for which the HBA driver shall issue
a SCSI reset on the channel.
int adapt_enable(struct device *dev, int enable)
Disable the adapter if enable is zero, or enable it if nonzero.
Returns 0 if operation is successful, or error from
<sys/errno.h>. This callback is optional, and is useful mostly
for hot-plug devices. For example, this callback would power
on or off the relevant PCMCIA socket for a PCMCIA controller.
int adapt_getgeom(struct scsipi_periph *periph, struct disk_parms
*params, u_long sectors)
Optional callback, used by high-level drivers to get the fictitious
geometry used by the controller's firmware for the specified
periph. Returns 0 if successful. See adaptec drivers for
details.
int adapt_accesschk(struct scsipi_periph *periph, struct
scsipi_inquiry_pattern *inqbuf)
Optional callback; if present the mid-layer uses it to check if
it can attach a driver to the specified periph. If the callback
returns a non-zero value, the periph is ignored by the
scsipi code. This callback is used by adapters which want to
drive some devices themselves, for example hardware RAID controllers.
scsipi_async_event(struct scsipi_channel *chan, scsipi_async_event_t
event, void *arg)
Asynchronous event notification for the mid-layer. event can
be one of:
ASYNC_EVENT_MAX_OPENINGS
set max openings for a periph. Argument is a struct
scsipi_max_openings with at least the following members:
int mo_target
int mo_lun
int mo_openings
Not all periphs may allow openings to increase; if
not allowed the request is silently ignored.
ASYNC_EVENT_XFER_MODE
update the xfer mode for an I_T nexus. Argument is a
struct scsipi_xfer_mode properly filled in. An
ASYNC_EVENT_XFER_MODE call with PERIPH_CAP_TQING set
in xm_mode is mandatory to activate tagged queuing.
ASYNC_EVENT_RESET
channel has been reset. No argument. HBA drivers
have to issue ASYNC_EVENT_RESET events if they rely
on the mid-layer for SCSI CHECK CONDITION handling.
scsipi_done(struct scsipi_xfer *xs)
shall be called by the HBA when the xfer is complete, or when
it needs to be requeued by the mid-layer. error in the
scsipi_xfer shall be set to one of the following:
XS_NOERROR
xfer completed without error.
XS_SENSE Check the returned SCSI sense for the error.
XS_SHORTSENSE
Check the ATAPI sense for the error.
XS_DRIVER_STUFFUP
Driver failed to perform operation.
XS_RESOURCE_SHORTAGE
Adapter resource shortage. The mid-layer will retry
the command after some delay.
XS_SELTIMEOUT
The device timed out while trying to send the command
XS_TIMEOUT
The command was accepted by the device, but it didn't
complete in allowed time.
XS_BUSY The mid-layer will check status for additional
details:
SCSI_CHECK SCSI check condition. The mid-layer
will freeze the periph queue and
issue a REQUEST SENSE command. If
the HBA supports tagged queuing, it
shall remove and requeue any command
not yet accepted by the HBA (or at
last make sure no more commands will
be sent to the device before the
REQUEST SENSE is complete).
SCSI_QUEUE_FULL The mid layer will adjust the
periph's openings and requeue the
command.
SCSI_BUSY The mid-layer will requeue the xfer
after delay.
XS_RESET xfer destroyed by a reset; the mid-layer will requeue
it.
XS_REQUEUE
Ask the mid-layer to requeue this command immediately.
The adapter should not reference an xfer once scsipi_done(xfer)
has been called, unless the xfer had XS_CTL_POLL set.
scsipi_done() will call the adapt_request() callback again only
if called with xs->error set to XS_NOERROR, and xfer doesn't
have XS_CTL_POLL set. All other error conditions are handled
by a kernel thread (once the HBA's interrupt handler has
returned).
scsipi_printaddr(struct scsipi_periph *periph)
print a kernel message with the periph's name, in the form
device(controller:channel:target:lun).
scsipi_channel_freeze(struct scsipi_channel *chan, int count)
Freeze the specified channel (requests are queued but not sent
to HBA). The channel's freeze counter is increased by count.
scsipi_channel_thaw(struct scsipi_channel *chan, int count)
Decrement the channel's freeze counter by count and process the
queue if the counter goes to 0. In order to preserve command
ordering, HBA drivers should not call scsipi_channel_thaw()
before calling scsipi_done() for all commands in the HBA's
queue which need to be requeued.
scsipi_periph_timed_thaw(void *arg)
Call scsipi_channel_thaw(arg, 1). Intended to be used as
callout(9) callback.
scsipi_periph_freeze(struct scsipi_periph *periph, int count)
scsipi_periph_thaw(struct scsipi_periph *periph)
scsipi_periph_timed_thaw(void *arg)
Same as the channel counterparts, but only for one specific
peripheral.
scsipi_target_detach(struct scsipi_channel *chan, int target, int lun,
int flags)
detach the periph associated with this I_T_L nexus. Both target
and lun may be wildcarded using the magic value -1. flags is
passed to config_detach() . Returns 0 if successfull, or error
code if a device couldn't be removed.
scsipi_thread_call_callback(struct scsipi_channel *chan, void
(*callback)(struct scsipi_channel *, void *), void *arg)
callback() will be called with chan and arg as arguments, from
the channel completion thread. The callback is run at splbio.
scsipi_thread_call_callback() will freeze the channel by one,
it's up to the caller to thaw it when appropriate. Returns 0
if the callback was properly recorded, or EBUSY if the channel
has already a callback pending.
sys/dev/scsiconf.h header file for use by SCSI HBA drivers
sys/dev/atapiconf.h header file for use by ATAPI HBA drivers
Both header files include sys/dev/scsipiconf.h which contains most structure
definitions, function prototypes and macros.
The best examples are existing HBA drivers. Most of them sit in the
sys/dev/ic directory.
The scsipi interface appeared in NetBSD 1.6.
The scsipi interface was designed and implemented by Jason R. Thorpe.
Manuel Bouyer converted most drivers to the new interface.
BSD April 22, 2001 BSD
[ Back ] |