Logo Search packages:      
Sourcecode: ibmasm-utils version File versions  Download package

libibmasm.c

/*
 * This software may be used and distributed according to the terms
 * of the Lesser GNU Public License, incorporated herein by reference
 *
 * Copyright (C) IBM Corporation, 2004
 *
 * Author: Max Asböck <amax@us.ibm.com>
 */


#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <signal.h>
#include <sys/ioctl.h>

#include "libibmasm.h"
#include "rsa.h"

00026 struct spnode { 
      unsigned int      opened;
      int         event_fd;
      int         heartbeat_fd;
      unsigned int      io_buffer_length;
      char        command_path[RSA_NAME_SIZE];
      char        event_path[RSA_NAME_SIZE];
      char        heartbeat_path[RSA_NAME_SIZE];
};

#define MAX_SP_NODES    16

static struct spnode *node_array[MAX_SP_NODES];
static unsigned int num_nodes = 0;
static int api_initialized = 0;

#define HANDLE_ADD 1          // handles must not be 0, so we always add 1
#define handle2node(h)  h - HANDLE_ADD
#define node2handle(n)  n + HANDLE_ADD

static inline struct spnode *get_spnode(int node)
{
      if (node < 0 || node >= num_nodes)
            return NULL;

      return node_array[node];
}

#define get_spnode_from_handle(h)         get_spnode(handle2node(h))

static int get_ibmasmfs_mount_point(char *mount_point)
{
      FILE *f;
      char line[RSA_NAME_SIZE];
      char *first, *mount, *type;


      f = fopen("/proc/mounts", "r");
      if (f == NULL)
            return 1;

      while(fgets(line, 1024, f)) {
            first = strtok(line, " ");
            mount = strtok(NULL, " ");
            type = strtok(NULL, " ");
            if (!strcmp(type, "ibmasmfs")) {
                  strncpy(mount_point, mount, RSA_NAME_SIZE - 1); 
                  fclose(f);
                  return 0;
            }
      }
      fclose(f);
      return 1;
}

static unsigned int api_init()
{ 
      DIR *dir;
      struct dirent *dirent;
      char mount_point[RSA_NAME_SIZE];
      struct spnode *nodes[MAX_SP_NODES];
      int n = 0;
      int i;

      // find out where ibmasmfs is mounted
      if (get_ibmasmfs_mount_point(mount_point) != 0)
            return 1;

      dir = opendir(mount_point);
      if (dir == NULL)
            return 1;

      // the ibmasmfs root directory contains a directory
      // entry for each service processor. Look them up
      // and allocate a data structure to save away 
      // path names and state information for each service
      // processor node.
      while ((dirent = readdir(dir))) {
            struct spnode *node;

            if (!strcmp(dirent->d_name, "."))
                  continue;
            if (!strcmp(dirent->d_name, ".."))
                  continue;

            // allocate memory: if we fail on one node
            // back out completely 
            node = malloc(sizeof(struct spnode));
            if (node == NULL) {
                  for (i=0; i<n; i++)
                        free(nodes[i]);
                  n = 0;
                  break;
            }
            // we found a service processor node
            // set up the path names for the command, event
            // and reverse heartbeat files
            snprintf(node->command_path, RSA_NAME_SIZE, "%s/%s/%s",
                mount_point, dirent->d_name, RSA_COMMAND);
            snprintf(node->event_path, RSA_NAME_SIZE, "%s/%s/%s",
                mount_point, dirent->d_name, RSA_EVENT);
            snprintf(node->heartbeat_path, RSA_NAME_SIZE, "%s/%s/%s",
                mount_point, dirent->d_name, RSA_HEARTBEAT);

            node->opened = 0;
            nodes[n] = node;
            n++;
            if (n >= MAX_SP_NODES)
                  break;
      }
      closedir(dir);

      // we didn't find any nodes or malloc failed
      if (n == 0)
            return 1;

      // we found at least one service processor node.
      // initialize the global node array and node number
      for (i=0; i<n; i++) 
            node_array[i] = nodes[i];
      num_nodes = n;
      return 0;
}

