[ Previous | Next | Contents | Home | Search ]
AIX Version 4.3 Understanding the Diagnostic Subsystem for AIX

Example TU open/close device interface

/*
 * COMPONENT_NAME: (TU_DEVICE) Resource Interface Access Code
 *
 * FUNCTIONS: Do_INIT_TUS
 *            Do_TERM_TUS
 */
  
  
/*   FILE NAME: device_interface.c                                        */
/*   FUNCTION:  Device Adapter Application Interface Code                 */
/*                                                                        */
/*    This source file contains source code for the Device adapter's      */
/*    Application Test Units to aid in various testing environments       */
/*    of the device   adapter. These test units provide a basic inter-    */
/*    face between the diagnostic application program and functions       */
/*    written in the diagnostic extension (pdiagex) which provide direct  */
/*    access to the device without the need for a device driver.          */
/*                                                                        */
/*                                                                        */
  
/* INCLUDED FILES */
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <sys/intr.h>
#include <sys/dma.h>
  
#include "device_err_detail.h"
#include "tu.h"
#include <diag/tucb.h>
#include <sys/pdiagex_dds.h>
  
/*****************************************/
/*- INITIALIZE Test Unit  #1            -*/
/*****************************************/
void
Do_INIT_TUS(TU_TYPE *dev_tucb, TU_GLOBAL_DATA *tu_data, TU_RETURN_TYPE *tu_rc)
{
        int     rc;
        void    *ih_handle;
  
        /* Set initial tu success status */
        tu_rc->major_rc = TU_SUCCESS;
  
        /*- unconfigure device/children and place device in diagnose state -*/
        rc = pdiag_diagnose_state(dev_tucb->resource_name);
        if (rc != 0) {           /*- test unit failed to complete normally -*/
                tu_rc->major_rc = TU_DEVICE_BUSY;
                tu_rc->minor_rc = rc;
                return;
        }
  
        tu_data->adapter_diagnose_state = 1;
  
        /* Get all the device attributes for the dds structure */
        rc = get_dds( dev_tucb, tu_data );
        if (rc != 0) {           /*- test unit failed to complete normally -*/
                tu_rc->major_rc = TU_SOFTWARE_ERROR;
                tu_rc->minor_rc = rc;
                return;
        }
  
       /************************************************************
        * Call pdiag_open 
        * This also loads the interrupt handler
        ************************************************************/
        /* Open the device for testing via PDIAGEX */
        rc = pdiag_open( dev_tucb->resource_name, &tu_data->dds, "device_intr",
          &tu_data->pdiagex_handle);
        if (rc != 0) {           /*- test unit failed to complete normally -*/
                if ( dev_tucb->parms.msg_file != (FILE *)NULL)
                        fprintf( dev_tucb->parms.msg_file,
                                 "pdiagex open rc = %d\n", rc);
                tu_rc->major_rc = TU_DEVICE_BUSY;
                tu_rc->minor_rc = rc;
                return;
        }
  
        return;                 /*- normal completion -*/
}
  
/*****************************************/
/*- TERMINATE Test Unit  #EFFF          -*/
/*****************************************/
void
Do_TERM_TUS(TU_TYPE *dev_tucb, TU_GLOBAL_DATA *tu_data, TU_RETURN_TYPE *tu_rc)
{
        int rc;
   
        tu_rc->major_rc = TU_SUCCESS;
 
        /* Close/terminate device from PDIAGEX     */
        /* This also unloads the interrupt handler */
        rc = pdiag_close(tu_data->pdiagex_handle);
        if ( rc != 0 ) {
                if ( dev_tucb->parms.msg_file != (FILE *)NULL)
                        fprintf( dev_tucb->parms.msg_file,
                                         "pdiagex close rc = %d\n", rc);
                tu_rc->major_rc = TU_SOFTWARE_ERROR;
                tu_rc->minor_rc = rc;
        }
  
        /*- reconfigure device/children to their original state -*/
        rc = pdiag_restore_state(dev_tucb->resource_name);
        if (rc != 0) {          /*- test unit failed to complete normally -*/
                tu_rc->major_rc = TU_SOFTWARE_ERROR;
                tu_rc->minor_rc = rc;
        }
  
        return;                 /*- normal completion -*/
}
  
