Writing Device Drivers

SCSI and SCSA

These interfaces are part of the Sun Common SCSI Interface, routines that support the writing of "target drivers" to drive SCSI devices. Most of these routines handle allocating SCSI command "packets," formulating SCSI commands within those packets, and "transporting" the packets to the host adapter driver for execution. See Chapter 13, SCSI Target Drivers.

int scsi_setup_cdb(union scsi_cdb *cdbp, u_char cmd, u_int addr, u_int cnt, u_int othr_cdb_data);

scsi_setup_cdb(9F) initializes a group 0, 1, 2, 4, or 5 type of command descriptor block pointed to by cdpb using cmd, addr, cnt, othr_cdb_data.

void makecom_g0(struct scsi_pkt *pkt, 
			struct scsi_device *devp, int flag, int cmd, int addr, int cnt);

makecom_g0(9F) formulates a group 0 SCSI command for the target device denoted by devp in the scsi_pkt(9S) structure pointed to by pkt. The target must be a nonsequential access device. Use makecom_g0_s(9F) to formulate group 0 commands for sequential access devices.

void makecom_g0_s(struct scsi_pkt *pkt,  	
			struct scsi_device *devp, int flag, int cmd, int cnt, int fixbit);

makecom_g0_s(9F) formulates a group 0 SCSI command for the sequential access target device denoted by devp in the scsi_pkt(9S) structure pointed to by pkt. Use makecom_g0(9F) to formulate group 0 commands for nonsequential access devices.

void makecom_g1(struct scsi_pkt *pkt,  	
			struct scsi_device *devp, int flag, int cmd, int addr, int cnt);

makecom_g1(9F) formulates a group 1 SCSI command for the target device denoted by devp in the scsi_pkt(9S) structure pointed to by pkt.

void makecom_g5(struct scsi_pkt *pkt,  	
			struct scsi_device *devp, int flag, int cmd, int addr, int cnt);

makecom_g5(9F) formulates a group 5 SCSI command for the target device denoted by devp in the scsi_pkt(9S) structure pointed to by pkt.

int scsi_abort(struct scsi_address *ap,  	
			struct scsi_pkt *pkt);

scsi_abort(9F) cancels the command encoded in the scsi_pkt(9S) structure pointed to by pkt at the SCSI address denoted by ap. To indicate the current target, pass in ap the sd_address field of the scsi_device(9S) structure for the target. To abort the current command, pass NULL for pkt.

struct buf *scsi_alloc_consistent_buf(struct scsi_address *ap, 
			struct buf *bp, size_t datalen, u_int bflags,  	
			int (*callback)(caddr_t), caddr_t arg);

scsi_alloc_consistent_buf(9F) allocates a buffer header and the associated data buffer for DMA transfer. This buffer is allocated from the IOPB space, which is considered consistent memory. If bp is NULL, a new buffer header is allocated using getrbuf(9F). If datalen is nonzero, a new buffer will be allocated using ddi_dma_mem_alloc(9F).

If callback is not NULL_FUNC and the requested DMA resources are not immediately available, the function pointed to by callback will be called when resources may have become available. callback can call )scsi_alloc_consistent_buf(9F) again. If callback is SLEEP_FUNC, )scsi_alloc_consistent_buf(9F) might block, waiting for resources.

char *scsi_cname(u_char cmd, char **cmdvec);

scsi_cname(9F) searches for the command code cmd in the command vector cmdvec, and returns the command name. Each string in cmdvec starts with a one-character command code, followed by the name of the command. To use scsi_cname(9F), the driver must define a command vector that contains strings of this kind for all the SCSI commands it supports.

struct scsi_pkt *scsi_dmaget(struct scsi_pkt *pkt,  	
			opaque_t dmatoken, int (*callback)(void));

scsi_dmaget(9F) allocates resources for an existing scsi_pkt(9S) structure pointed to by pkt. Pass in dmatoken a pointer to the buf(9S) structure that encodes original I/O request.

If callback is not NULL_FUNC and the requested DMA resources are not immediately available, the function pointed to by callback will be called when resources may have become available. callback can call scsi_dmaget(9F) again. If callback is SLEEP_FUNC, scsi_dmaget(9F) might block, waiting for resources.

char *scsi_dname(int dtype);

scsi_dname(9F) decodes the device type code dtype found in the INQUIRY data and returns a character string denoting this device type.

void scsi_free_consistent_buf(struct buf *bp);

scsi_free_consistent_buf(9F) frees a buffer header and consistent data buffer that was previously allocated using scsi_alloc_consistent_buf(9F).

