NAME
scsipi
- SCSI/ATAPI middle-layer interface
SYNOPSIS
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
)
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 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
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
, 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(4)
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 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.
- intadapt_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.
- intadapt_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.
- intadapt_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 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.
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
NetBSD1.6.
AUTHORS
The
scsipi
interface was designed and implemented by Jason R. Thorpe.
Manuel Bouyer converted most drivers to the new interface.