uphysio or uphysio_fast Kernel Service
Purpose
Performs character I/O for a block device using a uio structure.
Syntax
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/buf.h>
#include <sys/uio.h>
Parameters
The following table includes the parameters for uphysio and uphysio_fast:
Item | Description |
---|---|
uiop | Points to the uio structure describing the buffer of data to transfer using character-to-block I/O. |
rw | Indicates either a read or write operation. A value of B_READ for this flag indicates a read operation. A value of B_WRITE for this flag indicates a write operation. |
buf_cnt | Specifies the maximum number of buf structures to use when calling the strategy routine specified by the strat parameter. This parameter is used to indicate the maximum amount of concurrency the device can support and minimize the I/O redrive time. The value of the buf_cnt parameter can range from 1 to 64. |
devno | Specifies the major and minor device numbers. With the uphysio service, this parameter specifies the device number to be placed in the buf structure before calling the strategy routine specified by the strat parameter. |
strat | Represents the function pointer to the ddstrategy routine for the device. |
mincnt | Represents the function pointer to a routine used to reduce the data transfer size specified in the buf structure, as required by the device before the strategy routine is started. The routine can also be used to update extended parameter information in the buf structure before the information is passed to the strategy routine. |
minparms | Points to parameters to be used by the mincnt parameter. |
max_xfer | Specifies the maximum transfer size for the device in bytes. |
options | Specifies the value to store in b_options field of buffer headers. |
blk_align | Optional parameter to enforce a minimum block alignment on all transfers sent to the specified I/O strategy routine. This value is specified in bytes. When a non-zero value is specified, each I/O vector will be checked to ensure it is a multiple of this value. The transfer request will fail if not on an alignment boundary. When a block alignment is specified, it is assumed that the maximum transfer size, specified by the max_xfer parameter, is block aligned. |
Description
The uphysio or uphysio_fast kernel service performs character I/O for a block device. The uphysio or uphysio_fast service attempts to send to the specified strategy routine the number of buf headers specified by the buf_cnt parameter. These buf structures are constructed with data from the uio structure specified by the uiop parameter.
The uphysio or uphysio_fast service initially transfers data area descriptions from each iovec element found in the uio structure into individual buf headers. These headers are later sent to the strategy routine. The uphysio or uphysio_fast kernel service tries to process as many data areas as the number of buf headers permits. It then invokes the strategy routine with the list of buf headers.
The uphysio_fast service uses the specified maximum transfer size to tailor the length of data transfers and avoids the context switch overhead encountered with the mincnt routine that is required by the uphysio service. In environments where the maximum transfer size is already known by the caller and the buffer header fields do not need to be updated, this service should be used to reduce I/O pathlength.
Preparing Individual buf Headers
The routine specified by the mincnt parameter is called before the buf header, built from an iovec element, is added to the list of buf headers to be sent to the strategy routine. The mincnt parameter is passed a pointer to the buf header along with the minparms pointer. This arrangement allows the mincnt parameter to tailor the length of the data transfer described by the buf header as required by the device performing the I/O. The mincnt parameter can also optionally modify certain device-dependent fields in the buf header.
When the mincnt parameter returns with no error, an attempt is made to pin the data buffer described by the buf header. If the pin operation fails due to insufficient memory, the data area described by the buf header is reduced by half. The buf header is again passed to the mincnt parameter for modification before trying to pin the reduced data area.
This process of downsizing the transfer specified by the buf header is repeated until one of the three following conditions occurs:
- The pin operation succeeds.
- The mincnt parameter indicates an error.
- The data area size is reduced to 0.
When insufficient memory indicates a failed pin operation, the number of buf headers used for the remainder of the operation is reduced to 1. This is because trying to pin multiple data areas simultaneously under these conditions is not desirable.
If the user has not already obtained cross-memory descriptors, further processing is required. (The uio_segflg field in the uio structure indicates whether the user has already initialized the cross-memory descriptors. The usr/include/sys/uio.h file contains information on possible values for this flag.)
When the data area described by the buf header has been successfully pinned, the uphysio or uphysio_fast service verifies user access authority for the data area. It also obtains a cross-memory descriptor to allow the device driver interrupt handler limited access to the data area.
Calling the Strategy Routine
After the uphysio or uphysio_fast kernel service obtains a cross-memory descriptor to allow the device driver interrupt handler limited access to the data area, the buf header is then put on a list of buf headers to be sent to the strategy routine specified by the strat parameter.
The strategy routine specified by the strat parameter is called with the list of buf headers when:
- The list reaches the number of buf structures specified by the buf_cnt parameter.
- The data area described by the uio structure has been completely described by buf headers.
The buf headers in the list are chained together using the av_back and av_forw fields before they are sent to the strategy routine.
Waiting for buf Header Completion
When all available buf headers have been sent to the strategy routine, the uphysio or uphysio_fast service waits for one or more of the buf headers to be marked complete. The IODONE handler is used to wake up the uphysio or uphysio_fast service when it is waiting for completed buf headers from the strategy routine.
When the uphysio or uphysio_fast service is notified of a completed buf header, the associated data buffer is unpinned and the cross-memory descriptor is freed. (However, the cross-memory descriptor is freed only if the user had not already obtained it.) An error is detected on the data transfer under the following conditions:
- The completed buf header has a nonzero b_resid field.
- The b_flags field has the B_ERROR flag set.
When an error is detected by the uphysio or uphysio_fast service, no new buf headers are sent to the strategy routine.
The uphysio or uphysio_fast service waits for any buf headers already sent to the strategy routine to be completed and then returns an error code to the caller. If no errors are detected, the buf header and any other completed buf headers are again used to send more data transfer requests to the strategy routine as they become available. This process continues until all data described in the uio structure has been transferred or until an error has been detected.
The uphysio or uphysio_fast service returns to the caller when:
- All buf headers have been marked complete by the strategy routine.
- All data specified by the uio structure has been transferred.
The uphysio or uphysio_fast service also returns an error code to the caller if an error is detected.
Error Detection by the uphysio or uphysio_fast Kernel Service
When it detects an error, the uphysio or uphysio_fast kernel service reports the error that was detected closest to the start of the data area described by the uio structure. No additional buf headers are sent to the strategy routine. The uphysio or uphysio_fast kernel service waits for all buf headers sent to the strategy routine to be marked complete.
However, additional buf headers may have been sent to the strategy routine between these two events:
- After the strategy routine detects the error.
- Before the uphysio or uphysio_fast service is notified of the error condition in the completed buf header.
When errors occur, various fields in the returned uio structure may or may not reflect the error. The uio_iov and uio_iovcnt fields are not updated and contain their original values.
The uio_resid and uio_offset fields in the returned uio structure indicate the number of bytes transferred by the strategy routine according to the sum of all (the b_bcount field minus the b_resid fields) fields in the buf headers processed by the strategy routine. These headers include the buf header indicating the error nearest the start of the data area described by the original uio structure. Any data counts in buf headers completed after the detection of the error are not reflected in the returned uio structure.
Execution Environment
The uphysio or uphysio_fast kernel service can be called from the process environment only.
Return Values
Item | Description |
---|---|
0 | Indicates successful completion. |
ENOMEM | Indicates that no memory is available for the required buf headers. |
EAGAIN | Indicates that the operation fails due to a temporary insufficient resource condition. |
EFAULT | Indicates that the uio_segflg field indicated user space and that the user does not have authority to access the buffer. |
EIO or the b_error field in a buf header | Indicates an I/O error in a buf header processed by the strategy routine. |
Return code from the mincnt parameter | Indicates that the return code from the mincnt parameter if the routine returned with a nonzero return code. |