int scsi_hba_attach_setup(dev_info_t *dip,  	
			ddi_dma_attr_t *hba_dma_attr,  	scsi_hba_tran_t *hba_tran, int hba_flags);

scsi_hba_attach_setup(9F) registers the DMA attributes hba_dma_attr and the transport vectors hba_tran of each instance of the HBA device defined by dip. The HBA driver can pass different DMA attributes, and transport vectors for each instance of the device, as necessary, to support any constraints imposed by the HBA itself.

scsi_hba_attach_setup(9F) use the dev_bus_ops field in the dev_ops(9S) structure. The HBA driver should initialize this field to NULL before calling scsi_hba_attach_setup(9F).

int scsi_hba_detach(dev_info_t *dip);

scsi_hba_detach(9F) removes the reference to the DMA attributes structure and the transport vector for the given instance of an HBA driver.

int scsi_ifgetcap(struct scsi_address *ap, char *cap, int whom);

scsi_ifgetcap(9F) returns the current value of the host adapter capability denoted by cap for the host adapter servicing the target at the SCSI address pointed to by ap. See the manual page for a list of supported capabilities. whom indicates whether the capability applies only to the target at the specified SCSI address, or to all targets serviced by the host adapter.

int scsi_ifsetcap(struct scsi_address *ap,  	
			char *cap, int value, int whom);

scsi_ifsetcap(9F) sets the current value of the host adapter capability denoted by cap, for the host adapter servicing the target at the SCSI address pointed to by ap, to value. See the manual page for a list of supported capabilities. whom indicates whether the capability applies only to the target at the specified SCSI address, or to all targets serviced by the host adapter.

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);

scsi_init_pkt(9F) requests the transport layer to allocate a command packet for commands and, possibly, data transfers. If pktp is NULL, a new scsi_pkt(9S) is allocated. If bp is non-NULL and contains a valid byte count, the buf(9S) structure is set up for DMA transfer. If bp was allocated by scsi_alloc_consistent_buf(9F), the PKT_CONSISTENT flag must be set. If privatelen is set, additional space is allocated for the pkt_private area of the scsi_pkt(9S) structure; otherwise, pkt_private is a pointer that is typically used to store the bp during execution of the command. The flags are set in the command portion of the scsi_pkt(9S) structure.

If callback is not NULL_FUNC and the requested DMA resources are not immediately available, the function pointed to by callback will be called when resources may have become available. callback can call scsi_init_pkt(9F) again. If callback is SLEEP_FUNC, scsi_init_pkt(9F) might block, waiting for resources.

char *scsi_mname(u_char msg);

scsi_mname(9F) decodes the SCSI message code msg and returns the corresponding message string.

int scsi_poll(struct scsi_pkt *pkt);

scsi_poll(9F) transports the command packet pointed to by pkt to the host adapter driver for execution and waits for it to complete before it returns. Use scsi_poll(9F) sparingly and only for commands that must execute synchronously.

int scsi_probe(struct scsi_device *devp, int (*callback)(void *));

scsi_probe(9F) determines whether a target or lun is present and sets up the )scsi_device(9S) structure with inquiry data. scsi_probe(9F) uses the SCSI INQUIRY command to test if the device exists. It may retry the INQUIRY command as appropriate. If scsi_probe(9F) is successful, it will fill in the scsi_inquiry(9S) structure pointed to by the sd_inq member of the scsi_device(9S) structure, and return SCSI_PROBE_EXISTS.

If callback is not NULL_FUNC and necessary resources are not immediately available, the function pointed to by callback will be called when resources may have become available. If callback is SLEEP_FUNC, scsi_probe(9F) might block, waiting for resources.

int scsi_reset(struct scsi_address *ap, int level);

scsi_reset(9F) requests the host adapter driver to reset the target at the SCSI address pointed to by ap if level is RESET_TARGET. If level is RESET_ALL, the entire SCSI bus is reset.

char *scsi_rname(u_char reason);

scsi_rname(9F) decodes the packet completion reason code reason, and returns the corresponding reason string.

char *scsi_sname(u_char sense_key);

scsi_sname(9F) decodes the SCSI sense key sense_key, and returns the corresponding sense key string.

int scsi_transport(struct scsi_pkt *pkt);

scsi_transport(9F) requests the host adapter driver to schedule the command packet pointed to by pkt for execution. Use scsi_transport(9F) to issue most SCSI commands. scsi_poll(9F) may be used to issue synchronous commands.

void scsi_unprobe(struct scsi_device *devp);

scsi_unprobe(9F) is used to free any resources that were allocated on the driver's behalf during scsi_unprobe(9F).