SCSIPI(9)

SCSIPI(9) | Kernel Developer's Manual | SCSIPI(9)

# 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.

November 20, 2016 | NetBSD 10.0