|
|
Scatter/gather is used to do DMA data transfers of data that is written to noncontiguous areas of memory. A scatter/gather list is a list of vectors, each of which gives the location and length of one segment in the overall read or write request. Many devices have a DMA controller on each adapter card that must be programmed in some driver-specific fashion. ISA devices generally use the system DMA controller for DMA transfers. See ``DMA'' for general information about implementing DMA operations.
To implement scatter/gather for a driver, the driver must obtain the physical addresses of each contiguous memory region with which to program the device, using the appropriate mechanism for the data type and interface version.
DDI provides facilities for setting up scatter/gather operations for either STREAMS or non-STREAMS devices, depending on the type of device and the DDI version. The primary ones are:
The following method works for most non-STREAMS drivers which, for DDI 8, use a buf(D4) structure even for I/O operations that do not go through the system buffer cache.
phys_align
phys_boundary
phys_dma_size
The DDI scatter/gather implementation
supports both 32-bit and 64-bit data transfers.
The kernel uses phys_dma_size
to determine
which format to use.
See
``DMA up to 64 bits (DDI only)''.
phys_max_scgth
bcb_addrtype
bcb_flags
bcb_granularity
to 1
means that the I/O is not block-oriented.
bcb_max_xfer
bcb_granularity
bcb_physreq
drv_flags
member of the
drvinfo(D4)
structure.
The bcb structure is used by the buf_breakup(D3) function which, for DDI 8 and later drivers, is called before entering the biostart(D2) entry point routine that handles all read and write operations.
The scgth structure defines the physical memory region that is used for all scatter/gather operations in DDI 8 and later drivers.
The system picks up the bcb when the driver's open(D2) entry point routine executes. I/O operations that originate from the read, pread, write, or pwrite system call enter the driver at the biostart(D2) entry point. At this point, the memory is ``wired'' down and meets all the physreq constraints. The driver can use the scatter/gather list of physical addresses that is associated with this bcb structure for its I/O operations.
If the memory cannot be wired down within the bcb constraints, then an error is generated to the caller and the biostart( ) entry point is not invoked.
Note that,
if the I/O request is initiated with a
read
or
write
system call to a character device node
of a non-STREAMS DDI 8 driver,
the kernel creates a buffer of type BA_UIO
to describe the data.
This buffer is always passed through the
buf_breakup(D3)
function before the driver's
biostart(D2)
entry point routine is called.
DDI 8 does not distinguish
between block and character drivers,
but if the driver specifies BA_UIO
in the bcb_addrtype
member of the
bcb(D4)
structure,
buf_breakup( )
passes the buffer without manipulating it.
I/O operations that originate with
readv
or
writev
system calls atempt to invoke the
biostart( )
entry point as many times as is specified
by the iovcnt argument to the system call
but a scatter/gather list will not be built
for the iovec
entries.
This is a limitation of the current implementation;
the solution is to ensure that the application
does not call the
readv( )
and
writev( )
system calls for this device.
MDI drivers are a special type of STREAMS drivers. The following notes provide additional information about how scatter/gather operations are implemented for SVR5 MDI drivers.
mac_max_sdu
and mac_min_sdu
members
of the
mac_info_ack
structure, which define the packet size for the driver.
Processes that run above the DLPI's netX module obtain frame size parameters with the DL_INFO_REQ(D7dlpi) and DL_INFO_ACK(D7dlpi) primitives.
For SDI HBA drivers written for DDI versions prior to version 8 do this translation xlat(D2sdi) entry point routines.
Scatter/gather mechanisms are defined for SCO OpenServer 5 SCSI host adapters and SCO OpenServer 5 MDI network adapter drivers.
Scatter/gather operations for SCO OpenServer 5 SCSI host adapters use a scatter/gather list that is defined in the scsi_io_req(D4osdi) structure:
req_p->data_ptr
req_p->link_ptr
req_p->data_len
req_p->data_blk
In addition, the following must be set in the scsi_ha_info(D4osdi) structure:
info->do_sg
The Sram sample driver that is provided in the HDK O5hbasamp package illustrates how to implement scatter/gather operations in an SCO OpenServer 5 SCSI host adapter driver.
SCO OpenServer 5 MDI drivers use the
mdi_end_of_contig_segment(D3mdi)
function to check each block
and break it into scatter/gather segments if necessary.
The following code example is from the shrk driver that is provided in the O5ndsampl package in the HDK. Note that this driver is compiled to compile and build for both SCO OpenServer 5 and SVR5 systems, and is useful for comparing the interfaces for the two platforms.
/* streams scatter gather definitions and structures */ #define SCGTH32 0typedef struct scgth_el32 { uint_t sg_base; /* base physical address */ uint_t sg_size; /* size, in bytes, of this piece */ } scgth_el32_t;
typedef struct scgth { union { scgth_el32_t *el32; } sg_elem; unchar sg_nelem; unchar sg_format; } scgth_t;
...
bzero(&sg, sizeof(scgth_t)); sg.sg_elem.el32 = (scgth_el32_t *)kmem_zalloc(shrk_max_txbuf_per_msg * sizeof(scgth_el32_t), KM_NOSLEEP);
for (smp = mp; mp; mp = mp->b_cont ) { for (start = mp->b_rptr; start < mp->b_wptr; ) { end = mdi_end_of_contig_segment(start, mp->b_wptr - 1); sg.sg_elem.el32[sg.sg_nelem].sg_base = (uint_t) kvtophys(start); sg.sg_elem.el32[sg.sg_nelem].sg_size = end - start + 1; sg.sg_nelem, start, end); sg.sg_nelem++; start = end + 1; } }
...
kmem_free(sg.sg_elem.el32, shrk_max_txbuf_per_msg*sizeof(scgth_el32_t));
...