Museum

Home

Lab Overview

Retrotechnology Articles

⇒ Online Manual

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

adapter_driver(3K)

adapter_manager(3K)

device_interrupts(3K)

device_nodes(3K)

event_counters(3K)

fs_check_self_id(3K)

io_buffer_vector(3K)

io_select(3K)

memory_allocation(3K)

sc_panic(3K)

server_messages(3K)

status_code_macros(3K)

system_clock(3K)



device_driver(3K)              DG/UX R4.11MU05             device_driver(3K)


NAME
       device_driver: dev_xxx_init, dev_xxx_configure, dev_xxx_deconfigure,
       dev_xxx_device_to_name, dev_xxx_name_to_device, dev_xxx_open,
       dev_xxx_close, dev_xxx_service_interrupt, dev_xxx_read_write,
       dev_xxx_start_io, dev_xxx_select, dev_xxx_ioctl, dev_xxx_open_dump,
       dev_xxx_write_dump, dev_xxx_read_dump, dev_xxx_close_dump,
       dev_xxx_maddmap, dev_xxx_mmap, dev_xxx_munmap, dev_xxx_powerfail -
       implement a device driver

SYNOPSIS
       #include "/usr/src/uts/aviion/ii/i_io.h"

       status_type     dev_xxx_close (
       io_device_handle_type         device_handle,    READ_ONLY
       io_channel_flags_type         channel_flags     READ_ONLY )

       status_type     dev_xxx_close_dump (
       io_device_handle_type         device_handle     READ_ONLY )

       status_type     dev_xxx_configure (
       char_ptr_type                 device_name_ptr,  READ_ONLY
       io_major_device_number_type   major_number      READ_ONLY )

       status_type     dev_xxx_deconfigure (
       char_ptr_type                 device_name_ptr   READ_ONLY )

       status_type     dev_xxx_device_to_name (
       io_device_number_type         device_number,    READ_ONLY
       char_ptr_type                 name_ptr,         WRITE_ONLY
       uint32_type                   size              READ_ONLY )

       void            dev_xxx_init ()

       status_type     dev_xxx_ioctl (
       io_device_handle_type         device_handle,    READ_ONLY
       bit32e_type                   command,          READ_ONLY
       bit32e_type                   parameter,        READ_WRITE
       int32e_ptr_type               return_value_ptr  WRITE_ONLY )

       void            dev_xxx_maddmap (
       io_device_handle_type         device_handle,    READ_ONLY
       opaque_ptr_type               file_id,          READ_ONLY
       int32_type                    mmap_count_delta  READ_ONLY )

       status_type     dev_xxx_mmap (
       io_device_handle_type         device_handle,    READ_ONLY
       opaque_ptr_type               file_id,          READ_ONLY
       io_mmap_request_ptr_type      request_ptr,      READ_ONLY
       io_channel_flags_type         io_flags,         READ_ONLY
       byte_address_ptr_type         start_address_ptr WRITE_ONLY )

       status_type     dev_xxx_munmap (
       io_device_handle_type         device_handle,    READ_ONLY
       opaque_ptr_type               file_id,          READ_ONLY
       io_mmap_request_ptr_type      request_ptr,      READ_ONLY
       byte_address_type             start_phys_addr   READ_ONLY )

       status_type     dev_xxx_name_to_device (
       char_ptr_type                 device_name_ptr,  READ_ONLY
       io_device_number_ptr_type     number_ptr        WRITE_ONLY )

       status_type     dev_xxx_open (
       io_device_number_type         device_number,    READ_ONLY
       io_channel_flags_type         channel_flags,    READ_ONLY
       io_device_handle_ptr_type     device_handle_ptr WRITE_ONLY )

       status_type     dev_xxx_open_dump (
       char_ptr_type                 device_name,      READ_ONLY
       io_device_handle_ptr_type     device_handle_ptr READ_ONLY )

       status_type     dev_xxx_powerfail ()

       status_type     dev_xxx_read_dump (
       io_dump_request_info_ptr_type dump_rb_ptr       READ_ONLY )

       status_type     dev_xxx_read_write (
       io_request_info_ptr_type      request_info_ptr  READ_ONLY )

       void            dev_xxx_select (
       io_device_handle_type         device_handle,    READ_ONLY
       boolean_type                  select_mode,      READ_ONLY
       vp_ec_ptr_type                ec_ptr,           READ_ONLY
       io_select_intent_ptr_type     intent_ptr        READ_WRITE )

       void            dev_xxx_service_interrupt (
       dev_xxx_device_info_ptr_type  device_info_ptr   READ_ONLY )

       status_type     dev_xxx_start_io (
       io_operation_record_ptr_type  op_record_ptr     READ_ONLY )

       status_type     dev_xxx_write_dump (
       io_dump_request_info_ptr_type dump_rb_ptr       READ_ONLY )

       void        kernel_complete_io (
       io_operation_record_ptr_type  op_record_ptr,    READ_ONLY
       status_type                   status            READ_ONLY )

   where:
       channel_flags     Flags indicating how the device was or will be
                         opened (read, write, or read/write) and whether the
                         open is for block or character special operation.
                         These flags are listed below under Constants and
                         Data Structures, io_channel_flags_type.  (See also
                         i_io.h for a listing of the channel flags.)  The
                         driver does not need to validate this argument.
       command           A command to the device.  The driver must validate
                         the command because commands are driver-specific.
       device_handle     The device handle that was returned by the driver's
                         dev_xxx_open routine.  The driver does not need to
                         validate this argument.
       device_handle_ptr A pointer to the location where the device handle
                         is to be returned.  If the routine does not return
                         an OK status, this value is undefined.  The driver
                         does not need to validate this pointer.
       device_info_ptr   A pointer to the device information structure for
                         the interrupting device.  A pointer to the
                         dev_xxx_service_interrupt routine is the first
                         field in this structure.  The driver does not need
                         to validate this pointer.
       device_name       A pointer to the null-terminated string identifying
                         the device to be opened as a dump device.
       device_name_ptr   A pointer to a null-terminated string specifying
                         the name of the device to be configured,
                         deconfigured, or translated.
       device_number     The major and minor device numbers of a particular
                         device.
       dump_rb_ptr       A pointer to the dump request information
                         structure.  This structure contains the
                         io_buffer_vector, the device_handle, the
                         device_offset, and the device_offset_extender
                         fields.  The device_handle field is returned from
                         the dev_xxx_open_dump routine.
       ec_ptr            A pointer to the eventcounter to be advanced by the
                         driver when the particular type of select is
                         satisfied.  The driver does not need to validate
                         this pointer.
       file_id           A file identifier associated with the character
                         special file that was initially opened to gain
                         access to the device.
       intent_ptr        A pointer to an intent variable consisting of a set
                         of intent flags.  The kernel calls the driver with
                         the intent flags showing whether the device is
                         being selected for read, write, or exceptional
                         conditions or any combination of these.  When the
                         driver returns, it sets the intent flags to show
                         which input conditions are currently TRUE.  The
                         driver does not need to validate this argument.
                         The possible intent flags are described under
                         Constants and Data Structures below.
       io_flags          The channel flags for the descriptor passed to
                         mmap(2).
       major_number      The major number of the device to be configured.
       mmap_count_delta  The amount to increment or decrement the mmap use
                         count for the device.
       name_ptr          A pointer to the location where the device name is
                         to be written as a null-terminated string.
       number_ptr        A pointer to where the corresponding device number
                         is to be written.  The device number consists of a
                         major and minor device number.
       op_record_ptr     A pointer to the operation record for an
                         asynchronous request.  The operation record
                         contains the following fields:
                         ·  The device handle that is the target of the
                            operation.
                         ·  The operation to be performed; for example,
                            read, write, or both.
                         ·  The offset indicating where the read/write
                            operation should begin.  The offset is a file
                            pointer maintained by the kernel.  For example,
                            on a disk the offset might indicate where to
                            start reading after the start of the sector.
                            The interpretation of the offset is driver-
                            dependent.
                         ·  The address of the kernel's I/O completion
                            routine that is to be called by the driver's
                            complete_io routine when the operation
                            completes.  The Kernel I/O completion routine
                            follows the interface shown under
                            kernel_complete_io below.  Note that you pass
                            the op_record and a completion status back as
                            parameters to the kernel_complete_io routine.
                         ·  An io_buffer_vector structure that holds the
                            transfer size and the address of the memory
                            buffers.
       parameter         An argument to the command.  The interpretation of
                         the parameter is specific to the driver and the
                         command.  The parameter is often used to transfer
                         information between the caller and the device, in
                         both direction.  For example one might use it to
                         send a pointer to a buffer supplied by the caller.
       request_info_ptr  A pointer to a request information structure.
       request_ptr       Information indicating which memory is to be memory
                         mapped (and in what mode) or unmapped.  The members
                         of this structure correspond directly to mmap(2)
                         arguments as follows:
                            Member name             mmap Argument
                            start_address           addr
                            file_offset_extender    set to 0 by mmap()
                            file_offset             off
                            byte_count              len
                            protection_flags        prot
                            control_flags           flags
       request_ptr       Additional information indicating which memory is
                         requested to be unmapped.
       return_value_ptr  A pointer to a value that the routine defines and
                         returns.  This additional return value increases
                         the flexibility of your ioctl operation by
                         providing variations on the generic return value
                         specified in the "Return Value" subsection.
       select_mode       If select_mode is TRUE, this is the start of a
                         select operation.  If select_mode is FALSE, this is
                         the end of a select operation.
       size              The maximum number of bytes, including the
                         terminating null, that is to be written to
                         name_ptr.
       start_address_ptr Location used to return the start address in the
                         user address space of the newly mapped region.
       start_phys_addr   The physical memory address of the beginning of the
                         region to be unmapped.
       status            The completion status of the request.

