NAME
scsipi —
SCSI/ATAPI middle-layer
interface
SYNOPSIS
#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);
int
scsipi_adapter_addref(
struct
scsipi_adapter *adapt);
void
scsipi_adapter_delref(
struct
scsipi_adapter *adapt);
DESCRIPTION
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 through the
adapt_request() callback. The HBA driver signals completion
(with or without errors) of the request through
scsipi_done().
scsipi knows the resource's
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
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
- int
adapt_flags
- adapter properties
SCSIPI_ADAPT_POLL_ONLY
- the HBA can't do interrupts
SCSIPI_ADAPT_MPSAFE
- don't acquire the kernel lock when doing HBA
callbacks
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, void *,
int, struct lwp *)
- 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(9) machinery. The
print function shall be either
scsiprint() or
atapiprint().
OTHER DATA STRUCTURES
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 mid-layer. See
description of scsipi_done() for valid values
- union
{struct scsipi_sense_data scsi_sense; uint32_t atapi_sense;}
sense
- where to store sense info if error is
XS_SENSE
or
XS_SHORTSENSE
- uint8_t
status
- SCSI status; checked by middle layer when
error is
XS_BUSY
(the middle
layer handles SCSI_CHECK
and
SCSI_QUEUE_FULL
)
- uint8_t
xs_tag_type
- SCSI tag type, set to 0 if untagged command
- uint8_t
xs_tag_id
- tag ID, used for tagged commands
FUNCTIONS AND CALLBACKS
- (*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 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 queuing
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 non-zero. 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. scsipi_adapter_addref() and
scsipi_adapter_delref() maintain a reference count, the
enable callback is called appropriately for the first reference and the
last reference.
- 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
successful, 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
IPL_BIO
with the channel lock held.
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.
FILES
-
-
- 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.
EXAMPLES
The best examples are existing HBA drivers. Most of them sit in the
sys/dev/ic directory.
HISTORY
The
scsipi interface appeared in
NetBSD
1.6.
AUTHORS
The
scsipi interface was designed and implemented by
Jason R. Thorpe.
Manuel Bouyer
converted most drivers to the new interface.