/*****************************************/
/*- Get the device attributes           -*/
/*****************************************/
int
get_dds( TU_TYPE *dev_tucb, TU_GLOBAL_DATA *tu_data )
{
        int     rc;
        char    type;
        char    *parent_name;
  
        /* Open/Initialize Configuration Services */
        if ((rc = pdiag_cs_open()) != 0 )
                return (rc);
  
        /********************************************************/
        /* Initialize the DDS structure with all pertinent data */
        /********************************************************/
  
        /* Get the parent name */
        rc = pdiag_cs_get_attr(dev_tucb->resource_name, "parent_name",                                        &parent_name, &type );
  
        /* Bus ID for the parent resource */
        rc = getatt(&tu_data->dds.bus_id,'l',parent_name,"bus_id",NULL);
        pdiag_cs_free_attr ( parent_name );
  
        /* Slot number */
        rc=getatt(&tu_data->dds.slot_num,'i',dev_tucb->resource_name,
                  "connwhere", NULL);
  
        /* Bus Interrupt Level */
        rc=getatt(&tu_data->dds.bus_intr_lvl,'i',dev_tucb->resource_name,
                  "busintr", NULL);
  
        /* assign bus_io_addr */
        rc=getatt(&tu_data->dds.bus_io_addr,'l',dev_tucb->resource_name,
                  "busio",NULL);
  
        /* assign bus_io_length */
        rc=getatt(&tu_data->dds.bus_io_length,'l',dev_tucb->resource_name,
                  "bus_io_length",NULL);
  
        /* assign bus_mem_addr */
        rc=getatt(&tu_data->dds.bus_mem_addr,'l',dev_tucb->resource_name,
                 "bus_mem_addr",NULL);
  
        /* assign bus_mem_length */
        rc=getatt(&tu_data->dds.bus_mem_length,'l',dev_tucb->resource_name,
                 "bus_mem_length",NULL);
  
        tu_data->dds.intr_priority = INTCLASS2;
        tu_data->dds.intr_flags = NULL;               /* not used by PCI */
        tu_data->dds.dma_lvl = NULL;                  /* not used by PCI */
        tu_data->dds.dma_bus_mem = NULL;
        tu_data->dds.dma_bus_length = NULL;
        tu_data->dds.dma_flags = DMA_MASTER;
        tu_data->dds.bus_type = BUS_BID;
  
        tu_data->dds.data_ptr = (uchar *)NULL;
  
        tu_data->dds.maxmaster = 32;
  
        /* Close Configuration Services */
        pdiag_cs_close();
        return (rc);
}
/**************************************************************************
 * NAME: getatt
 *
 * FUNCTION: Obtains attribute from the configuration services
 *      database, or change list.
 *
 * EXECUTION ENVIRONMENT:
 *
 * NOTES:
 *
 * int
 *   getatt(dest_addr,dest_type,lname,att_name,newatt )
 *
 *      dest_addr = pointer to the destination field.
 *      dest_type = The data type which the attribute is to be converted to
 *                    's' = string              rep=s
 *                    'b' = byte sequence       rep=s,  e.g. "0x56FFE67.."
 *                    'l' = long                rep=n
 *                    'i' = int                 rep=n
 *                    'h' = short (half)        rep=n
 *                    'c' = char                rep=n,or s
 *                    'a' = address             rep=n
 *      lname     = Device logical name. ( or parent's logical name )
 *      att_name  = attribute name to retrieve
 *      newatt    = New attributes to be scanned before reading database
 *
 *
 * RETURNS:
 *      0  = Successful
 *      <0 = Successful (for byte sequence only, = -ve no. of bytes)
 *      >0 = errno ( E_NOATTR = attribute not found )
 *
**************************************************************************/
int getatt(dest_addr, dest_type, lname, att_name, newatt)
void            *dest_addr;     /* Address of destination                   */
char            dest_type;      /* Destination type                         */
char            *lname;         /* device logical name                      */
char            *att_name;      /* attribute name                           */
struct  attr    *newatt;        /* List of new attributes                   */
{
  struct  attr    *att_changed();
  struct  attr    *att_ptr;
  int             convert_seq();
  int             rc;
  char            *val_ptr;
  char            rep;
  char            *value;
  
  /* Note: We need an entry from customized, or predefined even if */
  /* an entry from newatt is going to be used because there is no  */
  /* representation (rep) in newatt                                */
  