DESCRIPTION
       This man page gives the detailed interface specifications for the
       following device driver routines:
       dev_xxx_init              Perform pre-configuration initialization
       dev_xxx_configure         Configure a device
       dev_xxx_deconfigure       Deconfigure a device
       dev_xxx_device_to_name    Return name associated with device number
       dev_xxx_name_to_device    Return device number for device name
       dev_xxx_open              Open a device
       dev_xxx_close             Close a device
       dev_xxx_service_interrupt Handle device interrupts
       dev_xxx_read_write        Synchronously read from or write to device
       dev_xxx_start_io          Start asynchronous I/O operation
       kernel_complete_io        Clean up after asynchronous I/O operation
       dev_xxx_select            Check whether device ready for I/O
       dev_xxx_ioctl             Performs control operation on device
       dev_xxx_open_dump         Open a dump device
       dev_xxx_write_dump        Write system dump data to dump destination
       dev_xxx_read_dump         Read a system dump device
       dev_xxx_close_dump        Close a dump device
       dev_xxx_maddmap           Modify device memory map reference count
       dev_xxx_mmap              Implement the mmap system call
       dev_xxx_munmap            Determine whether to unmap memory
       dev_xxx_powerfail*        Restart devices after power failure
       __________
       *Not currently supported

       Each routine specification includes a "Return Value" subsection that
       lists specific return values that the kernel can process when the
       routine returns.  When no return value is specified, the routine must
       not fail (the kernel will not process any returns or exceptions).  If
       the driver routine experiences an exception other than those
       specified in the "Return Value" subsection, it can proceed in one of
       the following three ways:

         1.   It can return an exception by returning a value other than one
              of the specified values.  The kernel will filter this value
              back to the user as a standard errno.  You can either define
              your own values for this errno or use values already defined
              by the system.  Check /usr/include/sys/errno.h for a listing
              of the existing errnos and their definitions.

         2.   It can use the error server to log an error.

         3.   It can halt the system.  Some driver routines are not allowed
              to halt.  The "Return Value" subsection of the interface
              description indicates whether or not a routine can halt.

       The status_code_macros(3K) man page describes how to define an error
       status and how to log an error to the error server.  The sc_panic(3K)
       man page describes how to use the routine that halts the system.

   Constants and Data Structures
       This subsection describes constants and data structures defined in
       the include files cited in the SYNOPSIS section and used by the
       routines documented in this man page.

       Try to avoid dependencies on the specifics of these structures, such
       as size or location of fields, because these specifics may change in
       later releases of the software.  You can verify exact variable
       definitions in the appropriate include file.  The best way to avoid
       such dependencies is to use kernel-supplied routines to manipulate
       these structures.

       io_driver_routines_vector_type
              typedef struct
                  {
                  uint16_type         version;
                  bit16_type          flags;
                  status_type         (*open)();
                  void                (*close)();
                  status_type         (*read_write)();
                  void                (*select)();
                  status_type         (*ioctl)();
                  status_type         (*start_io)();
                  void                (*init)();
                  status_type         (*configure)();
                  status_type         (*deconfigure)();
                  status_type         (*device_to_name)();
                  status_type         (*name_to_device)();
                  status_type         (*open_dump)();
                  status_type         (*write_dump)();
                  status_type         (*read_dump)();
                  status_type         (*close_dump)();
                  status_type         (*powerfail)();
                  status_type         (*mmap)();
                  status_type         (*munmap)();
                  status_type         (*maddmap)();
                  }  io_driver_routines_vector_type ;

       The kernel must have a pointer to each of your routines that it
       calls.  You provide a vector of pointers to your driver's routines in
       a routines vector of io_driver_routines_vector_type.  You must
       allocate a variable of this type for your driver in
       dev_xxx_global_data.c.

       The structure contains a version field that the kernel uses to
       support compatibility with device drivers if the routines vector
       changes between releases.  This field is also used to flag the
       difference between a device driver and an adapter driver.  Adapter
       drivers have two routines vectors, one of io_routines_vector_type
       type and one of dev_scsi_adapter_routines_vector_type type.  The
       version field is used to signal the kernel that the driver is an
       adapter driver and has another routines vector.

       If the driver was written prior to release 5.4.2, you should set the
       version field to one (1) for device drivers and to
       IO_DRIVER_ROUTINES_VECTOR_SCSI_ADAPTER_VERSION for adapter drivers.
       For drivers using the new wire/unwire memory calls for release 5.4.2
       [see the io_buffer_vector(3K) and memory_allocation(3K) man pages],
       the version field should be IO_DRIVER_ROUTINES_VECTOR_VERSION_2 for
       device drivers and IO_DRIVER_ROUTINES_VECTOR_SCSI_ADAPTER_VERSION_2
       for adapter drivers.

       io_device_number_type
              typedef struct
                  {
                  io_major_device_number_type         major;
                  io_minor_device_number_type         minor;
                  }  io_device_number_type ;

       A device number is a composite of the device's major and minor device
       numbers.  During configuration, the kernel calls your
       dev_xxx_configure routine with the device's major number.  Your
       dev_xxx_configure routine gets the device's minor number and creates
       the device number variable for the unit by calling the kernel's
       io_allocate_device_number routine.  dev_xxx_configure then uses the
       device number to create the special file (node) for the specific
       units.  After dev_xxx_configure creates the device number, the kernel
       uses it as an device identifier when calling your dev_xxx_open
       routine.  dev_xxx_open returns a file descriptor that the kernel uses
       to identify the unit to the user and a device handle that the kernel
       uses to identify the unit to other driver routines.

       io_device_handle_type
              typedef opaque32_type    io_device_handle_type ;

       A device handle identifies an open device to other calls to the
       device driver.  Your dev_xxx_open routine defines and returns the
       device handle when the device is opened.  The device handle becomes
       invalid when the device is closed.

       The kernel does not interpret the device handle.  Thus, you are free
       to define the device handle as you want.  A common strategy is to use
       a pointer to the unit-specific portion of the device information
       structure as the device handle.

       io_request_info_type
              typedef struct
                  {
                  io_operation_type                   op;
                  io_channel_flags_type               flags;
                  io_device_handle_type               device_handle;
                  uint32_type                         device_offset_extender;
                  uint32_type                         device_offset;
                  io_buffer_vector_type               buffer_vector;
                  df_self_id_type                     self_id;
                  }  io_request_info_type;

       The kernel uses a variable of this type to supply information to your
       driver's routines about an I/O request made to your driver.  The
       request information package groups several related I/O request
       parameters.  The request information package fields are as follows:
       op     This field indicates the requested operation.  See
              io_operation_type for a list of the operation types.  The op
              request is modified by the flags field below.
       flags  This field holds an additional set of flags that modifies the
              operation indicated by the op field.  See
              io_channel_flags_type described later in this subsection for a
              list of the flags.
       device_handle
              This field holds the device handle of the device to which the
              request is to be directed.  It must be the device handle
              returned by the driver's open routine.
       device_offset_extender
              This field exists for device offsets needing more than 32
              bits.  This field should be zero if the request does not use
              large offsets (for example, nondisk devices).  Disk drivers
              should check this field.  If your disk does not support
              offsets needing the extender, you should reject requests where
              this offset is non-zero.
       device_offset
              This field holds the offset in bytes on the device where the
              transfer is to begin.  The interpretation of this field is
              defined by the driver to which the request is directed.
       buffer_vector
              This field holds a buffer vector describing the main memory
              area that is to be used in the I/O operation.  The addresses
              may be logical or physical depending upon the operation
              specified in the op field.
       self_id
              The home system identification against which read data is to
              be checked if the IO_CHECK_SELF_ID flag is TRUE.

       io_operation_type
              typedef bit16_type              io_operation_type ;
              #define IO_OPERATION_READ
              #define IO_OPERATION_WRITE
              #define IO_OPERATION_CHECK_SELF_ID
              #define IO_OPERATION_PHYSICAL_BUFFER
              #define IO_OPERATION_USER_BUFFER

       This type defines a bit field used to modify the I/O operation
       specified in the op field of io_request_info_type.  The READ or WRITE
       bits are exclusive, only one can be on at a time.  The
       PHYSICAL_BUFFER flag indicates that the buffer address supplied with
       the operation is a physical memory address not a logical memory
       address.  The USER_BUFFER flag indicates that the buffer address
       supplied with the operation is a user memory address rather than a
       kernel memory address.  The PHYSICAL_BUFFER flag and the USER_BUFFER
       flag may be present only on a READ or WRITE.  The CHECK_SELF_ID flag
       may be present only on a READ operation.

       io_channel_flags_type
              typedef bit32_type      io_channel_flags_type ;
              #define   IO_CHANNEL_NO_FLAGS
              #define   IO_CHANNEL_READ_INTENT
              #define   IO_CHANNEL_WRITE_INTENT
              #define   IO_CHANNEL_EXCLUDE_WRITERS_INTENT
              #define   IO_CHANNEL_APPEND_INTENT
              #define   IO_CHANNEL_SYNC_IO
              #define   IO_CHANNEL_NO_WAIT
              #define   IO_CHANNEL_ASYNC_IO
              #define   IO_CHANNEL_NONBLOCK
              #define   IO_CHANNEL_NDELAY
              #define   IO_CHANNEL_BLOCK_SPECIAL
              #define   IO_CHANNEL_NO_RETRIES
              #define   IO_CHANNEL_NOTIFY_IF_MANDATORY
              #define   IO_CHANNEL_NOCTTY

       This type defines a set of literals that modify the open operation.
       The channel flags specify the open conditions that the user requested
       and are passed in the flags field of the io_request_info_type.  These
       conditions are passed to the dev_xxx_open routine.  See dev_xxx_open
       for more information about the conditions.  The open options are as
       follows:

       IO_CHANNEL_NO_FLAGS
              This flag indicates that none of the conditions described
              below applies.

       IO_CHANNEL_READ_INTENT
              This flag indicates that the channel is opened with read
              intent.  This flag corresponds to the O_RDONLY or O_RDWR
              option on the open system call.

       IO_CHANNEL_WRITE_INTENT
              This flag indicates that the channel is opened with write
              intent.  This flag corresponds to the O_WRONLY or O_RDWR
              option on the open system call.

       IO_CHANNEL_EXCLUDE_WRITERS_INTENT
              This flag indicates that the channel is opened only if there
              are currently no writers, and future attempts to open with
              write intent are disallowed.  This flag is used internally by
              the file system to prevent other processes from writing to a
              disk it is managing.

       IO_CHANNEL_APPEND_INTENT
              This flag indicates that the channel is opened with append
              intent.  This flag corresponds to the O_APPEND option on the
              open system call.

       IO_CHANNEL_SYNC_IO
              This flag indicates that the channel is opened with the
              synchronous I/O option.  This flag corresponds to the O_SYNC
              option on the open system call.

       IO_CHANNEL_NO_WAIT
              This flag indicates that the channel is opened with the no-
              wait I/O option.  This flag corresponds to the O_NDELAY or to
              the O_NONBLOCK option on the open system call.

       IO_CHANNEL_ASYNC_IO
              This flag indicates that the channel is opened with the
              asynchronous I/O option.  This flag corresponds to setting the
              FASYNC option with the fcntl system call.

       IO_CHANNEL_NONBLOCK
              This flag indicates that the channel is opened with the
              O_NONBLOCK option.

       IO_CHANNEL_NDELAY
              This flag indicates that the channel is opened with the
              O_NDELAY option.  The driver should not look at this flag.

       IO_CHANNEL_BLOCK_SPECIAL
              This flag indicates that the driver is being opened as a block
              special device.  This flag is used only internally.

       IO_CHANNEL_NO_RETRIES
              This flag indicates that the I/O performed via this channel
              should not be retried if errors occur; all errors are treated
              as hard errors.  This flag may or may not be supported by a
              given device driver.

       IO_CHANNEL_NOTIFY_IF_MANDATORY
              This flag indicates that the kernel uses this option
              internally to avoid deadlock on mandatory locks.  Drivers
              should not use this option.

       IO_CHANNEL_NOCTTY
              This flag indicates that the driver is being opened with the
              O_NOCTTY open flag set.  The kernel uses this option to
              prevent the controlling terminal from being set.

       io_operation_record_type
              typedef struct
                  {
                  misc_queue_links_type               links;
                  io_request_info_type                ri;
                  io_completion_routine_ptr_type      completion_routine;
                  }  io_operation_record_type;

       You use the operation record when starting an asynchronous I/O
       request using your driver's dev_xxx_start_io function.  The structure
       is basically an extension of the io_request_info_type that you use
       for synchronous requests.  This extension supplies extra information
       needed to service the request in an asynchronous manner.  The
       operation record's fields are as follows:

       links  A pointer to a space that the driver can use to link this
              operation record into a queue with other operation records.
              The driver determines the actual use of this space.

       ri     The request information structure that specifies the request.

       completion_routine
              A pointer to the address of the function that should be called
              when the operation denoted by this operation record is
              complete.  This function must conform to the I/O completion
              routine interface described below under kernel_complete_io.

       io_select_intent_type
              typedef bit16_type  io_select_intent_type ;
                  IO_SELECT_INTENT_READ
                  IO_SELECT_INTENT_WRITE
                  IO_SELECT_INTENT_EXCEPTION
                  IO_SELECT_INTENT_POLLIN
                  IO_SELECT_INTENT_POLLPRI
                  IO_SELECT_INTENT_POLLOUT
                  IO_SELECT_INTENT_POLLERR
                  IO_SELECT_INTENT_POLLHUP
                  IO_SELECT_INTENT_POLLNVAL
                  IO_SELECT_INTENT_NONE
                  IO_SELECT_INTENT_POLLWRBAND
                  IO_SELECT_INTENT_POLLRDBAND
                  IO_SELECT_INTENT_POLLRDNORM

       This type describes the select options that may be specified to a
       device driver's dev_xxx_select routine.  The READ, WRITE, and
       EXCEPTION options start a select for the corresponding operation.
       Any combination of these three options may be sent in a single
       dev_xxx_select call.  IO_SELECT_INTENT_NONE is used as a return value
       from io_select_cancel when no intent has been satisfied.

       io_buffer_vector_type
              typedef struct
                  {
                  union
                  {
                  io_buffer_vector_control_type    many;
                  io_buffer_descriptor_type        one;
                  } u;
                  uint16_type                      descriptor_count;
                  uint16_type                      current_descriptor;
                  uint32_type                      current_offset;
                  uint32_type                      total_remaining;
                  }  io_buffer_vector_type ;

       This structure defines a buffer vector, which is a collection of
       individual buffer descriptors plus an associated state.  A buffer
       vector may be the source or destination of a single read or write
       operation; the individual buffer descriptors define the locations
       from which the data is being read or into which the data is being
       written.

       The current position indicates where the next byte of data will be
       read from or written to.  The current position is initialized to the
       first byte of the first buffer descriptor.  The current position
       within the buffer vector is maintained by the associated state.

       The fields in this structure are as follows:

       many   This field contains a pointer to the array of buffer
              descriptors and the total of the sizes of all the elements of
              the array.  This field is used only when descriptor_count is
              non-zero.  See also io_buffer_vector_control_type later in
              this subsection.

       one    This field contains the single buffer descriptor when the
              buffer vector consists of a single descriptor.  This field is
              used only when descriptor_count is zero.  See also
              io_buffer_descriptor_type later in this subsection.

       descriptor_count
              This field indicates the number of entries in the many array
              of the io_buffer_vector_control_type and is used to determine
              the actual amount of memory allocated to the array.  If this
              field is zero, then there is no memory allocated to the array
              and a single descriptor is stored in the one field.  The
              total_size field of io_buffer_vector_control_type controls the
              number of entries that are actually used, which may be less
              than the amount specified by descriptor_count.

       current_descriptor
              This field contains the index of the descriptor that contains
              the current position.

       current_offset
              This field contains the offset of the current position in the
              buffer descriptor indexed by current_descriptor.

       total_remaining
              This field indicates the total number of bytes remaining to be
              moved to or from this buffer vector since it was initialized.

       io_buffer_descriptor_type
              typedef struct
                  {
                  pointer_to_any_type  buffer_ptr;
                  uint32_type          size;
                  }  io_buffer_descriptor_type ;

       This structure describes the buffer from which data is to be read or
       to which data is to be written.  The fields in this structure are as
       follows:

       buffer_ptr  A pointer to the start of the buffer.

       size        The size of the buffer, in bytes.

       io_buffer_vector_control_type
              typedef struct
                  {
                  io_buffer_descriptor_ptr_type     descriptors_ptr;
                  uint32_type                       total_size;
                  }  io_buffer_vector_control_type;

       This structure is used in the many field of io_buffer_vector_type.
       The fields in this structure are as follows:

       descriptors_ptr
              A pointer to an array of buffer descriptors.  The array may
              contain as many as UINT16_MAX entries.  (For the definition of
              UINT16_MAX, see /usr/src/uts/aviion/ext/c_generics.h.)

       total_size
              The sum of the size fields in all the elements of the array
              buffer descriptors.

