SCSA HBA interfaces include HBA entry points, HBA data structures, and an HBA framework.
SCSA defines a number of HBA driver entry points, listed in Table 14-1. These entry points are called by the system when configuring a target driver instance connected to the HBA driver, or when the target driver makes a SCSA request. See "SCSA HBA Entry Points" for more information.
Table 14-1 SCSA HBA Entry Point Summary
Function Name |
Called as a Result of |
---|---|
tran_tgt_init(9E) |
System attaching target device instance |
tran_tgt_probe(9E) |
Target driver calling scsi_probe(9F) |
tran_tgt_free(9E) |
System detaching target device instance |
tran_start(9E) |
Target driver calling scsi_transport(9F) |
tran_reset(9E) |
Target driver calling scsi_reset(9F) |
tran_abort(9E) |
Target driver calling scsi_abort(9F) |
tran_getcap(9E) |
Target driver calling scsi_ifgetcap(9F) |
tran_setcap(9E) |
Target driver calling scsi_ifsetcap(9F) |
tran_init_pkt(9E) |
Target driver calling scsi_init_pkt(9F) |
tran_destroy_pkt(9E) |
Target driver calling scsi_destroy_pkt(9F) |
tran_dmafree(9E) |
Target driver calling scsi_dmafree(9F) |
tran_sync_pkt(9E) |
Target driver calling scsi_sync_pkt(9F) |
tran_reset_notify(9E) |
Target driver calling scsi_reset_notify(9F) |
SCSA defines data structures to enable the exchange of information between the target and HBA drivers. These data structures include:
scsi_hba_tran(9S)
scsi_address(9S)
scsi_device(9S)
scsi_pkt(9S)
Each instance of an HBA driver must allocate a scsi_hba_tran(9S) structure using scsi_hba_tran_alloc(9F) in the attach(9E) entry point. scsi_hba_tran_alloc(9S) initializes the scsi_hba_tran(9S) structure before it returns. The HBA driver must initialize specific vectors in the transport structure to point to entry points within the HBA driver. Once initialized, the HBA driver exports the transport structure to SCSA by calling scsi_hba_attach_setup(9F).
Because SCSA keeps a pointer to the transport structure in the driver-private field on the dev_info(9S) structure, HBA drivers must not use ddi_set_driver_private(9F). They may, however, use ddi_get_driver_private(9F) to retrieve the pointer to the transport structure.
The scsi_hba_tran(9S) structure contains the following fields:
dev_info_t *tran_hba_dip; /* HBA dev_info_t ptr */ void *tran_hba_private; /* HBA softstate */ void *tran_tgt_private; /* target-specific info */ struct scsi_device *tran_sd; /* scsi_device, if clone */ int (*tran_tgt_init)(); /* target initialization */ int (*tran_tgt_probe)(); /* target probing */ void (*tran_tgt_free)(); /* target free */ int (*tran_start)(); /* command transport */ int (*tran_reset)(); /* target/bus reset */ int (*tran_abort)(); /* command abort */ int (*tran_getcap)(); /* get capability */ int (*tran_setcap)(); /* set capability */ struct scsi_pkt *(*tran_init_pkt)(); /* allocate scsi pkt */ void (*tran_destroy_pkt)(); /* free scsi pkt */ void (*tran_dmafree)(); /* free dma resources */ void (*tran_sync_pkt)(); /* sync data after dma */ void (*tran_reset_notify)(); /* bus reset notification */
Code fragments presented subsequently in this chapter use these fields to describe practical HBA driver operations. See "SCSA HBA Entry Points" for more information.
tran_hba_dip is a pointer to the HBA device instance dev_info structure. The function scsi_hba_attach_setup(9F) sets this field.
tran_hba_private is a pointer to private data maintained by the HBA driver. Usually, tran_hba_private contains a pointer to the state structure of the HBA driver.
tran_tgt_private is a pointer to private data maintained by the HBA driver when using cloning. By specifying SCSI_HBA_TRAN_CLONE when calling scsi_hba_attach_setup(9F), the scsi_hba_tran(9S) structure is cloned once per target, permitting the HBA to initialize this field to point to a per-target instance data structure in the tran_tgt_init(9E) entry point. If SCSI_HBA_TRAN_CLONE is not specified, tran_tgt_private is NULL and must not be referenced. See "Transport Structure Cloning (optional)" for more information.
tran_sd is a pointer to a per-target instance scsi_device(9S) structure used when cloning. If SCSI_HBA_TRAN_CLONE is passed to scsi_hba_attach_setup(9F), tran_sd is initialized to point to the per-target scsi_device structure before any HBA functions are called on behalf of that target. If SCSI_HBA_TRAN_CLONE is not specified, tran_sd is NULL and must not be referenced. See "Transport Structure Cloning (optional)" for more information.
tran_tgt_init is a pointer to the HBA driver entry point called when initializing a target device instance. If no per-target initialization is required, the HBA may leave tran_tgt_init set to NULL.
tran_tgt_probe is a pointer to the HBA driver entry point called when a target driver instance calls scsi_probe(9F) to probe for the existence of a target device. If no target probing customization is required for this HBA, the HBA should set tran_tgt_probe to scsi_hba_probe(9F).
tran_tgt_free is a pointer to the HBA driver entry point called when a target device instance is destroyed. If no per-target deallocation is necessary, the HBA may leave tran_tgt_free set to NULL.
tran_start is a pointer to the HBA driver entry point called when a target driver calls scsi_transport(9F).
tran_reset is a pointer to the HBA driver entry point called when a target driver calls scsi_reset(9F).
tran_abort is a pointer to the HBA driver entry point called when a target driver calls scsi_abort(9F).
tran_getcap is a pointer to the HBA driver entry point called when a target driver calls scsi_getcap(9F).
tran_setcap is a pointer to the HBA driver entry point called when a target driver calls scsi_setcap(9F).
tran_init_pkt is a pointer to the HBA driver entry point called when a target driver calls scsi_init_pkt(9F).
tran_destroy_pkt is a pointer to the HBA driver entry point called when a target driver calls scsi_destroy_pkt(9F).
tran_dmafree is a pointer to the HBA driver entry point called when a target driver calls scsi_dmafree(9F).
tran_sync_pkt is a pointer to the HBA driver entry point called when a target driver calls scsi_sync_pkt(9F).
tran_reset_notify is a pointer to the HBA driver entry point called when a target driver calls tran_reset_notify(9F).
The scsi_address(9S) structure provides transport and addressing information for each SCSI command allocated and transported by a target driver instance.
The scsi_address(9S) structure contains the following fields:
scsi_hba_tran_t *a_hba_tran; /* HBA transport vectors */ u_short a_target; /* Target on SCSI bus */ u_char a_lun; /* Lun on that Target */
a_hba_tran is a pointer to the scsi_hba_tran(9S) structure, as allocated and initialized by the HBA driver. If SCSI_HBA_TRAN_CLONE was specified as the flag to scsi_hba_attach_setup(9F), a_hba_tran points to a copy of that structure.
a_target identifies the SCSI target on the SCSI bus.
a_lun identifies the SCSI logical unit on the SCSI target.
The HBA framework allocates and initializes a scsi_device(9S) structure for each instance of a target device before calling an HBA driver's tran_tgt_init(9E) entry point. This structure stores information about each SCSI logical unit, including pointers to information areas that contain both generic and device-specific information. There is one scsi_device(9S) structure for each target device instance attached to the system.
If the per-target initialization is successful (in other words, if either tran_tgt_init(9E) returns success or the vector is NULL), the HBA framework will set the target driver's per-instance private data to point to the scsi_device(9S) structure, using ddi_set_driver_private(9F).
The scsi_device(9S) structure contains the following fields:
struct scsi_address sd_address; /* routing information */ dev_info_t *sd_dev; /* device dev_info node */ kmutex_t sd_mutex; /* mutex used by device */ struct scsi_inquiry *sd_inq; struct scsi_extended_sense *sd_sense; caddr_t sd_private; /* for driver's use */
sd_address is a data structure that is passed to the SCSI resource allocation routines.
sd_dev is a pointer to the target's dev_info structure.
sd_mutex is a mutex for use by the target driver. This is initialized by the HBA framework and can be used by the target driver as a per-device mutex. This mutex should not be held across a call to scsi_transport(9F) or scsi_poll(9F). See Chapter 4, Multithreading, for more information on mutexes.
sd_inq is a pointer for the target device's SCSI inquiry data. The scsi_probe(9F) routine allocates a buffer, fills it in, and attaches it to this field.
sd_sense is a pointer to a buffer to contain Request Sense data from the device. The target driver must allocate and manage this buffer itself; see the target driver's attach(9E) routine in "attach()" for more information.
sd_private is a pointer field for use by the target driver. It is commonly used to store a pointer to a private target driver state structure.
To execute SCSI commands, a target driver must first allocate a scsi_pkt(9S) structure for the command, specifying its own private data area length, the command status, and the command length. The HBA driver is responsible for implementing the packet allocation in the tran_init_pkt(9E) entry point. The HBA driver is also responsible for freeing the packet in its tran_destroy_pkt(9E) entry point. See scsi_pkt(9S) in Chapter 13, SCSI Target Drivers, for more information.
The scsi_pkt(9S) structure contains these fields:
opaque_t pkt_ha_private; /* HBA private data */ struc t scsi_address *pkt_address; /* destination address */ opaque_t pkt_private; /* target driver private */ void (*pkt_comp)(); /* pkt completion routine */ u_int pkt_flags; /* flags */ int pkt_time; /* completion timeout */ u_char *pkt_scbp; /* ptr to status block */ u_char *pkt_cdbp; /* ptr to command block */ ssize_t pkt_resid; /* bytes not transferred*/ u_int pkt_state; /* state of command */ u_int pkt_statistics; /* statistics */ u_char pkt_reason; /* pkt completion reason */
The HBA driver must modify the following fields during transport.
pkt_resid
pkt_state
pkt_statistics
pkt_reason
pkt_ha_private is a pointer to per-command HBA-driver private data.
pkt_address is a pointer to the scsi_address(9S) structure providing address information for this command.
pkt_private is a pointer to per-packet target-driver private data.
pkt_comp is a pointer to the target driver completion routine called by the HBA driver when the transport layer has completed this command.
pkt_flags are the flags for the command.
pkt_time specifies the completion timeout in seconds for the command.
pkt_scbp is a pointer to the status completion block for the command.
pkt_cdbp is a pointer to the command descriptor block (CDB) for the command.
pkt_resid is a count of the data bytes not transferred when the command has been completed or the amount of data for which resources have not been allocated.
pkt_state is the state of the command.
pkt_statistics provides a history of the events the command experienced while in the transport layer.
pkt_reason is the reason for command completion.
An HBA driver must allocate a scsi_hba_tran(9S) structure during attach(9E) and initialize the vectors in this transport structure to point to the required HBA driver entry points. This scsi_hba_tran(9S) structure is then passed into scsi_hba_attach_setup(9F).
The scsi_hba_tran(9S) structure contains a tran_hba_private field, which may be used to refer to the HBA driver's per-instance state.
Each scsi_address(9S) structure contains a pointer to the scsi_hba_tran(9S) structure and also provides the target (a_target) and logical unit (a_lun) addresses for the particular target device. Because every HBA driver entry point is passed a pointer to the scsi_address(9S) structure, either directly or indirectly through the scsi_device(9S) structure, the HBA driver can reference its own state and can identify the target device being addressed.
Figure 14-3 illustrates the HBA data structures for transport operations.
Cloning may be useful if an HBA driver needs to maintain per-target private data in the scsi_hba_tran(9S) structure, or if it needs to maintain a more complex address than is provided in the scsi_address(9S) structure.
When cloning, the HBA driver must still allocate a scsi_hba_tran(9S) structure at attach(9E) time and initialize the tran_hba_private soft state pointer and HBA entry point vectors as before. The difference occurs when the framework begins to connect an instance of a target driver to the HBA driver. Before calling the HBA driver's tran_tgt_init(9E) entry point, the framework duplicates (clones) the scsi_hba_tran(9S) structure associated with that instance of the HBA. This means that each scsi_address(9S) structure, allocated and initialized for a particular target device instance, points to a per-target instance copy of the scsi_hba_tran(9S) structure, not to the scsi_hba_tran(9S) structure allocated by the HBA driver at attach(9E) time.
Two important pointers that an HBA driver can use when it has specified cloning are contained in the scsi_hba_tran(9S) structure.The first pointer is the tran_tgt_private field, which the driver can use to point to per-target HBA private data. This is useful, for example, if an HBA driver needs to maintain a more complex address than the a_target and a_lun fields in the scsi_address(9S) structure allow. The second pointer is the tran_sd field, which is a pointer to the scsi_device(9S) structure referring to the particular target device.
When specifying cloning, the HBA driver must allocate and initialize the per-target data and initialize the tran_tgt_private field to point to this data during its tran_tgt_init(9E) entry point. The HBA driver must free this per-target data during its tran_tgt_free(9E) entry point.
When cloning, the framework initializes the tran_sd field to point to the scsi_device(9S) structure before the HBA driver tran_tgt_init(9E) entry point is called.
The driver requests cloning by passing the SCSI_HBA_TRAN_CLONE flag to scsi_hba_attach_setup(9F).
Figure 14-4 illustrates the HBA data structures for cloning transport operations.
SCSA also provides a number of functions, listed in Table 14-2, intended for use by HBA drivers.
Table 14-2 SCSA HBA Functions
Function Name |
Called by Driver Entry Point |
---|---|
scsi_hba_init(9F) |
_init(9E) |
scsi_hba_fini(9F) |
_fini(9E) |
scsi_hba_attach_setup(9F) |
attach(9E) |
scsi_hba_detach(9F) |
detach(9E) |
scsi_hba_tran_alloc(9F) |
attach(9E) |
scsi_hba_tran_free(9F) |
detach(9E) |
scsi_hba_probe(9F) |
tran_tgt_probe(9E) |
scsi_hba_pkt_alloc(9F) |
tran_init_pkt(9E) |
scsi_hba_pkt_free(9F) |
tran_destroy_pkt(9E) |
scsi_hba_lookup_capstr(9F) |
tran_getcap(9E) and tran_setcap(9E) |