  /* SEARCH FOR ENTRY */
  rc = pdiag_cs_get_attr(lname, att_name, &value, &rep );
  
  /* CONVERT THE DATA TYPE TO THE DESTINATION TYPE */
  rc = convert_att(dest_addr, dest_type, value, rep );
  
  /* Free up what the pdiag_cs_get_addr allocated */
  pdiag_cs_free_attr( &value );
  
  return(rc);
}
  
  
/*************************************************************************
 * NAME: convert_att
 *
 * FUNCTION: This routine converts attributes into different data types
 *
 * EXECUTION ENVIRONMENT:
 *
 *      Generally this routine is called by getatt(), but it is available
 *      to other procedures which need to convert data which may not also
 *      be represented in the database.
 *      No global variable are used, so this may be dynamically linked.
 *
 * RETURNS:
 *
 *       0 = Successful
 *      <0 = Successful (for byte sequence only, = -ve no. of bytes)
 *      >0 = errno
**************************************************************************/
int convert_att(dest_addr, dest_type, val_ptr, rep )
void    *dest_addr;             /* Address of destination                   */
char    dest_type;              /* Destination type                         */
char    *val_ptr;               /* Address of source                        */
char    rep;                    /* Representation of source ('s', or 'n')   */
{
  
  if( rep == 's' ) {
        switch( dest_type ) {
                case 's':
                        strcpy( (char *)dest_addr, val_ptr );
                        break;
                case 'c':
                        *(char *)dest_addr = *val_ptr;
                        break;
                case 'b':
                        return ( convert_seq( val_ptr, (char *)dest_addr ) );
                case 'i':
                        *(int *)dest_addr =
                            (int)strtoul( val_ptr, (char **)NULL, 0);
                        break;
                default:
                            return 1;
        }
  } else if( rep == 'n' ) {
        switch( dest_type ) {
                case 'l':
                        *(long *)dest_addr =
                            strtoul( val_ptr, (char **)NULL, 0);
                        break;
                case 'i':
                        *(int *)dest_addr =
                            (int)strtoul( val_ptr, (char **)NULL, 0);
                        break;
                case 'h':
                        *(short *)dest_addr =
                            (short)strtoul( val_ptr, (char **)NULL, 0);
                        break;
                case 'c':
                        *(char *)dest_addr =
                            (char)strtoul( val_ptr, (char **)NULL, 0);
                        break;
                case 'a':
                        *(void **)dest_addr =
                            (void *)strtoul( val_ptr, (char **)NULL, 0);
                        break;
                default:
                            return 1;
        }
  } else {
        return 1;
  }
  return 0;
}
  
  
/**************************************************************************
 * NAME: convert_seq
 *
 * FUNCTION: Converts a hex-style string to a sequence of bytes
 *
 * EXECUTION ENVIRONMENT:
 *
 *      This routine uses no global variables
 *
 * NOTES:
 *
 *      The string to be converted is of the form
 *      "0xFFAAEE5A567456724650789789ABDEF678"  (for example)
 *      This would put the code FF into the first byte, AA into the second,
 *      etc.
 *
 * RETURNS: No of bytes, or -3 if error.
 *
***************************************************************************/
  
int convert_seq( source, dest )
char *source;
uchar *dest;
{
  char    byte_val[5];    /* e.g. "0x5F\0"        */
  int     byte_count = 0;
  
  uchar   tmp_val;
  char    *end_ptr;
  
  strcpy( byte_val, "0x00" );
  
  if( *source == '\0' ) {   /* Accept empty string as legal */
                return 0;
  }
  
  if( *source++ != '0' ) {
        return 1;
  }
  
  if( tolower(*source++) != 'x' ) {
        return 1;
  }
  
  while( ( byte_val[2] = *source ) && ( byte_val[3] = *(source+1) ) ) {
        source += 2;
  
        /* be careful not to store illegal bytes in case the
         * destination is of exact size, and the source has
         * trailing blanks
         */
 
        tmp_val = (uchar) strtoul( byte_val, &end_ptr, 0 );
        if( end_ptr != &byte_val[4] ) {
                break;
        }
 
        *dest++ = tmp_val;
        byte_count++;
  }
 
  return -byte_count;
}
 

[ Previous | Next | Contents | Home | Search ]