Skip to content
Snippets Groups Projects
Commit 0f4decbb authored by Federico Vaga's avatar Federico Vaga
Browse files

lib: basic implementation


Signed-off-by: default avatarFederico Vaga <federico.vaga@cern.ch>
parent 11706246
No related merge requests found
......@@ -7,6 +7,25 @@
#ifndef _FMC_CORE_H
#define _FMC_CORE_H
#include <stdbool.h>
const char *fmc_version_get(void);
struct fmc_tkn;
#define FMC_ID_INVALID 0xFFFFFFFF
unsigned int *fmc_carrier_id_list_get(void);
void fmc_carrier_id_list_put(unsigned int *id_list);
unsigned int *fmc_slot_id_list_get(struct fmc_tkn *tkn);
void fmc_slot_id_list_put(unsigned int *id_list);
struct fmc_tkn *fmc_carrier_open(unsigned int carrier_id);
void fmc_carrier_close(struct fmc_tkn *tkn);
bool fmc_slot_is_present(struct fmc_tkn *tkn, unsigned int slot_n);
bool fmc_slot_is_fru_valid(struct fmc_tkn *tkn, unsigned int slot_n);
int fmc_slot_geo_address(struct fmc_tkn *tkn, unsigned int slot_n,
unsigned int *ga);
#endif /* _FMC_CORE_H */
......@@ -4,7 +4,18 @@
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <glob.h>
#include <errno.h>
#include <string.h>
#include <libgen.h>
#include <fmc/core.h>
#ifndef GIT_VERSION
......@@ -14,6 +25,29 @@
static const char *libfmc_version = GIT_VERSION;
const char *libfmc_version_full = "libfmc version:" GIT_VERSION;
#ifndef BIT
#define BIT(_n) (1 << _n)
#endif
#define FMC_SLOT_PRESENT BIT(0)
#define FMC_SLOT_FRU_VALID BIT(1)
#define MAX_PATH_LEN 128
#define MAX_SYS_LEN 16
struct fmc_slot {
unsigned int id;
unsigned long flags;
unsigned int ga;
char eeprom_type[MAX_SYS_LEN];
};
struct fmc_carrier {
unsigned int id;
struct fmc_slot **slot;
unsigned int n_slots;
};
/**
* Return the FMC library version
* @return return the FMC library version as string
......@@ -22,3 +56,314 @@ const char *fmc_version_get(void)
{
return libfmc_version;
}
static struct fmc_slot *__fmc_slot_get(struct fmc_carrier *carrier,
unsigned int slot_n)
{
int i;
for (i = 0; i < carrier->n_slots; ++i)
if (carrier->slot[i]->id == slot_n)
return carrier->slot[i];
return NULL;
}
static bool fmc_slot_is_flag_set(struct fmc_tkn *tkn, unsigned int slot_n,
unsigned int flag)
{
struct fmc_carrier *carrier = (struct fmc_carrier *)tkn;
struct fmc_slot *slot = __fmc_slot_get(carrier, slot_n);
if (!slot)
return false;
return (slot->flags & flag);
}
static int __fmc_sys_read_string(struct fmc_carrier *carr,
unsigned int slot_n,
const char *name,
char *str,
unsigned int max_len)
{
char path[MAX_PATH_LEN];
int fd;
int ret;
snprintf(path, MAX_PATH_LEN,
"/sys/class/fmc/fmc-carrier-%d/fmc-slot-%d.%d/%s",
carr->id, carr->id, slot_n, name);
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
ret = read(fd, str, max_len);
close(fd);
return ret;
}
static int __fmc_sys_read_int(struct fmc_carrier *carr,
unsigned int slot_n,
const char *name,
unsigned int *val)
{
char buf[MAX_SYS_LEN];
int ret;
ret = __fmc_sys_read_string(carr, slot_n, name, buf, MAX_SYS_LEN);
if (ret < 0)
return ret;
ret = sscanf(buf, "%d", val);
if (ret != 1)
return -1;
return 0;
}
static bool __fmc_slot_is_present(struct fmc_carrier *carr,
unsigned int slot_n)
{
int err;
unsigned int val;
err = __fmc_sys_read_int(carr, slot_n, "present", &val);
if (err < 0)
return false;
return val;
}
static bool __fmc_slot_is_fru_valid(struct fmc_carrier *carr,
unsigned int slot_n)
{
int err;
unsigned int val;
err = __fmc_sys_read_int(carr, slot_n, "fru_valid", &val);
if (err < 0)
return false;
return val;
}
static int __fmc_slot_ga_get(struct fmc_carrier *carr,
unsigned int slot_n,
unsigned int *ga)
{
int err;
err = __fmc_sys_read_int(carr, slot_n, "fmc_ga", ga);
if (err)
*ga = 0xFF;
return err;
}
static int fmc_carrier_slots_init(struct fmc_carrier *carr)
{
char pattern[MAX_PATH_LEN];
glob_t g;
int err, i;
snprintf(pattern, MAX_PATH_LEN, "/sys/class/fmc/fmc-carrier-%d/fmc-slot-%d.*",
carr->id, carr->id);
err = glob(pattern, 0, NULL, &g);
if (err == GLOB_NOMATCH)
goto err_glob;
carr->n_slots = g.gl_pathc;
carr->slot = calloc(carr->n_slots, sizeof(struct fmc_slot *));
if (!carr->slot) {
errno = ENOMEM;
goto err_alloc;
}
for (i = 0; i < carr->n_slots; i++) {
carr->slot[i] = malloc(sizeof(*carr->slot[i]));
memset(carr->slot[i], 0, sizeof(*carr->slot[i]));
sscanf(basename(g.gl_pathv[i]), "fmc-slot-%*d.%d",
&carr->slot[i]->id);
__fmc_slot_ga_get(carr, carr->slot[i]->id, &carr->slot[i]->ga);
if (__fmc_slot_is_present(carr, carr->slot[i]->id))
carr->slot[i]->flags |= FMC_SLOT_PRESENT;
if (__fmc_slot_is_fru_valid(carr, carr->slot[i]->id))
carr->slot[i]->flags |= FMC_SLOT_FRU_VALID;
}
globfree(&g);
return 0;
err_alloc:
globfree(&g);
err_glob:
return -1;
}
static void fmc_carrier_slots_cleanup(struct fmc_carrier *carr)
{
int i;
for (i = 0; i < carr->n_slots; i++)
free(carr->slot[i]);
free(carr->slot);
}
/**
* Check whether the an FMC mezzanine is present or not
* @param[in] tkn: FMC carrier token
* @param[in] slot_n: FMC slot number (LUN)
*
* @return true if present; false if not present or error
*/
bool fmc_slot_is_present(struct fmc_tkn *tkn, unsigned int slot_n)
{
return fmc_slot_is_flag_set(tkn, slot_n, FMC_SLOT_PRESENT);
}
/**
* Check whether the an FMC mezzanine is present or not
* @param[in] tkn: FMC carrier token
* @param[in] slot_n: FMC slot number (LUN)
*
* @return true if the FRU is valid; false if the FRU is not valid or error
*/
bool fmc_slot_is_fru_valid(struct fmc_tkn *tkn, unsigned int slot_n)
{
return fmc_slot_is_flag_set(tkn, slot_n, FMC_SLOT_FRU_VALID);
}
/**
* Get the slot geographical address
* @param[in] tkn: FMC carrier token
* @param[in] slot_n: FMC slot number (LUN)
* @param[out] ga: geographical address
*
* @return on success 0, otherwise -1 and errono is appropriately set
*/
int fmc_slot_geo_address(struct fmc_tkn *tkn, unsigned int slot_n,
unsigned int *ga)
{
struct fmc_carrier *carrier = (struct fmc_carrier *)tkn;
struct fmc_slot *slot = __fmc_slot_get(carrier, slot_n);
if (!slot)
return -1;
*ga = slot->ga;
return 0;
}
/**
* Open an FMC carrier
*
* @param[in] carrier_id: carrier identifier
* @return on success a valid pointer, otherwise NULL and errono is
* appropriately set
*/
struct fmc_tkn *fmc_carrier_open(unsigned int carrier_id)
{
struct fmc_carrier *carr;
int ret;
carr = malloc(sizeof(*carr));
if (!carr)
return NULL;
memset(carr, 0, sizeof(*carr));
carr->id = carrier_id;
ret = fmc_carrier_slots_init(carr);
if (ret < 0)
goto err_slots;
return (struct fmc_tkn *)carr;
err_slots:
free(carr);
return NULL;
}
/**
* Close a previously opened FMC carrier
*
* @param[in] tkn: FMC carrier token
*/
void fmc_carrier_close(struct fmc_tkn *tkn)
{
if (tkn) {
struct fmc_carrier *carr = (struct fmc_carrier *)tkn;
fmc_carrier_slots_cleanup(carr);
free(carr);
}
}
/**
* Identifiers list of available carrier
* @return on success a list of identifiers terminated by
* FMC_ID_INVALID
*/
unsigned int *fmc_carrier_id_list_get(void)
{
glob_t g;
int err, i;
unsigned int *id_list;
err = glob("/sys/class/fmc/fmc-carrier-*", 0, NULL, &g);
if (err == GLOB_NOMATCH)
goto err_glob;
id_list = calloc(g.gl_pathc + 1, sizeof(unsigned int));
if (!id_list)
goto err_alloc;
for (i = 0; i < g.gl_pathc; i++) {
int ret = sscanf(g.gl_pathv[i],
"/sys/class/fmc/fmc-carrier-%d",
&id_list[i]);
if (ret != 1)
goto err_scanf;
}
id_list[i] = FMC_ID_INVALID;
globfree(&g);
return id_list;
err_scanf:
free(id_list);
err_alloc:
globfree(&g);
err_glob:
return NULL;
}
/**
* Identifiers list of available slots on a given carrier
* @return on success a list of identifiers terminated by
* FMC_ID_INVALID
*/
unsigned int *fmc_slot_id_list_get(struct fmc_tkn *tkn)
{
struct fmc_carrier *carrier = (struct fmc_carrier *)tkn;
unsigned int *id_list;
int i;
id_list = calloc(carrier->n_slots + 1, sizeof(unsigned int));
if (!id_list)
goto err_alloc;
for (i = 0; i < carrier->n_slots; ++i)
id_list[i] = carrier->slot[i]->id;
id_list[i] = FMC_ID_INVALID;
return id_list;
err_alloc:
return NULL;
}
static void fmc_id_list_put(unsigned int *id_list)
{
free(id_list);
}
void fmc_carrier_id_list_put(unsigned int *id_list)
{
fmc_id_list_put(id_list);
}
void fmc_slot_id_list_put(unsigned int *id_list)
{
fmc_id_list_put(id_list);
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment