uphysio 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>

int uphysio (uiop, rw, buf_cnt, devno, strat, mincnt, minparms)
struct uio * uiop;
int  rw;
uint  buf_cnt;
dev_t  devno;
int (* strat)( );
int (* mincnt )( );
void * minparms;

Parameters

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.

Description

The uphysio kernel service performs character I/O for a block device. The uphysio 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 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 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.

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:

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 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 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 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 service waits for one or more of the buf headers to be marked complete. The IODONE handler is used to wake up the uphysio service when it is waiting for completed buf headers from the strategy routine.

When the uphysio 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:

When an error is detected by the uphysio service, no new buf headers are sent to the strategy routine.

The uphysio 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 service returns to the caller when:

The uphysio service also returns an error code to the caller if an error is detected.

Error Detection by the uphysio Kernel Service

When it detects an error, the uphysio 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 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:

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 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.