SCSIPI(9)
π NAME π
scsipi β SCSI/ATAPI middle-layer interface. This is SCSIPI(9) from the Kernel Developer's Manual, bestie, and weβre folding that header in right here like a cute lilβ sticker. π
β¨ 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 πΈ
Okay so scsipi is the middle-layer interface between SCSI/ATAPI host bus adapters (HBA) and high-level SCSI/ATAPI drivers. This doc is specifically about the interfaces that the scsipi layer gives to 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 β meaning a 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. No cap. π₯
π οΈ INITALISATION π οΈ
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βsstruct 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 bychan_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 toNULLif not used.int (*adapt_getgeom)(struct scsipi_periph *, struct disk_parms *, u_long)β optional, set toNULLif not used.int (*adapt_accesschk)(struct scsipi_periph *, struct scsipi_inquiry_pattern *)β optional, set toNULLif 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βsstruct scsipi_adapter.struct scsipi_bustype *chan_bustypeβ should be initialized to eitherbus_atapiorbus_scsi, both defined in thescsipicode.int chan_channelβ channel number (starting at0).int chan_flagsβ channel flags:SCSIPI_CHAN_OPENINGSβ Use per-channel max number of commandschan_openingsinstead of per-adapteradapt_openings.SCSIPI_CHAN_CANGROWβ This channel can grow itschan_openingsoradapt_openingson request (via theadapt_request()callback).SCSIPI_CHAN_NOSETTLEβ Do not waitSCSI_DELAYseconds 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 theSCSIPI_CHAN_OPENINGSflag is set).chan_max_periphβ number of commands per device the adapter can handle on this channel (used only if theSCSIPI_CHAN_OPENINGSflag 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βsstruct 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_datapoints to astruct uiobuffer.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 byscsipi_done()).XS_STS_PRIVATEβ mask of flags reserved for HBAβs use (0xf0000000).
Okay so, picking right back up with the rest of the scsipi_xfer fields β stay with me, bestie, because every single one of these matters:
struct scsipi_periph *xs_periphβ the 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 throughscsipi_done()with aXS_TIMEOUTerror.struct scsipi_generic *cmdβ the scsipi command to execute.int cmdlenβ len (in bytes) of thecmdbuffer.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 betweendatalenand how much data was really transferred.scsipi_xfer_result_t errorβ error value returned by the HBA driver to mid-layer. See description ofscsipi_done()for valid values.union {struct scsipi_sense_data scsi_sense; uint32_t atapi_sense;} senseβ where to store sense info iferrorisXS_SENSEorXS_SHORTSENSE.uint8_t statusβ SCSI status; checked by middle layer whenerrorisXS_BUSY(the middle layer handlesSCSI_CHECKandSCSI_QUEUE_FULL).uint8_t xs_tag_typeβ SCSI tag type, set to0if 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.reqcan be one of:ADAPTER_REQ_RUN_XFERβ request the adapter to send a command to the device.argis a pointer to thestruct scsipi_xfer. Once the xfer is complete the HBA driver shall callscsipi_done()with updated status and error information.ADAPTER_REQ_GROW_RESOURCESβ ask the adapter to increase resources of the channel (growadapt_openingsorchan_openings) if possible. Support of this feature is optional. This request is called from the kernel completion thread.argmust 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.argpoints to astruct scsipi_xfer_modedefined 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 transfersPERIPH_CAP_WIDE16β ST 16 bit wide transfersPERIPH_CAP_WIDE32β ST 32 bit wide transfersPERIPH_CAP_DTβ DT transfersPERIPH_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. No cap, be ready for it. π
adapt_minphys()β pointer to the driver'sminphysfunction. If the driver can handle transfers of sizeMAXPHYS, this can point tominphys().adapt_ioctl()β ioctl function for the channel. The only ioctl supported at this level isSCBUSIORESETfor which the HBA driver shall issue a SCSI reset on the channel.int adapt_enable(struct device *dev, int enable)β disable the adapter ifenableis zero, or enable it if non-zero. Returns0if 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()andscsipi_adapter_delref()maintain a reference count, theenablecallback 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. Returns0if 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.eventcan be one of:ASYNC_EVENT_MAX_OPENINGSβ set max openings for a periph. Argument is astruct scsipi_max_openingswith 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 astruct scsipi_xfer_modeproperly filled in. AnASYNC_EVENT_XFER_MODEcall withPERIPH_CAP_TQINGset inxm_modeis mandatory to activate tagged queuing.ASYNC_EVENT_RESETβ channel has been reset. No argument. HBA drivers have to issueASYNC_EVENT_RESETevents 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.errorin thescsipi_xfershall 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 checkstatusfor 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 oncescsipi_done(xfer)has been called, unless the xfer hadXS_CTL_POLLset. This is a hard line, bestie β do not cross it. π
scsipi_done()β this one's the vibe check for the adapt layer: it will call theadapt_request()callback again only if it's called withxs->errorset toXS_NOERROR, and only ifxferdoesn't haveXS_CTL_POLLset. Every other error condition gets handled by a kernel thread (once the HBA's interrupt handler has returned). No cap, that's just how it is πscsipi_printaddr(struct scsipi_periph *periph)β prints a kernel message with the periph's name, in the formdevice(controller:channel:target:lun). It's giving "hello, this is my whole address" energy β¨scsipi_channel_freeze(struct scsipi_channel *chan, int count)β freezes the specified channel, meaning requests get queued but not sent to the HBA. The channel's freeze counter goes up bycount. Think of it as putting the whole channel on Do Not Disturb π§scsipi_channel_thaw(struct scsipi_channel *chan, int count)β decrements the channel's freeze counter bycountand processes the queue if the counter hits0. But hear me out: to preserve command ordering, HBA drivers should not callscsipi_channel_thaw()before callingscsipi_done()for all commands in the HBA's queue which need to be requeued. Order matters, bestie, fr fr π₯scsipi_periph_timed_thaw(void *arg)β literally just callsscsipi_channel_thaw(arg, 1). It's intended to be used as acallout(9)callback. Scheduled thaw, iconic behavior β°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. Same energy, smaller scope β main character periph only π
scsipi_target_detach(struct scsipi_channel *chan, int target, int lun, int flags)β detaches the periph associated with this I_T_L nexus. Bothtargetandlunmay be wildcarded using the magic value-1.flagsis passed toconfig_detach(). Returns0if successful, or an error code if a device couldn't be removed. Breaking up with a device is complicated sometimes πscsipi_thread_call_callback(struct scsipi_channel *chan, void (*callback)(struct scsipi_channel *, void *), void *arg)βcallback()will be called withchanandargas arguments, from the channel completion thread. The callback is run atIPL_BIOwith the channel lock held.scsipi_thread_call_callback()will freeze the channel by one, and it's up to the caller to thaw it when appropriate. Returns0if the callback was properly recorded, orEBUSYif the channel has already a callback pending. So like, it's a whole commitment, don't double-book πΈ
π FILES
sys/dev/scsiconf.hβ header file for use by SCSI HBA driverssys/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. So scsipiconf.h is the actual mothership πΈ
π EXAMPLES
The best examples are existing HBA drivers. Most of them sit in the sys/dev/ic directory. Go read the source, bestie, that's the whole assignment πβ¨
π°οΈ HISTORY
The scsipi interface appeared in NetBSD 1.6. Vintage but make it fresh π
π AUTHORS
The scsipi interface was designed and implemented by Jason R. Thorpe. Manuel Bouyer converted most drivers to the new interface. Absolute legends, both of them π«Ά
And that's the whole page, babe β brought to you by Debian, dated November 20, 2016. Slay, go write a driver π π
π¦ where this page comes from
- nixpkgs unstable: netbsd-source 11.0
- Copyright (c) 2001 Manuel Bouyer
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms