Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ RIC(4) — AIX PS/2 1.2.1

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

icaload



RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



-------------------------------------------------------------------------------
RIC



PURPOSE

Supports the Realtime Interface Co-processor (RIC) Multiport 2.

DESCRIPTION

The /dev/ric are special files that provide an image of RIC memory.  Ric0
refers to the first RIC card, ric1 to the second, ric2 to the third, and ric3
to the fourth RIC card.

Byte address in /dev/ric refer to locations in memory on the appropriate RIC
card.  References to non-existent locations cause errors to be returned.

In addition to memory image, /dev/ric has several ioctl commands which are
defined in sys/1386/ric.h.

ICACMD         Issues a command to a task on the RIC.  The argument of this
               ioctl is a pointer to a riccmd structure.  This ioctl will not
               return until the RIC task has returned an interrupt.  The
               content of the input buffer is copied into the arg element of
               the riccmd structure when the interrupt is received from the RIC
               task.  A command 3 is sent to the RIC task 0 after copying the
               input buffer.  This ioctl is primarily intended for sending
               commands to RCM.

ICARESET       Issues a hardware reset to the RIC card.  This command may take
               up to 30 seconds to complete, as the RIC card will run its
               diagnostic tests.  This command also initializes the RCM's
               maximum number of tasks, priorities, queues, and timeouts.

ICACMDNOWAIT   Performs the same function as ICACMS, but does not wait for an
               interrupt from the RIC task, does not copy the input buffer, and
               does not send a command 3 to the RIC task upon completion.

ANOUNCETASK    Identifies a task so that other device drivers that depend on
               the RIC tasks can find the appropriate task on the RIC card.

ICA_STAT1      Retrieves the primary status byte of a specified task on an
               ARTIC card.  This value is returned in the user provided
               argument (the first byte of the arg field of the riccmd
               structure; see the header file ric.h)

ICA_STAT2      Retrieves secondary status bytes (the length of the buffer is
               task dependent) of a specified task on an ARTIC card.  It is
               issued in the main module of the application process.  Data is
               returned via the arg field of the riccmd structure.




Processed November 7, 1990         RIC(4,F)                                   1





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



ICA_ASYNC      Allows an application process (caller) to handle asynchronous
               interrupts from a particular task on an ARTIC card.  It is
               issued by the main module of the application process.

ICA_NOASYNC    Undoes the effect of ICA_ASYNC.

ICA_CHKSIG     Allows an application process to find out which task on an ARTIC
               card has caused an asynchronous interrupt.  This command is
               normally issued by the signal handler of the application
               process.

ICA_QURIC      Reports the number of ARTIC cards installed on a machine.
               Returned values include slot number, card number, and card type
               respectively (see the header file ric.h), via the arg field of
               the riccmd structure.

Note:  If a card is bad, its type will be UNKNOWNCARD.

SUPPORTING COMMANDS

There are two commands which enable users to reset an ARTIC card and then
download tasks onto it.

To reset a card, enter at the command line:

  icareset <icareset <card_number>

where card_number is some integer n which is 0 for the ARTIC card in the lowest
slot number, 1 for the ARTIC card in the slot next to the lowest one, etc.

To load a task on an ARTIC card, enter at the command line:

  icaload [-v] <card_number> <task_name> <task_number> [load_option]

where task_name is the file name of a task and task_number is an integer
between 1 and MAXTASK inclusively (the default value for MAXTASK is 16; though,
it can be changed in /etc/system).  To load a task only, enter 1 for the
load_option; by default, the loaded task is started once it is loaded.

THE ARTIC CARD MEMORY DUMP

To dump the memory content of an ARTIC card, use the dd command, using as the
input file name dev/ric0, /dev/ric1, etc.  The recommended way of viewing the
content of the output file is with the od command, as illustrated by the
example below:

  dd of=/dev/ric0 of=/tmp/ric0.out
  od -x /tmp/ric0.out | pg

Alternatively, you can open one of these files with a C program and read the
memory content of the card, and then use the printf subroutine to format the
output in octal or hexadecimal.



Processed November 7, 1990         RIC(4,F)                                   2





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)




THE NEW IOCTL SYSTEM CALLS

The syntax for the new ioctl calls is:

         ioctl(fd,op,&info)

Before an ioctl call, the following declarations and instructions are written:

  int fd;
  struct riccmd {
         unsigned char task;
         unsigned char cmd;         /* this structure is actually
         unsigned short arglen;        defined in ric.h           */
         unsigned char arg|30|;
  } ;
  struct riccmd info;

  fd = open("/dev/ric00,...);

      /* Here the riccmd structure is filled
         with the needed information before
         the ioctl call is issued            */

The ioctl call is issued with the correct file descriptor, the correct ioctl
call, and all the information needed through the riccmd structure.  This file
descriptor is used by the driver to get the board number.  All the following
ioctl calls are issued to tasks running on the board corresponding to the file
descriptor created with the open call.

The return value of the call is -1 if an error occurs, and 0 if the call is
successful.  If the call requests information to be returned from the driver,
this information is stored in the arg array of the riccmd structure used in the
call.

The new ioctl operations are:

ICA_STAT1    This ioctl operation enables a process to read the primary status
             byte of a task.  The user passes the task number in info.task and
             the primary status of that task is returned in the first byte of
             info.arg at the end of the ioctl call.

ICA_STAT2    This ioctl operation enables a process to read the secondary
             status buffer of a task.  The user passes the task number in
             info.task and the length of the arg field in info.arglen (the
             ARTIC driver uses this value to determine how many bytes to return
             without overflowing arg field).  The secondary status bytes are
             returned in info.arg at the end of the system call.  Application
             processes should check info.arglen to determine the number of
             bytes of data being returned.





Processed November 7, 1990         RIC(4,F)                                   3





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



ICA_ASYNC    This ioctl operation is issued with the task number in info.task.
             This call informs the driver of the following:

               o The application program wants to be signaled when asynchronous
                 interrupts come from the task and card specified.  The user
                 does not need to provide the card number because the ARTIC
                 driver acquires the information through the file descriptor.

               o The process issuing the ioctl call handles the signals sent by
                 the driver when receiving asynchronous interrupt(s) from the
                 task.

ICA_QURIC    This ioctl operation allows callers to determine the number of
             ARTIC cards installed on a machine and what their types are.  Data
             is returned in info.arg and info.arglen specifies the number of
             installed ARTIC cards.  To determine the length in bytes of
             info.arg, multiply info.arglen by three.

ICA_NOASYNC  This ioctl operation cancels the effect of the ICA_ASYNC ioctl
             operation that was previously issued to the same task on the same
             card.  The asynchronous interrupts caused by that task are ignored
             until another process issues ICA_ASYNC.

ICA_CHKSIG   This ioctl operation enables the user to determine the card and
             task numbers responsible for generating asynchronous interrupts
             after receiving a signal.  One or more signals may need to be
             processed.  The task and card numbers are in the first two bytes
             of info.arg respectively at the end of the call.

The program sample below shows how the ioctl operations ICACMD, ICA_STAT1, and
ICA_STAT2 are used:

  #include <fcntl.h>
  #include <sys/ioctl.h>
  #include <ric.h>
  #include <stdio.h>
  main()
  {
      int fd, i, rval, nbcopy;
        unsigned char b0, b1, b2, b3;
      struct riccmd buf;                /*defines a structure to be used in
                                            ioctls */
      fd = open ("/dev/ric00", 0_RDWR);

      /* issue a command to task 3 and check for  */
      /* error if there is any

      buf.cmd = 0xa0;    /* command to task 3 */
      buf.task=3;
      buf.arglen = 0;   /* this command has no argument   */

      if (ioctl (fd,ICACMD, &buf) == -1)



Processed November 7, 1990         RIC(4,F)                                   4





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



        {
          printf ("ioctl - ICACMD failed");
        goto end;
       }

      /* look at primary status to check for error */
        buf.task=3;
      rval = ioctl (fd, ICA_STAT1, &buf);
      if (rval == -1)
       {
           printf ("ioctl (ICA_STAT1) failed");
           goto end;
       }
      /* if there is an error, look at secondary status bytes for */
      /* more details                                             */

      if (buf.arg [0] == ERROR)
      {

           /* get the secondary status bytes   */
           buf.task = 3;
           buf.arglen = 6;             /* want only 6 bytes */
           if (ioctl (fd, ICA_STAT2, &buf) == -1)
      {
                printf ("ioctl - ICA_STAT2 failed");
                goto end;
      }

      nbcopy = buf.arglen;   /* number of bytes ioctl-ICA_STAT2 returned  */
      printf ("number of bytes returned by ioctl-ICA_STAT2 = %d", nbcopy);
      printf ("secondary status byte of task is: ");
           b0 = buf.arg [0] ; b1 = buf.arg [1];
      b2 = buf.arg[2] ; b3 = buf.arg [3];
      printf ("byte" = %x byte1 = %x byte2 = %x byte3 = %x", b0, b1, b2, b3);
     }
  end: ;
  }

THE READX SYSTEM CALLS

A special character file is associated with each ARTIC card. For the first
ARTIC card, there is a corresponding /dev/ric00.  For the second card, there is
a corresponding /dev/ric01.  Each file has the file protection mode of 0x666,
allowing all users to open these files for reading or writing on ARTIC card
tasks.

Any process can read or write to any task on any board after the correct open
system call has been issued.

To read data from the task input buffer of a task on a particular card, the
user must open the special file associated with the card and issue the readx




Processed November 7, 1990         RIC(4,F)                                   5





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



command.  For example, to read data from the input buffer of a task on card
one, the following sequence of system calls must be issued:

      fd = open("/dev/ric01", ...)
      readx(fd, buffer, buffer_length, task_number)

An ioctl or writex call must be issued by appl.level to inform the task that
the application level has read the data.  The task input buffer can then be
reused by the task.  This information is user-defined to establish handshaking
between the application and the tasks.

The readx system call works in the following manner:

Note:  The input buffer is a buffer created by a task.  The task leaves data in
       this buffer for a system unit process to read.

  o The device driver gets the input buffer page, its offset and its length
    from the interface block on the ARTIC card for the task.  If the buffer
    provided by the user is shorter than the task input buffer, readx fills the
    buffer and updates the file offset pointer accordingly.  The next readx,
    which is issued to read the input buffer of the same task, copies the data
    at the point where the last readx stopped, as long as the file offset
    pointer is smaller than the task input buffer length.  When the file offset
    pointer is equal or greater than the input buffer length, EOF is reached
    and -1 is returned.  If the buffer provided by the user is longer than the
    task input buffer, the buffer is filled with the data from the task input
    buffer.  File offset pointer is also updated accordingly.  The readx call
    returns the number of bytes successfully read and a value of -1 in case of
    error.

  o Although this is a character special file, the lseek system call can be
    issued at the application level to change the file offset pointer.  This is
    done when the application process has exhausted the data in the task input
    buffer and it is ready to read another buffer.

SPECIAL CONSIDERATIONS

The C compiler on AIX PS/2 1.2 and the C compiler used to compile ARTIC tasks
have different word alignments, as illustrated in the following example:

     struct example {
  short int s;
  int i;
  }

The size of the structure example is 6 bytes for the ARTIC compiler and 8 bytes
for the AIX compiler. In AIX PS/2, the alignment for the integer is doubleword,
which is 4 bytes.  The variable s is a short int (2 bytes), which leaves 2
bytes of unused space between s and i.

In the case of the readx system call, the data is copied byte-by-byte from the
input buffer of the ARTIC card task into the user buffer of type structure



Processed November 7, 1990         RIC(4,F)                                   6





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



struct example.  The first 6 bytes of the user buffer contain the data. At the
application level, when the i field of structure struct example is referenced,
only the first two bytes have valid data.  The other two bytes of valid data
are in the gap between the variables s and i.

The following diagram illustrates the above:

    /* the driver stored the data as followed */
            |---------|-----------------------------|
            |  x |  x |  x | x  | x  | x  |    |    |
            |---------|---------|-------------------|

    /* at the application level, references the data is the following */
            |---------|-----------------------------|
            |  x |  x |  x | x  | x  | x  |    |    |
            |---------|---------|-------------------|
            |short    |         |int                |
            |example.s|  gap    |----example.i------|

To avoid errors caused by alignment problems, all buffers used for the readx
and writex system calls should only be of type char or unsigned char.

DEALING WITH INTERRUPTS (ARTIC CARD --> APPLICATION PROGRAM)

SYNCHRONOUS INTERRUPTS

Each time a command is sent to a task with the ICACMD ioctl system call, the
process sleeps and the ioctl does not return until the ARTIC task interrupts
the process.  This interrupt is called a synchronous interrupt.

ASYNCHRONOUS INTERRUPTS

All other interrupts coming from ARTIC tasks are called asynchronous
interrupts.  They can be interrupts coming from ARTIC tasks upon completion of
an ICACMDNOWAIT ioctl call (from the task side, these interrupts are
synchronous), or interrupts coming from the ARTIC card that request the
attention of the application program.

PROCESSING THE INTERRUPTS

The device driver processes the interrupts with its second level interrupt
handler ricintr() in the following way:

  o In the case of synchronous interrupts, ricintr() wakes up the process
    sleeping in the ICACMD ioctl call.

  o In the case of asynchronous interrupts, there are two possibilities:

    1. Interrupts handled in the kernel by device drivers.  For example,
      rictty is the device driver in the kernel that drives tty's (terminals
      for instance), using the ARTIC task com232.exe to control the transfer
      of data through the card.



Processed November 7, 1990         RIC(4,F)                                   7





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)




      The kernel subroutine icaintratch arranges a kernel function to be
      called when the indicated task on the indicated on the ARTIC card (both
      parameters of icaintratch posts an interrupt to the system unit.  The
      address of this function is put in a structure called taskvec.  This
      address is checked by the ARTIC card device driver in order to know
      which function handles an interrupt coming from an ARTIC task.

        struct ricintrvec {
               int (*inthandler)();
               int intarg;
               int taskid;
        }

        struct ricintrvec taskvec[MAXCYCLONE][MAXTASK+1]
        /* max of cards and tasks */

      In the rictty thefollowing is an icaintratch function:

        icaintratch(0,board,ttytask[unit],rtyintr,0)

        /* ttytask[unit] is the task on the board that posts the async. int. */
        /* rtyintr is the function called and it is in the taskvec structure */

    2. Interrupts handled by the user.  If the user decides that he wants to
      handle asynchronous interrupts coming from certain tasks, the driver
      will then send a signal sigurg to the process that has issued an
      ICA_ASYNC ioctl call for the given tasks.

For each ARTIC card, the driver maintains a free list and a queue list.  The
free list is a linked list of nodes, twice as long as the number of tasks
allowed to run on the card.  Each time a task posts an asynchronous interrupt
and there is a process which has requested to handle the interrupt coming from
this task, the ARTIC card device driver, before sending the SIGURG signal to
the application process, saves the card number unit on which the task is
running, the task number, and the process id number of the process to which the
driver will send the signal.  The driver gets a node from the free list, stores
that information in it, and attaches this node to the queue list. Each time a
process issues the ICA_CHKSG ioctl call to find out about the nature of the
interrupt, the driver returns the task number and the card number of the task
that caused the interrupt to the calling process.  The unnecessary node is
freed from the queue list and returns to the free list.  If more asynchronous
interrupts occur before processes issue ICA_CHKSIG ioctl calls to retrieve
information from the queue list, the free list may be exhausted.  In this
situation, the driver reuses the node at the head of the queue.  A new node is
attached to the end of the queue.

The following is the structure of the linked list:







Processed November 7, 1990         RIC(4,F)                                   8





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



      struct jobs_queue {
          int pid;
          unsigned char task_no ;
          unsigned char board_no;
          struct jobs_queue * next;
      }

An opened file is either closed by the last process using it (by issuing a
close system call) or it is closed automatically by the kernel at the end of
the execution of the last process opening the file.  This rule also applies to
opened special files.  In each case the ricclose function is called by the
kernel.  In this module, the driver reinitializes the sig_pend_tb table and
removes the queue to return the space to the free list.  These two steps are
performed only for the ARTIC card being closed; other tables remain intact.

SPECIAL CONSIDERATIONS

In the following situation, the user decides to acknowledge asynchronous
interrupts coming from certain tasks.  These asynchronous interrupts are sent
when this process is sleeping in a ICACMD ioctl call to a different task
waiting for a synchronous interrupt from this task to wake it up.  The
situation is handled in the following manner:

  1. Asynchronous interrupts that trigger signals are only processed when the
    process is awakened by the synchronous interrupt and returns to the user
    mode.  Since the tsleep system call is issued with the PCATCH argument, if
    sleep is killed by a signal, it returns with the TS_SIG value. The
    following loop keeps the process asleep until either the synchronous
    interrupt wakes it, or the elapsed time exceeds 6 seconds:

            while  (tsleep(pid,...|PCATCH,6) = = TS_SIG)

  2. If more than one signal is sent to the process while it is sleeping, the
    device driver provides information so the user can handle all the
    processes.  The kernel does not queue the signals when the process is
    sleeping but the device driver uses the two lists to keep track of signals
    sent during sleep.

    The information in the different buffers and primary status of a task
    sending multiple asynchronous interrupts during the sleep of the process is
    not saved by the kernel.  It is up to the user to make his ARTIC tasks in a
    way that this transfer of information can be done in correct delays.  When
    the process is awakened, it returns to user mode and the first signal is
    automatically handled in the user defined signal handler. The user then
    issues the CHK_SIG ioctl call to find out if other signals were sent to the
    process while sleeping.  The following provides an example:









Processed November 7, 1990         RIC(4,F)                                   9





RIC(4,F)                    AIX Technical Reference                    RIC(4,F)



          handler ()
          {
             ...
              while ( ioctl (fd,CHECK_SIGNAL,&buf) != -1)
              {
                  deal_with () /* user defined func. processes the signal */
              }
          }

  3. When the CHK_SIG ioctl command is issued at the application level to
    determine if it has any pending signals the driver searches the linked list
    for the first occurrence of a node with a process id that is the same as
    the process id of the process issuing the system call.  If the search
    succeeds, the task number and the card number stored in this node are
    copied to the user buffer and this node is removed from the linked list.
    If the search fails, the ioctl call will return -1.

RELATED INFORMATION

The icaload command in the AIX Operating System Commands Reference.



































Processed November 7, 1990         RIC(4,F)                                  10



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