/**
 * OpenSPDriverNode
 * must be called first by an application, before any other API call
 * can be made.
 *
 * Return codes:
 *    RC_ALREADY_OPEN
 *    RC_INVALID_BUFFER
 *    RC_SYSTEM_ERROR
 *    RC_SUCCESS
 */
unsigned int OpenSPDriverNode(int *handle, 
            unsigned int      io_buffer_length,
            unsigned int      node,
            unsigned int      *num,
            unsigned long     reserved)
{
      struct spnode *spnode;

      if (handle == NULL && num == NULL)
            return RC_INVALID_HANDLE;

      /* ensure the the io buffer size is valid (1 - 32 Kb) */
      if ((io_buffer_length < 1) || (io_buffer_length > 32))
            return  RC_INVALID_BUFFER;

      if (!api_initialized) {
            api_initialized = 1;
            if (api_init() == 1) {
                  api_initialized = 0;
                  return RC_SYSTEM_ERROR;
            }
      }
      if (num != NULL)
            *num = num_nodes;

      if (handle == NULL)
            return RC_SUCCESS;

      spnode = get_spnode(node);
      if (spnode == NULL)
            return RC_OPEN_FAILED;

      if (spnode->opened)
            return RC_ALREADY_OPEN;

      spnode->event_fd = open(spnode->event_path, O_RDWR);
      if (spnode->event_fd < 0)
            goto event_open_failed;

      spnode->heartbeat_fd = open(spnode->heartbeat_path, O_RDWR);
      if (spnode->heartbeat_fd < 0)
            goto heartbeat_open_failed;

      spnode->io_buffer_length      = io_buffer_length * 1024;
      spnode->opened                = 1;
      *handle = node2handle(node);
      return RC_SUCCESS;


heartbeat_open_failed:
      close(spnode->event_fd);
event_open_failed:
      return RC_OPEN_FAILED;
}


/**
 * OpenSPDriver
 * for backwards compatibility      
 */
unsigned int OpenSPDriver(int *handle,
                  unsigned int io_buffer_length,
                  unsigned long reserved)
{
     return OpenSPDriverNode(handle, io_buffer_length, 0, NULL, reserved); 
}


static void io_cancel(int fd)
{
      char c = 0;

      write(fd, &c, 1);
}

/**
 * CloseSPDriver
 * must be called when an application closes.
 *
 * Return values:
 *    RC_INVALID_HANDLE
 *    RC_ALREADY_CLOSED
 *    RC_SUCCESS
 */
unsigned int CloseSPDriver(int handle, unsigned long reserved)
{
      struct spnode *node;

      node = get_spnode_from_handle(handle);
      if (node == NULL || !node->opened)
            return RC_INVALID_HANDLE;

      node->opened = 0;
      io_cancel(node->event_fd);
      io_cancel(node->heartbeat_fd);
      close(node->event_fd);
      close(node->heartbeat_fd);

      return RC_SUCCESS;
}


static int send_command(struct spnode *node, void *command)
{
      int fd;
      int len = node->io_buffer_length;
      int result;

        fd = open(node->command_path, O_RDWR);
        if (fd < 0)
            return RC_SYSTEM_ERROR;

      result = write(fd, command, len);
      if (result <= 0) {
            close(fd);
            return RC_SYSTEM_ERROR;
      }

      result = read(fd, command, len);
      if (result <= 0) {
            close(fd);
            return RC_SYSTEM_ERROR;
      }
      close(fd);
      return 0;
}
      
/**
 * SystemDataIO
 * Send a command to the service processor
 *
 * Return values:
 *      RC_INVALID_HANDLE
 *      RC_INVALID_BUFFER
 *      RC_SYSTEM_ERROR
 *      RC_TIMEOUT
 */
unsigned int SystemDataIO(int handle, void *command, unsigned long reserved)
{
      struct dot_command *dot_command = (struct dot_command *)command;
      struct spnode *node = get_spnode_from_handle(handle);

      if (node == NULL || !node->opened)
            return RC_INVALID_HANDLE;

      if (command == NULL)
            return RC_INVALID_BUFFER;

      switch(dot_command->type) {
      case dotcmd_write:
      case dotcmd_write_next:
      case dotcmd_read:
      case dotcmd_read_next:
            return send_command(node, command);
      default:
            dot_command->type = dotcmd_command_response;
            return RC_SUCCESS;
      }
}