DEVICE DRIVER ROUTINE DESCRIPTIONS
   dev_xxx_close
       This routine removes a specified device from the set of devices on
       which this driver can perform I/O.  You should invoke one
       dev_xxx_close for each successful dev_xxx_open.  dev_xxx_close should
       always get the same intents supplied to the open and the same device
       handle returned by the open.  However, if a device is opened multiple
       times, it will not necessarily be closed in the same or reverse order
       of the opens.

       Typically, dev_xxx_close performs any necessary exit operations such
       as flushing any buffers that may be present and releasing previously
       allocated storage.  Some devices will also have special exit
       requirements.  For example, a tape close would probably rewind the
       tape.  Most drivers also use dev_xxx_close in coordination with
       dev_xxx_open to manage the number of outstanding opens.

   dev_xxx_close_dump
       The routine closes the dump device previously opened by
       dev_xxx_open_dump.

       The dev_xxx_close_dump routine is called by the system dump code when
       all of the data has been written to the dump destination.
       dev_xxx_close_dump should perform all the standard exit operations
       (for example, write End-of-file or rewind the tape).  In particular,
       it should close the completed volume and inform the operator that the
       dump has completed.

   dev_xxx_configure
       This routine configures a single device of the type supported by this
       driver.

       The routine performs operations that make a physical device of the
       driver's type supported accessible to the system.  The
       dev_xxx_configure routine can be called anytime.  If your device has
       system and master file entries, it will be called by system
       initialization code during system boot.  It is called once for each
       system file entry in the system.

       The dev_xxx_configure routine receives a device_name_ptr variable
       that points to a device name.  The name string is terminated by a
       null character and has the following form:
              device_mnemonic [@device_code]([parameters])

       Because each dev_xxx_configure is called for all system file entries,
       your dev_xxx_configure should verify that the name string for the
       current call contains its device's name.  If the name is not for one
       of its devices, dev_xxx_configure should exit with a return value of
       IO_ENXIO_DEVICE_NAME_NOT_RECOGNIZED.

       dev_xxx_configure must initialize the device and must make the device
       accessible to the kernel.  Device initialization is unique to the
       device and to the driver.  The dev_xxx_configure routine should
       perform the following functions:

       ·    Allocate a device information structure.  The driver uses the
            device information structure to hold information relating to a
            specific device (status, permissions, and so on).  While the
            driver can define most of this structure's internal specifics,
            the structure must contain a pointer to the driver's interrupt
            service routine (if it has one) in the first field.  In
            addition, if you want to use the kernel's routines for managing
            a select list [see the io_select(3K) man page], you should
            allocate a select list header in the device information
            structure.  The select list header type is defined in i_io.h.
            You will also have to initialize this list by calling the
            kernel's io_init_select routine.

       ·    Register the device information structure.  If the device
            handles interrupts, you must register the device information
            structure using the io_register_device_info routine.
            Registering the device information links the device code and
            device class of the driver with the interrupt service routine
            given in the device information structure.

       ·    Define a device handle and device number.  You do this by
            calling io_allocate_device_number.  io_allocate_device_number
            allocates a minor number for the device specified and links the
            device number and device handle in the kernel's internal tables.
            Later you can retrieve this information by using kernel routines
            for accessing device information (see the device_interrupts(3K)
            man page).  The kernel will pass the device number to your
            driver's dev_xxx_open routine, but thereafter it will identify a
            device to all driver routines by passing the device handle.  If
            the device has a controller with accessible units, you should
            establish a device number and device handle for all units that
            users will access.

       ·    Create device node special files.  As with device numbers, you
            should create device node special files for all the units that
            users will access.  We recommend that you create the special
            files after registering your device information structure,
            because it is possible for the register operation to fail.  The
            device_nodes(3K) man page describes kernel routines that create
            device node special files.

       If the device has a controller, the driver usually performs any
       initialization needed to bring the controller on-line in
       dev_xxx_configure.  The driver can then initialize the controller's
       units at open time.

       If a failure occurs in any phase of the operation, dev_xxx_configure
       must return the system to the state it was in before the
       dev_xxx_configure routine was called.  Data structures must be
       deallocated and the device interrupt table slot freed.

       You should write your dev_xxx_configure routine such that it can be
       called any time during the life of the system.

   dev_xxx_deconfigure
       This routine deconfigures the specified device if it is of the device
       type supported by this driver.

       The dev_xxx_deconfigure routine does the opposite of the configure
       routine (see dev_xxx_configure).  It releases all system resources
       obtained to configure the device.  After dev_xxx_deconfigure has
       completed, the system should be in the state it was in before the
       device configure routine was executed.  dev_xxx_deconfigure performs
       the following functions:

       ·    Deallocates a device information structure

       ·    Frees the minor number

       ·    Deregisters device information and removes the device from the
            system dump list

       ·    Releases all memory

       ·    Releases Generic and I/O Server messages and timeout space, [see
            io_unspecify_max_demon_messages(3K),
            io_unspecify_max_generic_demon_messages(3K), and
            vp_unspecify_max_timeouts(3K)].

       ·    Removes /dev entries.

       dev_xxx_deconfigure receives a pointer to a device specification of
       the following form:
              device_mnemonic [@device_code]([parameters])

       The pointer is terminated by a null character.

   dev_xxx_device_to_name
       This routine returns the device name associated with the specified
       device number.  The name is returned as a null-terminated string.

       The dev_xxx_device_to_name routine is called by various file system
       utilities to translate a device number into a device name.  It
       returns the name in a string of the following form:
              device_mnemonic [@device_code]([parameters])

       If an earlier driver routine (for example, the configuration routine)
       stored the device code and unit number in its unit tables, the
       dev_xxx_device_to_name may call the kernel's io_map_device_number to
       retrieve the device code and unit number for the given device number.

   dev_xxx_init
       This routine performs any pre-configuration initialization your
       driver might need.  It should not initialize the hardware device
       itself, however.

       The kernel calls the dev_xxx_init routine as part of system
       initialization.  dev_xxx_init gives the driver an opportunity to
       perform any initialization needed before any of the driver's devices
       are configured into the system.  dev_xxx_init is invoked once in the
       life of the system.  No devices controlled by the driver will be
       configured until after the dev_xxx_init routine completes.

       The dev_xxx_init routine operates in a restricted environment.  It
       may not await or take a page fault.

   dev_xxx_ioctl
       This routine performs a control operation on the specified device.

       The dev_xxx_ioctl routine performs an ioctl control operation on the
       specified device based on the values of command and parameter.  It is
       invoked in response to a user or kernel ioctl call for one of the
       driver's devices.  However, not all user ioctl calls go to
       dev_xxx_ioctl.  Some ioctl calls are actually file descriptor
       operations.  These are intercepted and handled by the kernel.  The
       FIONCLEX operation, for example, would not reach dev_xxx_ioctl.
       Multiple ioctl operations on the same or different minor devices may
       be in progress simultaneously.

       The kernel calls dev_xxx_ioctl with the command and parameter
       arguments as specified by the ioctl system call.  The kernel does not
       interpret these arguments.  Thus, you can define your driver's
       command and parameter arguments as you wish.

       Because ioctl operations are so specific to each driver, the kernel
       validates only the device handle argument.

   dev_xxx_maddmap
       This routine modifies the reference count for memory-mapped sections
       for the device.  The reference count is called the "mmap use" count.

       This routine maintains the mmap use count for the device.  The count
       indicates to the driver whether there are any outstanding memory
       mappings of the device.  If the count is positive, there are some
       mappings.  Otherwise, the count must be zero, indicating there are no
       mappings.

       This routine may assume that the device is either open or memory
       mapped at the time it is called.  That is, if the mmap count for the
       device is zero when this routine is called, then the device's open
       count and mmap_count_delta must both be positive.  Typically, you can
       maintain the mmap count and open count for a device as a single
       unsigned integer (the use count), which must be at least 32 bits in
       size and protected by the device's open lock.  dev_xxx_maddmap
       adjusts the device's use count by the (signed) amount specified by
       mmap_count_delta.  The use count must be positive prior to the call.

       If the mmap count becomes zero and the open count is already zero as
       a result of this call, then dev_xxx_maddmap should perform the
       actions associated with the last system-wide close of the device (for
       example, freeing resources).  This means that the driver's close
       routine must not perform the last close actions for a device unless
       both the open count and mmap count are zero.  If the use count
       becomes zero, then dev_xxx_maddmap must perform the last close
       actions for the device.

   dev_xxx_mmap
       This routine implements the mmap system call.  It maps a physical
       address region controlled by the xxx character special device into
       the user address space.

       This routine validates and translates the caller's mmap request based
       on the mapping of device offsets to physical address regions defined
       by device_handle, request_ptr, and io_flags.  If the request is valid
       and all required resources are available, then dev_xxx_mmap maps the
       appropriate physical address region controlled by the device into
       user memory at the address returned in start_address_ptr.

       The required steps are as follows:

         1.   Verify that the device offset range corresponds to a range of
              physical addresses controlled by the device and is safely
              accessible by the caller.  The device offset range is defined
              by the file_offset_extender, file_offset, and byte_count
              fields of request_ptr.  If the range is not valid, return
              IO_ENXIO_ILLEGAL_DEVICE_ADDRESS.

       NOTE:  file_offset_extender denotes the high 32 bits of the 64-bit
              device offset.  A driver that supports only 32-bit offsets
              should return an error if file_offset_extender is non-zero.

         2.   Translate the beginning of the request's device offset range
              to its corresponding physical address.

         3.   Compute the maximum access to the physical memory that the
              mapping should allow.  Generally, you should allow read and
              execute access to the memory if the caller's channel flags
              indicate that the device is open for reading.  Similarly, you
              should allow write access to the memory if the device is open
              for writing.

         4.   Determine the appropriate memory cache control for the mapped
              memory.  Most memory mapped devices require caching to be
              disabled.

       After successfully completing these steps,  dev_xxx_mmap calls
       vm_mmap_physical_memory to complete the request and returns the
       status from vm_mmap_physical_memory's to the caller.  To prevent
       deadlock, avoid holding any locks when calling
       vm_mmap_physical_memory as vm_mmap_physical_memory calls the driver's
       maddmap routine one or more times.

   dev_xxx_munmap
       This routine determines whether to allow an unmap of a previously
       memory-mapped region of physical memory.

       This routine has no side effects beyond returning a status.
       Presently, all character special devices which support memory mapping
       must also allow subsequent unmapping on arbitrary page boundaries.
       Thus, this routine must return OK.

   dev_xxx_name_to_device
       This routine returns the device number for the specified device name.

       This routine is called by various file system utilities to translate
       a device name into the major and minor device numbers that are
       required to access the device.  The device name specified by
       device_name_ptr is of the following form:
              device_mnemonic [@device_code]([parameters])

       To simplify its processing, dev_xxx_name_to_device can call the
       kernel's io_get_device_info, which returns a pointer to the device
       information structure that will contain the device's device number.

       The driver should verify that the device mnemonic given in the name
       matches its own mnemonic (xxx).

   dev_xxx_open
       This routine prepares a specified device for future I/O operations.
       It also adds the device to the set of devices on which I/O can be
       performed by this driver.

       The kernel calls the routine whenever one of the driver's devices is
       opened by a user or by the kernel.  The kernel will not call
       dev_xxx_open until both dev_xxx_init and dev_xxx_configure have
       completed.

       The DG/UX system allows multiple opens on a device, and dev_xxx_open
       should manage this feature as appropriate to its device.
       dev_xxx_open controls the number of outstanding opens.  For example,
       dev_xxx_open may impose restrictions such as requiring an exclusive
       open of a particular minor device.  To implement this, dev_xxx_open
       might return an error status if the minor device has already been
       opened but not closed.  Multiple dev_xxx_open processes may be in
       progress simultaneously on the same or different minor device
       numbers.

       The dev_xxx_open routine must also control the type of open
       requested.  The kernel passes dev_xxx_open a set of channel flags
       that specify the intents given in the higher level open call (for
       example, read, write or both).  dev_xxx_open may reject the open
       because of conflicts between the current open intent and open intents
       that have already taken place or because of conflicts with the
       device's capabilities.  For example, a write intent on a read-only
       device must fail.

       dev_xxx_open typically performs other operations to prepare the
       device and ensure that it is ready for I/O.  For example, it may
       allocate storage for and initialize databases to hold information
       describing the I/O operation on the specific unit.  If the device is
       a real hardware device, dev_xxx_open may query the device to verify
       that it is on-line and ready for the type of I/O specified in the
       open intent.  For example, it may check that there is a write ring in
       the tape if write intent is specified.

       dev_xxx_open must establish the device handle that the kernel will
       use as a parameter in all future driver operations.  It can retrieve
       the handle that dev_xxx_configure stored by calling
       io_map_device_number with the device number.  If dev_xxx_open returns
       an OK, it must return the device handle in device_handle_ptr.  If it
       returns a status other than OK, the kernel presumes that the open
       failed and it will disregard the returned device_handle_ptr argument.

   dev_xxx_open_dump
       This routine prepares one of the driver's devices for use as the
       destination of a system dump.

       A master file entry specifies the default device for a system dump,
       but during the dump procedure the user is allowed to specify an
       alternative dump destination.  If your device is selected as the dump
       destination, the system will call your dev_xxx_open_dump routine if
       the system halts.

       The dev_xxx_open_dump routine initializes the device as a dump
       destination.  To do this, it must reinitialize the device's
       controller (and/or units).  Because the system is in an undefined
       state as a result of the halt, the standard kernel facilities will
       not be available for the initialization procedure.  In particular,
       this means that dev_xxx_open_dump must run in physical memory since
       dynamically allocated memory cannot be accessed.  dev_xxx_open_dump
       should statically allocate its data structures in
       dev_xxx_global_data.c.

       The dev_xxx_open_dump routine should also use device polling when
       interacting with the controller, because the standard interrupt
       mechanism will not be available.

       Because the dump procedure is a single-threaded process, you do not
       need and should not use the kernel locking mechanisms.

       The dev_xxx_open_dump routine receives a device name specified by
       device_name.  It should verify that the device specified is of the
       driver's type.  The device name is of the following form:
              device_mnemonic [@device_code]([parameters])

       Finally, as with any open routine, dev_xxx_open_dump should perform
       any operations necessary to ensure that the device is on-line and
       ready for a write operation.  For example, if the device is a tape,
       the tape should be on-line and write-enabled.

       NOTE:  This routine must not halt because it is invoked as part of
              the halt sequence.

   dev_xxx_powerfail
       This routine restarts all devices managed by this driver when power
       has been restored after a power failure.

       The DG/UX system does not support this operation at this time.  You
       should use the appropriate io_nodevice stub for this routine.

   dev_xxx_read_dump
       This routine handles reading a system dump device.

       This routine may be called during a halt to read one or more blocks
       from the system dump device.  Because it will be called during halt
       processing, the normal kernel facilities may not be available.  In
       particular this routine should not use locks or interrupts.  It
       should implement the read operation by polling the device for the
       read operation to complete.

   dev_xxx_read_write
       This routine performs a synchronous read or write of the specified
       device.

       You can assume the request information structure has a valid
       operation code and device handle.  The driver must validate the
       device offset and transfer count as being appropriate for the device.
       The driver must also be prepared to handle errors in referencing the
       memory address as specified in the buffer vector.

       The transfer count specifies the maximum number of bytes that should
       be transferred.  The driver determines how much data to actually
       transfer before it returns.  If there is an error, the amount may be
       less than the transfer count.  However, under no circumstances may
       the amount of data transferred exceed the specified maximum.

       The offset specified is a file pointer maintained by the kernel; it
       indicates where the read/write operation should begin.  For example,
       on a disk, the offset might specify where, after the start of the
       sector, the desired data is located.  The driver may ignore this
       parameter if it is not applicable to its device for example, if the
       device is character special.

       The request information structure can be accessed only when the
       requesting process is running; it can not be accessed from the
       interrupt level.

       The dev_xxx_read_write routine performs a synchronous read or write
       of the specified device, transferring data between the device and the
       specified buffer.  It is invoked whenever a user or kernel read or
       write is performed on a device supported by this driver.  This
       routine is usually used for character special I/O, but it may also be
       used for block special I/O.

       Multiple reads/writes of the same or different minor devices may be
       in progress simultaneously.  Therefore the driver should take steps
       to serialize requests as needed.  This usually means using locks on
       important data structures.

       The dev_xxx_read_write routine should also handle any special
       transfer constraints for its device.  For example, a disk device
       might allow only those transfer counts that are multiples of 512
       bytes.  dev_xxx_read_write should be prepared to handle a kernel-
       requested self-identification check as indicated in the self-id field
       in the request information structure.  The flag indicates that the
       driver should verify that this self-id matches the device's self-id
       as stored in data blocks read from that device.  You can use the
       kernel's fs_check_self_id routine to retrieve the self-id stored in
       the data (see the fs_check_self_id(3K) man page).

       Because the dev_xxx_read_write routine is synchronous, any data that
       is going to be transferred to or from the buffer must already be
       transferred when it completes.  Because it must wait for the I/O to
       complete, dev_xxx_read_write will need to set up await mechanisms
       such as a timeout, a signal, or an I/O completion event.  The
       event_counters(3K) man page describes kernel routines that the driver
       can use to implement these await mechanisms.

       The buffer can only be accessed only when the requesting process is
       running.  Be sure to check the buffer's access status before reading
       or writing to it.  You should check write access to the buffer for
       read operations and read access to the buffer for write operations.

       Many transfer operations must be done to wired buffers.  The
       specified buffer is wired unless the IO_OPERATION_USER_BUFFER
       operation flag is set in the request block operation field.  If the
       buffer is unwired and the transfer requires a wired buffer, the
       driver must explicitly wire the buffer and unwire it before
       returning.  The memory_allocation(3K) man page describes kernel
       routines that the driver can use to wire and unwire memory.

       After the read/write, the driver should update the buffer vector
       pointers to reflect the actual data transferred (which may be less
       than the transfer count in cases of error).  You must use kernel
       utilities for all references and updates to data contained in the
       io_buffer_vector structure.  The io_buffer_vector(3K) man page
       describes the kernel routines used to manipulate buffer vectors.

   dev_xxx_select
       This routine supplies information about whether the specified device
       is ready to perform an I/O operation.

       The kernel calls the dev_xxx_select routine in response to user-level
       select system calls.  dev_xxx_select operates as follows:

       ·      If the user is selecting a device (select_mode argument is
              TRUE), and the device is ready for at least one of the
              incoming intents, the driver should set the intent flags to
              match the device's current state and return.  It should set
              the flags to FALSE for all intents that are not currently
              ready.  It should set the intent flag to TRUE if that flag was
              TRUE on input and the intent is currently ready.  If none of
              the conditions the caller was interested in are TRUE, the
              driver should add the eventcounter pointed to by ec_ptr to a
              list of events maintained by the driver.  Later, when one of
              the specified intents becomes TRUE, the driver must advance
              this eventcounter.  Usually, drivers have the
              dev_xxx_service_interrupt routine complete select processing
              via a message to the Driver or Generic Server.

       ·      If the user is unselecting the device (the select_mode
              argument is FALSE), the driver should discard the previously
              saved ec_ptr and report any intents that have become TRUE.

       Multiple selects of the same or different minor devices may be in
       progress simultaneously.  The dev_xxx_select routine must be able to
       store multiple eventcounter pointers for each of the read, write, and
       exception selects and advance them all when the intent becomes TRUE.
       Kernel routines for managing select lists (adding and removing
       entries and satisfying selects) are described in the io_select(3K)
       man page.  The driver should have allocated and initialized the
       select list structure before select operations begin, usually in the
       dev_xxx_configure routine.

       For many devices, such as disks and tapes, dev_xxx_select always
       returns TRUE because the I/O operations are quick.  dev_xxx_select is
       more meaningful on character devices that depend upon external
       intervention.  For example, the kernel might send a select FALSE for
       writing to a terminal when its output is being held with Ctrl-S.
       Similarly, it would select FALSE for reading when the driver is
       waiting for the user to type something.

   dev_xxx_service_interrupt
       This routine handles interrupts from devices under the control of
       this driver.  It is called by the system interrupt handler.

       The dev_xxx_service_interrupt routine performs any steps needed to
       service the device at interrupt level.  It operates in a restricted
       environment: interrupts are disabled; no page faults may be taken;
       and the process must not wait.  Because of these restrictions,
       dev_xxx_service_interrupt should defer as much device service as
       possible to a base-level process.

       The dev_xxx_service_interrupt must avoid calling any routine that may
       pend.  Therefore, it must forgo virtually all the kernel-supplied
       utilities.  You should use the Driver or Generic Server to signal or
       send information back to other processes.  You send a message to the
       appropriate server (daemon) by queuing a message with a completion
       routine to the server's queue.  [To queue messages, see
       io_queue_message_to_driver_demon(3K) and
       io_queue_message_to_generic_demon(3K).]  The server will dequeue the
       message and execute the completion routine in the server's context
       rather than the interrupt service routine's limited context.

       Typically, dev_xxx_service_interrupt might do any of the following:
       read the device's status registers; advance an eventcounter for
       synchronous events; send a message to the Driver or Generic Server
       for an asynchronous event; or do a select satisfy for a select
       operation.  If the interrupt is not cleared automatically by reading
       the status register, dev_xxx_service_interrupt must clear the
       interrupt before exiting.

       The pointer to the device information structure allows
       dev_xxx_service_interrupt to access the device database associated
       with the I/O request.

       NOTE:  If the device does not generate hardware interrupts, you do
              not need to create this routine.

   dev_xxx_start_io
       This routine starts an asynchronous I/O operation on the specified
       device.

       When a user initiates a read or write operation on a block special
       device, the kernel will invoke dev_xxx_start_io to process the
       request asynchronously.  The dev_xxx_start_io routine is used only on
       block special devices.  Multiple dev_xxx_start_io routines on the
       same or different minor devices may be in progress simultaneously.

       dev_xxx_start_io should start the operation and then exit, leaving
       the completion to be handled by another routine.  If dev_xxx_start_io
       cannot initiate the operation (for example, if the device is busy),
       it should queue the request to be handled later and exit.  This
       routine should not pend.

       The operation record must reside in global kernel memory, so it may
       be accessed by any process, not just the requester.  The driver need
       not validate most of the fields of the operation record.  The
       exceptions are the device offset and transfer size fields.  The
       driver may need to check these fields to ensure that they are
       meaningful for the device.

       The dev_xxx_start_io routine returns before the data transfer is
       complete.  The driver must therefore decide how to finish processing
       once the operation does complete.  The driver is relatively free to
       handle completion as necessary for its own device.

       The only thing the driver is required to do during completion is to
       call the kernel completion routine supplied in the operation record.
       The kernel waits until its I/O completion routine is called before
       expecting new data in the buffer, modifying data in a buffer that was
       written, or modifying the operation record that was passed in as an
       argument.  Until the driver calls the kernel's I/O completion
       routine, the kernel does not consider the operation complete.

       The driver decides when to call the kernel's I/O completion routine.
       Typically, when the operation completes, the
       dev_xxx_service_interrupt routine queues a message to the Driver or
       Generic Server.  The message contains a pointer to a routine which
       the server will execute.  This routine might be either the kernel's
       I/O completion routine or a driver-supplied complete_io routine that
       in turn calls the kernel's I/O completion routine.  The
       server_messages(3K) man page describes the kernel routines for
       interacting with the Driver or Generic Server.

       The information below under kernel_complete_io describes the
       interface the kernel's I/O completion routine uses.  You do not need
       to the kernel-specified interface in your driver's complete_io
       routine.

       The following implementation notes are relevant regardless of how
       completion is implemented:

       ·    The driver must transfer the exact amount of data specified in
            the request unless there is an I/O error (in which case less
            data is acceptable).  Under no circumstances may the amount of
            data transferred exceed the amount specified.

       ·    You must not call the kernel's I/O completion routine in the
            same process from which the dev_xxx_start_io routine is called
            lest the kernel's I/O completion routine be called before
            dev_xxx_start_io finishes.

       ·    The buffer to receive the data is wired in memory.  The driver
            may perform logical-to-physical address translations without
            having to explicitly wire the buffer.  Further, the buffer must
            reside in global kernel memory, so any process may access the
            buffer or perform the logical-to-physical translation.

   dev_xxx_write_dump
       This routine writes system dump data to the dump destination device
       previously opened by dev_xxx_open_dump.

       During a dump, the system's halt code path calls dev_xxx_write_dump
       to write the data specified in the io_buffer_vector.  The halt code
       will call the dev_xxx_write_dump routine as many times as necessary
       to transfer all of the dump data.  You will not need to wire buffer
       memory or verify parameters for this routine.

       If the dump destination must use multiple volumes to hold the entire
       system dump, the dev_xxx_write_dump routine should close the
       completed volume, request that the operator mount a new volume, and
       open the new volume.

       NOTE:  Because the normal kernel facilities are not available, this
              routine should busy-wait for the write operations to complete.
              The normal system interrupt handler is not available.  Also,
              this routine must not halt because it is invoked as part of
              the halt sequence.

   kernel_complete_io
       This routine defines the kernel I/O completion routine interface.
       The kernel supplies a routine that adheres to this interface to
       perform work necessary when an asynchronous I/O operation completes.

       The kernel's I/O completion routine performs the cleanup the kernel
       must do to complete the asynchronous I/O.  The driver calls it to
       indicate that the operation is complete.

       The status argument indicates the result of the asynchronous I/O
       operation.

       The kernel's I/O completion routine must always succeed.  Therefore
       it does not have a return value.

