SCSI_INIT_PKT(9F) Kernel Functions for Drivers SCSI_INIT_PKT(9F)


NAME


scsi_init_pkt - prepare a complete SCSI packet

SYNOPSIS


#include <sys/scsi/scsi.h>


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


INTERFACE LEVEL


illumos DDI specific (illumos DDI).

PARAMETERS


ap

Pointer to a scsi_address(9S) structure.


pktp

A pointer to a scsi_pkt(9S) structure.


bp

Pointer to a buf(9S) structure.


cmdlen

The required length for the SCSI command descriptor block (CDB) in
bytes.


statuslen

The required length for the SCSI status completion block (SCB) in
bytes. Valid values are:

0

No status back.


1

Return SCSI status byte.


sizeof(scsi_arq_status)

Return status information in a scsi_arq_status structure. This
will include up to 20 bytes of sense data. Please refer to
scsi_arq_status(9S) for more information.

For extra sense packets (PKT_XARQ flag asserted), set statuslen
to be a greater number like, (N + sizeof(struct scsi_arq_status))
where N is the number of extra bytes beyond the default 20. For
example, N=1 requests 21 bytes of sense, N=235 asks for 255
bytes.


privatelen

The required length for the pkt_private area.


flags

Flags modifier.


callback

A pointer to a callback function, NULL_FUNC, or SLEEP_FUNC.


arg

The callback function argument.


DESCRIPTION


Target drivers use scsi_init_pkt() to request the transport layer to
allocate and initialize a packet for a SCSI command which possibly
includes a data transfer. If pktp is NULL, a new scsi_pkt(9S) is
allocated using the HBA driver's packet allocator. The bp is a pointer to
a buf(9S) structure. If bp is non-NULL and contains a valid byte count,
the buf(9S) structure is also set up for DMA transfer using the HBA
driver DMA resources allocator. When bp is allocated by
scsi_alloc_consistent_buf(9F), the PKT_CONSISTENT bit must be set in the
flags argument to ensure proper operation. If privatelen is non-zero then
additional space is allocated for the pkt_private area of the
scsi_pkt(9S). On return pkt_private points to this additional space.
Otherwise pkt_private is a pointer that is typically used to store the bp
during execution of the command. In this case pkt_private is NULL on
return.


The flags argument is a set of bit flags. Possible bits include:

PKT_CONSISTENT

This must be set if the DMA buffer was allocated using
scsi_alloc_consistent_buf(9F). In this case, the HBA driver will
guarantee that the data transfer is properly synchronized before
performing the target driver's command completion callback.


PKT_DMA_PARTIAL

This may be set if the driver can accept a partial DMA mapping. If
set, scsi_init_pkt() will allocate DMA resources with the
DDI_DMA_PARTIAL bit set in the DMA flags. The pkt_resid field of the
scsi_pkt(9S) structure may be returned with a non-zero value, which
indicates the number of bytes for which scsi_init_pkt() was unable to
allocate DMA resources. In this case, a subsequent call to
scsi_init_pkt() may be made for the same pktp and bp to adjust the
DMA resources to the next portion of the transfer. This sequence
should be repeated until the pkt_resid field is returned with a zero
value, which indicates that with transport of this final portion the
entire original request will have been satisfied.


PKT_XARQ

Setting this flag requests that the HBA return extra sense data for
this scsi_pkt(9S). The default auto request sense mechanism returns
up to 20 bytes. More than 20 bytes of sense data can be requested by
setting this flag and setting the statuslen correctly. Set the
statuslen to be the sizeof(struct scsi_arq_status) plus the number of
sense bytes needed beyond 20. For example, set statuslen to be
(sizeof(struct scsi_arq_status) + 5) for 25 bytes of sense.


When calling scsi_init_pkt() to move already-allocated DMA resources, the
cmdlen, statuslen, and privatelen fields are ignored.


The last argument arg is supplied to the callback function when it is
invoked.


callback indicates what the allocator routines should do when resources
are not available:

NULL_FUNC
Do not wait for resources. Return a NULL pointer.


SLEEP_FUNC
Wait indefinitely for resources.


Other Values
callback points to a function which is called when
resources may have become available. callback must return
either 0 (indicating that it attempted to allocate
resources but again failed to do so), in which case it is
put back on a list to be called again later, or 1
indicating either success in allocating resources or
indicating that it no longer cares for a retry.


When allocating DMA resources, scsi_init_pkt() returns the scsi_pkt field
pkt_resid as the number of residual bytes for which the system was unable
to allocate DMA resources. A pkt_resid of 0 means that all necessary DMA
resources were allocated.

RETURN VALUES


The scsi_init_pkt() function returns NULL if the packet or DMA resources
could not be allocated. Otherwise, it returns a pointer to an initialized
scsi_pkt(9S). If pktp was not NULL the return value will be pktp on
successful initialization of the packet.

CONTEXT


If callback is SLEEP_FUNC, then this routine can be called only from
user-level code. Otherwise, it can be called from user, interrupt, or
kernel context. The callback function may not block or call routines that
block.

EXAMPLES


Example 1: Allocating a Packet Without DMA Resources Attached




To allocate a packet without DMA resources attached, use:


pkt = scsi_init_pkt(&devp->sd_address, NULL, NULL, CDB_GROUP1,
1, sizeof (struct my_pkt_private *), 0,
sd_runout, sd_unit);


Example 2: Allocating a Packet With DMA Resources Attached




To allocate a packet with DMA resources attached use:


pkt = scsi_init_pkt(&devp->sd_address, NULL, bp, CDB_GROUP1,
sizeof(struct scsi_arq_status), 0, 0, NULL_FUNC, NULL);


Example 3: Attaching DMA Resources to a Preallocated Packet




To attach DMA resources to a preallocated packet, use:


pkt = scsi_init_pkt(&devp->sd_address, old_pkt, bp, 0,
0, 0, 0, sd_runout, (caddr_t) sd_unit);


Example 4: Allocating a Packet with Consistent DMA Resources Attached




Since the packet is already allocated, the cmdlen, statuslen and
privatelen are 0. To allocate a packet with consistent DMA resources
attached, use:


bp = scsi_alloc_consistent_buf(&devp->sd_address, NULL,
SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL);
pkt = scsi_init_pkt(&devp->sd_address, NULL, bp, CDB_GROUP0,
sizeof(struct scsi_arq_status), sizeof (struct my_pkt_private *),
PKT_CONSISTENT, SLEEP_FUNC, NULL);


Example 5: Allocating a Packet with Partial DMA Resources Attached




To allocate a packet with partial DMA resources attached, use:


my_pkt = scsi_init_pkt(&devp->sd_address, NULL, bp, CDB_GROUP0,
1, sizeof (struct buf *), PKT_DMA_PARTIAL,
SLEEP_FUNC, NULL);


SEE ALSO


scsi_alloc_consistent_buf(9F), scsi_destroy_pkt(9F), scsi_dmaget(9F),
scsi_pktalloc(9F), buf(9S), scsi_address(9S), scsi_pkt(9S)


Writing Device Drivers

NOTES


If a DMA allocation request fails with DDI_DMA_NOMAPPING, the B_ERROR
flag will be set in bp, and the b_error field will be set to EFAULT.


If a DMA allocation request fails with DDI_DMA_TOOBIG, the B_ERROR flag
will be set in bp, and the b_error field will be set to EINVAL.


May 24, 2014 SCSI_INIT_PKT(9F)