static int wait_for_event(struct spnode *node, void *buffer)
{
      int ret;
      unsigned int size;

      if (node->io_buffer_length > IBMASM_EVENT_MAX_SIZE)
            size = IBMASM_EVENT_MAX_SIZE;
      else
            size = node->io_buffer_length;

      ret = read(node->event_fd, buffer, size);
      if (ret == 0)
            return RC_EVENT_CANCELLED;
      else if (ret < 0) {
            switch(errno) {
            case EBUSY:
                  return RC_ALREADY_REGISTERED;
            case EINTR:
                  return RC_SUCCESS;
            default:
                  return RC_SYSTEM_ERROR;
            }
      }
      return RC_SUCCESS;
}

static int
event_ignored(void *buffer,  unsigned char **ignore_list, short ignore_count)
{
      int i;
      char *event = (char *)buffer + sizeof(struct dot_command);
      int size = ((struct dot_command *)buffer)->command_size;

      for (i=0; i<ignore_count; i++) {
            if (!strncmp(ignore_list[i], event, size))
                  return 1;
      }
      return 0;
}


/**
 * RegisterForEvents
 * allows an application to register for event notification.
 *
 * Return code:
 *    RC_INVALID_HANDLE
 *    RC_INVALID_BUFFER
 *    RC_SUCCESS
 *    RC_EVENT_CANCELLED
 */
unsigned int RegisterForEvents(int handle, void *buffer, short ignore_count, unsigned char **ignore_list, unsigned long reserved)
{
      int i;
      int ret;
      struct spnode *node = get_spnode_from_handle(handle);

      if (node == NULL || !node->opened)
            return RC_INVALID_HANDLE;
      
      if (buffer == NULL)                                                   
            return RC_INVALID_BUFFER;  

      if (ignore_count && ignore_list == NULL)
            return RC_INVALID_BUFFER;

      for(i=0; i<ignore_count; i++) {
            if (ignore_list[i] == NULL)
                  return RC_INVALID_BUFFER;
      }

      while ( (ret = wait_for_event(node, buffer)) == RC_SUCCESS )
            if ( !event_ignored(buffer, ignore_list, ignore_count) )
                  break;
      
      return ret;
}

/**
 * DeregisterForEvents
 * Cancel event registration, i.e wake up the thread that is waiting
 * for an event.
 * 
 * Return values:
 *      RC_INVALID_HANDLE
 *      RC_SUCCESS
 */
unsigned int DeregisterForEvents(int handle, unsigned long reserved)
{
      struct spnode *node = get_spnode_from_handle(handle);

      if (node == NULL || !node->opened)
            return RC_INVALID_HANDLE;

      io_cancel(node->event_fd);
      return RC_SUCCESS;
}

unsigned int RegisterForReverseHB(int handle, unsigned long reserved)
{
      struct spnode *node = get_spnode_from_handle(handle);
      unsigned char c = 0;
      int ret;

      if (node == NULL || !node->opened)
            return RC_INVALID_HANDLE;

      ret = read(node->heartbeat_fd, &c, 1);
      if (ret == 1)
            return RC_REVERSE_HEARTBEAT_HAS_FAILED;

      switch(errno) {
      case EBUSY:
            return RC_REVERSE_HB_ALREADY_REGISTERED;
      case EINTR:
            return RC_SUCCESS;
      default:
            return RC_SYSTEM_ERROR;
      }
}

unsigned int DeRegisterForReverseHB(int handle, unsigned long reserved)
{
      struct spnode *node = get_spnode_from_handle(handle);

      if (node == NULL || !node->opened)
            return RC_INVALID_HANDLE;

      io_cancel(node->heartbeat_fd);
      return RC_SUCCESS;
}

Generated by  Doxygen 1.6.0   Back to index