Part I Designing Device Drivers for the Solaris Platform
1. Overview of Solaris Device Drivers
2. Solaris Kernel and Device Tree
5. Managing Events and Queueing Tasks
7. Device Access: Programmed I/O
10. Mapping Device and Kernel Memory
14. Layered Driver Interface (LDI)
Part II Designing Specific Kinds of Device Drivers
15. Drivers for Character Devices
Introduction to Target Drivers
Sun Common SCSI Architecture Overview
Declarations and Data Structures
scsi_pkt Structure (Target Drivers)
Autoconfiguration for SCSI Target Drivers
probe() Entry Point (SCSI Target Drivers)
attach() Entry Point (SCSI Target Drivers)
detach() Entry Point (SCSI Target Drivers)
getinfo() Entry Point (SCSI Target Drivers)
Building and Transporting a Command
Synchronous scsi_transport() Function
18. SCSI Host Bus Adapter Drivers
19. Drivers for Network Devices
Part III Building a Device Driver
21. Compiling, Loading, Packaging, and Testing Drivers
22. Debugging, Testing, and Tuning Device Drivers
23. Recommended Coding Practices
B. Summary of Solaris DDI/DKI Services
C. Making a Device Driver 64-Bit Ready
To send a SCSI command to the device, the target driver must create and initialize a scsi_pkt(9S) structure. This structure must then be passed to the host bus adapter driver.
The scsi_init_pkt(9F) routine allocates and zeroes a scsi_pkt(9S) structure. scsi_init_pkt() also sets pointers to pkt_private, *pkt_scbp, and *pkt_cdbp. Additionally, scsi_init_pkt() provides a callback mechanism to handle the case where resources are not available. This function has the following syntax:
struct scsi_pkt *scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pktp, struct buf *bp, int cmdlen, int statuslen, int privatelen, int flags, int (*callback)(caddr_t), caddr_t arg)
where:
Pointer to a scsi_address structure. ap is the sd_address field of the device's scsi_device(9S) structure.
Pointer to the scsi_pkt(9S) structure to be initialized. If this pointer is set to NULL, a new packet is allocated.
Pointer to a buf(9S) structure. If this pointer is not null and has a valid byte count, DMA resources are allocated.
Length of the SCSI command descriptor block in bytes.
Required length of the SCSI status completion block in bytes.
Number of bytes to allocate for the pkt_private field.
Set of flags:
PKT_CONSISTENT – This bit must be set if the DMA buffer was allocated using scsi_alloc_consistent_buf(9F). In this case, the host bus adapter driver guarantees that the data transfer is properly synchronized before performing the target driver's command completion callback.
PKT_DMA_PARTIAL – This bit can be set if the driver accepts a partial DMA mapping. If set, scsi_init_pkt(9F) allocates DMA resources with the DDI_DMA_PARTIAL flag set. The pkt_resid field of the scsi_pkt(9S) structure can be returned with a nonzero residual. A nonzero value indicates the number of bytes for which scsi_init_pkt(9F) was unable to allocate DMA resources.
Specifies the action to take if resources are not available. If set to NULL_FUNC, scsi_init_pkt(9F) returns the value NULL immediately. If set to SLEEP_FUNC, scsi_init_pkt() does not return until resources are available. Any other valid kernel address is interpreted as the address of a function to be called when resources are likely to be available.
Parameter to pass to the callback function.
The scsi_init_pkt() routine synchronizes the data prior to transport. If the driver needs to access the data after transport, the driver should call scsi_sync_pkt(9F) to flush any intermediate caches. The scsi_sync_pkt() routine can be used to synchronize any cached data.
If the target driver needs to resubmit the packet after changing the data, scsi_sync_pkt(9F) must be called before calling scsi_transport(9F). However, if the target driver does not need to access the data, scsi_sync_pkt() does not need to be called after the transport.
The scsi_destroy_pkt(9F) routine synchronizes any remaining cached data that is associated with the packet, if necessary. The routine then frees the packet and associated command, status, and target driver-private data areas. This routine should be called in the command completion routine.
For most I/O requests, the data buffer passed to the driver entry points is not accessed directly by the driver. The buffer is just passed on to scsi_init_pkt(9F). If a driver sends SCSI commands that operate on buffers that the driver itself examines, the buffers should be DMA consistent. The SCSI request sense command is a good example. The scsi_alloc_consistent_buf(9F) routine allocates a buf(9S) structure and a data buffer that is suitable for DMA-consistent operations. The HBA performs any necessary synchronization of the buffer before performing the command completion callback.
Note - scsi_alloc_consistent_buf(9F) uses scarce system resources. Thus, you should use scsi_alloc_consistent_buf() sparingly.
scsi_free_consistent_buf(9F) releases a buf(9S) structure and the associated data buffer allocated with scsi_alloc_consistent_buf(9F). See attach() Entry Point (SCSI Target Drivers) and detach() Entry Point (SCSI Target Drivers) for examples.