DIAGNOSTICS
   Return Value
       The dev_xxx_init routine does not return a status; any errors that it
       encounters must result in a halt or in some method of flagging the
       error to dev_xxx_configure for further processing.

       For dev_xxx_configure:
              OK     The device was successfully configured.
              IO_ENXIO_DEVICE_NAME_NOT_RECOGNIZED
                     device_name_ptr does not specify a device of the type
                     supported by this driver.
              IO_ENXIO_DEVICE_NOT_SUPPORTED
                     device_name_ptr specifies a device of the type
                     supported by this driver, but the particular model is
                     not supported.
              IO_EIO_PHYSICAL_UNIT_FAILURE
                     A request issued to the device controller failed with
                     an error status.
              IO_EIO_DEVICE_TIMED_OUT
                     The controller did not respond to a request within a
                     reasonable length of time.
              IO_ENXIO_DEVICE_IS_ALREADY_CONFIGURED
                     A device is already registered at the location
                     specified by device_name_ptr.

       For dev_xxx_deconfigure:
              OK     The device was successfully deconfigured.
              IO_ENXIO_DEVICE_NAME_NOT_RECOGNIZED
                     device_name_ptr does not specify a device of the type
                     supported by this driver.  This error is returned when
                     the device mnemonic does not match the mnemonic
                     associated with the driver.
              IO_EBUSY_DEVICE_HAS_OPEN_UNITS
                     The specified device currently has one or more units
                     that are open.

       For dev_xxx_device_to_name:
              OK     The translation was performed successfully.
              IO_ENXIO_DEVICE_IS_NOT_CONFIGURED
                     The specified device number is not configured.

       For dev_xxx_name_to_device:
              OK     The device name was successfully translated.
              IO_ENXIO_DEVICE_NAME_NOT_RECOGNIZED
                     The specified device is not supported by this driver.
                     This error is returned when the device mnemonic does
                     not match the mnemonic associated with the driver.
              IO_ENXIO_DEVICE_IS_NOT_CONFIGURED
                     The specified device is supported by this driver but is
                     not currently configured in the system.

       For dev_xxx_open:
              OK     The dev_xxx_open routine was successful in preparing
                     the device for further operations.
              IO_ENXIO_UNIT_NOT_READY
                     The unit is not ready or on-line.
              IO_ENXIO_DEVICE_IS_NOT_CONFIGURED
                     The specified device number cannot be mapped to a
                     configured device.
              IO_ENXIO_OPEN_INTENT_CONFLICTS
                     The unit is already open and can only be opened
                     exclusively.
              IO_ENXIO_NO_WRITE_RING
                     The tape was opened with write intent, but the tape did
                     not have a write ring (only applicable to tape
                     devices).
              IO_ENXIO_TAPE_DENSITY_NOT_SUPPORTED
                     The requested density is not supported by the tape
                     controller (only applicable to tape devices).
              IO_ENXIO_CANNOT_CHANGE_TAPE_DENSITY
                     The requested density is not compatible with the
                     current density setting of the unit, and the tape is
                     not at the beginning of the tape (BOT) (only applicable
                     to tape devices).

       For dev_xxx_close:
              OK     The close was successful.
              IO_STATUS_ERROR_ON_EARLIER_REQUEST
                     An error occurred on the last asynchronous request made
                     to the device.  Since the last request was
                     asynchronous, this is the first opportunity to notify
                     the interested process.

       The dev_xxx_read_write routine must return a status indicating the
       success or failure of the transfer.  The definition of success or
       failure is determined by the driver and need not be related to the
       number of bytes actually transferred.
              OK     The dev_xxx_read_write routine was successful.
              IO_EINVAL_ILLEGAL_REQUEST_SIZE
                     The requested count is not valid for the device type.
              IO_EINVAL_ILLEGAL_BUFFER_ADDRESS
                     The buffer was not aligned as required by the device.
              IO_ENXIO_ILLEGAL_DEVICE_ADDRESS
                     The location specification for reading/writing is
                     invalid for the device.
              IO_EIO_DEVICE_TIMED_OUT
                     The device controller did not respond to a request in a
                     reasonable length of time.
              IO_EIO_HARD_IO_ERROR
                     An unrecoverable I/O error occurred, resulting from a
                     media failure.
              IO_EIO_PHYSICAL_UNIT_FAILURE
                     An uncorrectable error occurred that presumably affects
                     I/O operations to the entire physical unit.
              IO_EINTR_INTERRUPTED_BY_SIGNAL
                     A signal was received while waiting for the I/O to
                     complete.
              IO_EINVAL_REQUEST_SIZE_TOO_LARGE
                     The requested count exceeds the limit of this device.

       The dev_xxx_start_io routine must return a status indicating the
       success or failure of the start of a transfer. All errors other than
       IO_EINVAL_REQUEST_SIZE_TOO_LARGE are reported via the completion
       routine.
              OK     The request was successfully started.
              IO_EINVAL_REQUEST_SIZE_TOO_LARGE
                     The requested count exceeds the limit of this device.

       The dev_xxx_ioctl routine should return a status indicating the
       success or failure of the control operation.  The definition of
       success or failure is determined by the driver.
              OK     The dev_xxx_ioctl routine was successful.  No errors
                     should be indicated to the caller.
              IO_EINVAL_COMMAND_NOT_SUPPORTED_BY_DEVICE
                     The command was not supported by the driver.

       For dev_xxx_open_dump:
              OK     The open completed successfully.
              IO_STATUS_DUMP_NOT_SUPPORTED
                     The device identified by the device_name string is not
                     supported as a dump device by this driver.  Either the
                     device mnemonic does not match the mnemonic associated
                     with your driver; the device name is in an
                     unrecognizable format; or the device specified by
                     device_name_ptr is supported by the driver but the
                     device type is not a valid dump destination device.
              IO_EIO_HARD_IO_ERROR
                     A request to the dump destination device has resulted
                     in an error condition.

       For dev_xxx_write_dump:
              OK     The write operation completed normally.
              IO_STATUS_TAKE_CHECKPOINT
                     The write operation completed normally but was written
                     as the first record on a volume.  The system dump code
                     should checkpoint its current state.
              IO_EIO_HARD_IO_ERROR
                     An unrecoverable I/O error occurred.  The system dump
                     code should restore its state from the last checkpoint
                     and begin writing again from there.  This error does
                     not occur on the first record of the volume.

       For dev_xxx_read_dump:
              OK     The volume was successfully read.
              IO_EIO_HARD_IO_ERROR
                     An unrecoverable error occurred during the read
                     operation.

       For dev_xxx_close_dump:
              OK     The volume was successfully closed.
              IO_EIO_HARD_IO_ERROR
                     An unrecoverable error occurred in closing the volume.
                     The operator is prompted to mount another volume, and
                     the system dump utility should resume operation at its
                     last checkpoint.

       For dev_xxx_mmap:
              OK     The call successfully created a mapping at the user
                     address returned in start_address_ptr.
              IO_ENXIO_ILLEGAL_DEVICE_ADDRESS
                     The requested device offset range did not fall entirely
                     within a range of mappable device offsets.
              other error status from vm_mmap_physical_memory
                     The mmap request failed due to a problem detected by
                     the vm_mmap_physical_memory routine.
                     vm_mmap_physical_memory will pass back the error
                     status.

       For dev_xxx_munmap:
              OK     All munmaps of this device are allowed.  dev_xxx_munmap
                     must return OK.

       For dev_xxx_powerfail:
              OK     Return this value in all cases.

       For the other routines: none.

SEE ALSO
       adapter_driver(3K), adapter_manager(3K), device_interrupts(3K),
       device_nodes(3K), event_counters(3K), fs_check_self_id(3K),
       io_buffer_vector(3K), io_select(3K), memory_allocation(3K),
       sc_panic(3K), server_messages(3K), status_code_macros(3K).
       system_clock(3K).
       Programming in the DG/UX Kernel Environment.


Licensed material--property of copyright holder(s)

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026