ses_log_transport.c revision e4f5a11d4a234623168c1558fcdf4341e11769e1
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* SCSI Enclosure Services Log Transport Module
*
* This transport module is responsible for accessing the ses devices seen
* from this host, reading their logs, generating ereports for targeted
* entries, and then writing the log contents to a well known location in
* the filesystem.
*
*/
#include <ctype.h>
#include <fm/topo_mod.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <fm/libseslog.h>
#include <errno.h>
/*
* This struct contains the default property values. These may
* be overridden by entries in a ses_log_transport.conf file.
*/
static const fmd_prop_t fmd_props[] = {
};
/* Maintains statistics on dropped ereports. */
static struct slt_stat
{
} slt_stats = {
};
/*
* This structure maintains a reference to the input values, transport, and
* other data which is held by FMD and retrieved whenever an entry point
* is called.
*/
typedef struct ses_log_monitor
{
char *slt_path; /* Output path for log files */
/* Contains expander log data retrieved from a topology node */
typedef struct expander
{
} expander_t;
#define EXAMINE_FMRI_VALUE 0 /* Operation value for extractin fmri val */
/* Prototype needed for use in declaring and populating tables */
/* Holds a code-operation pair. Contains a log code an a function ptr */
typedef struct code_operation {
int code;
/* Holds a platform type and a list of code-operation structures */
typedef struct platform {
const char *pid;
int count;
} platform_t;
/* Holds a reference to all of the platforms */
typedef struct platforms {
int pcount;
} platforms_t;
/* This is the genesis list of codes and functions. */
};
/* This is the list of all platforms and their associated code op pairs. */
platform_t platform_list[] = {
{ "SUN-GENESIS",
sizeof (genesis_codes) / sizeof (code_operation_t),
};
/* This structure holds a reference to the platform list. */
platforms_t platforms = {
sizeof (platform_list) / sizeof (platform_t),
};
/*
* Post ereports using this method.
*/
static void
{
int e = 0;
if (e == 0) {
} else {
}
} else {
}
}
/*
* Create a directory if it doesn't exist.
* Parameters:
* path: The directory path to create.
* mode: The mode used when creating the directory.
*/
static int
{
int status = 0;
/* Directory does not exist */
status = -1;
status = -1;
}
return (status);
}
/*
* Validates that all directories in path exist
* path: The directory path to create.
* mode: The mode used when creating the directory.
*/
static int
{
char *pp;
char *sp;
int status = 0;
/* Neither root nor double slash in path */
*sp = '\0';
*sp = '/';
}
}
return (status);
}
/*
* Rotate the file from base.max-1->base.max, ... base.1->base.2, base->base.1
* Parameter:
* file: The name of the current log file.
*/
void
{
int i;
char newFile[MAXPATHLEN];
char oldName[MAXPATHLEN];
int size;
/*
* If current file size plus what will be added is larger
* than max file size, rotate the logs
* For check to see if larger than configured max size.
*/
/* next log entries can fit */
return;
}
/* next log entries could make log entries too large */
}
/* Finally move base to base.1 */
}
/*
* This method exists to give access into the fmri. One purpose is to flip the
* instance number on the FMRI for a given hc-list entry. It is also
* used to pull the value of an hc-list entry. In all cases, the function
* returns the value of the hc-list entry found, NULL if no value was found.
*/
static char *
{
int i;
char *name;
int ival;
char ivs[25];
char *target_val = NULL;
return (NULL);
}
/* hc-list is an array of nvlists */
/*
* Loop until you find the list that has hc-name that equals the
* passed in "target" value (such as controller) in it.
*/
for (i = 0; i < nelem; i++) {
/* Skip this pair if it is not labeled hc-name */
!= 0) {
continue;
}
/*
* Extract the value of the name. Continue on an error because
* we want to check all of the hc-name entries.
*/
continue;
}
/* If this isn't the target, go to the next pair. */
continue;
}
!= 0) {
"Could not find hc-id in the fmri for %s", target);
return (NULL);
}
/*
* This is the target pair. If we can't get the value then
* exit out and log an error.
*/
"Target value not returned.");
return (NULL);
}
switch (operation) {
case INVERT_FMRI_INSTANCE : {
== 0) {
"hc-id", ivs)) != 0) {
"Error setting ivalue.");
}
} else {
"Error removing original ivalue.");
}
break;
}
case EXAMINE_FMRI_VALUE : {
/*
* target_val is already set. Return without modifying
* its value.
*/
break;
}
/* Can return target_val as is (NULL) */
default : {
*err = INVALID_OPERATION;
break;
}
} /* End switch on operation */
/* Exit the loop. You have found the target */
break;
}
return (target_val);
}
/*
* Generate a filename based on the target path
* Parameters:
* filename: The space for the generated output log file name.
* expander: An expander_t struct containing path, pid etc info from the node.
* slmp: A pointer to the transport data structure which contains the
* configurable file parameters.
*/
static int
int byte_count)
{
char *ses_node;
int i;
int label_length;
int status = 0;
char *subchassis_val = NULL;
/*
* Add the file name with the path root
* and append a forward slash if one is not there.
*/
if (ses_node) {
}
}
/*
* If a subchassis is defined, include it in the file name.
* Errors are logged in the function. There may legitimately be no
* subchassis, so simply continue if none is found.
*/
if (subchassis_val != NULL) {
}
/* remove spaces and forward slashes from name */
for (i = 0; i < label_length; i++) {
}
}
/*
* Ensure directory structure exists for log file.
*/
/*
* Check size of file and rotate if necessary.
*/
return (status);
}
/*
* Determines the error class type based on the severity of the entry.
* Parameter
* severity: A severity level from a log entry.
*/
static char *
error_type(int severity)
{
char *rval;
switch (severity) {
break;
break;
break;
}
return (rval);
}
/*
* Allocates and adds an entry for a given expander to the expander list.
* Parameters
* slmp: A pointer to the ses_log_monitor_t struct for this transport.
* key: A unique identifier for this expander.
*/
static int
{
int status = 0;
"Error allocating expander detail space (%d)", status);
return (status);
}
DEFAULT_DATA)) != 0) {
"Error adding default data to expander details (%d)",
status);
} else {
expanderDetails)) != 0) {
"Error storing the default expander details (%d)",
status);
}
}
return (status);
}
/*
* Retrieves the expander record nvlist that is associated with the
* expander identified by the given key. If no match is found, an
* entry is created with default values.
* Parameters
* slmp: A pointer to the ses_log_monitor_t struct for this transport.
* key: A pointer to the key for an expander.
* expdata: A pointer to a pointer for the last log entry data for this
* expander.
*/
static int
{
int err = 0;
/*
* Retrieve the expander record that matches this expander. A default
* entry will be returned if no matching entry is found.
*/
&expanderRecord)) != 0) {
"Expander add failed for %s", key);
return (err);
}
&expanderRecord)) != 0) {
"Could not retrieve the data after adding it", key);
return (err);
}
}
!= 0) {
"Could not retrieve the expander data field (%d)", err);
return (err);
}
return (err);
}
/*
* Searches the platform lists for target codes. If a match is found then
* it calls then indicated function.
*/
static int
{
int status = 0;
int i, x;
break;
}
}
break;
}
}
if (status != 0) {
"Error checking for a code action (%d)", status);
}
return (status);
}
/*
* Inverts the controller instance in the specified FMRI
*/
static int
{
int err = 0;
if (err != 0) {
"invert_fmri encountered an error: %d", err);
}
return (err);
}
/*
* Checks the severity of the log entry against the configured boundary,
* generates and ereport, and writes the data out to the log file.
* Parameters
* slmp: A pointer to the ses_log_monitor_t struct for this transport.
* entry: The log entry
* ena: the ena for this transport.
* expander: Contains derived information for this expander.
* format_time: The formatted time to append to this entry.
* fp: A file pointer for the data to be written out to.
*/
static int
{
char *log_entry;
char *severity;
int severityValue = 0;
char *code;
int rval = 0;
return (rval);
}
== 0) {
/*
* Pull the code and check to see if there are any
* special operations to perform for it on the given
* platform.
*/
&code) == 0) {
/* Log errors in function */
}
"log severity %d mapped to NULL", severity);
return (rval);
}
/*
* Create the ENA for this transport so that it can be
* used for any ereports that we need to generate.
*/
}
} else {
"Unable to pull severity from the entry.");
return (rval);
}
/*
* Append the log entry to the log file.
*/
if (fp) {
&log_entry)) == 0) {
} else {
"Unable to pull log from the entry.");
}
}
return (rval);
}
/*
* The function performs the work of deallocating the space used for an
* expander_t structure.
* Parameters:
* slmp: A pointer to t ses_log_monitor_t struct for this transport.
* exp: A pointer to an expander_t structure that identifies an expander.
*/
static void
{
}
}
}
/*
* This function performs the log read on a target
*
* Parameters:
* slmp: A pointer to the ses log monitor structure.
* expander: A pointer to an expander object that contains info required
* for a call to the libseslog library.
* lib_param: The structure used to pass data to and from the library. This
* contains the target's information as well as a ponter to returned data.
*/
static int
struct ses_log_call_struct *lib_param)
{
char *expdata;
int err;
/* Retrieve the last entry for this expander for the lib call */
return (err);
}
/*
* If the library call returned non zero, log it, however, the call
* may still have returned valid log data. Check the log data. If it
* is NULL, return an error. Otherwise continue processing.
*/
}
/* Double check that log data actually exists. */
return (NULL_LOG_DATA);
}
/*
* If we can retrieve the expander details for this expander then store
* the last log entry returned from the library. Otherwise log it
* and continue processing.
*/
&expanderRecord)) == 0) {
lib_param->last_log_entry) != 0) {
"Error saving buffer data in expander details");
}
} else {
"Could not retrieve expander to store last entry: %d", err);
}
return (err);
}
/*
* This function processes the log data from a target. This includes
* writing the data to the filesystem and initiating generation of ereports
* as needed by calling slt_post_ereport.
*
*
* Parameters:
* slmp: A pointer to the ses log monitor structure.
* expander: A pointer to an expander object that contains info about the
* expander.
* lib_param: The structure used to pass data to and from the library. This
* contains the target's information as well as a ponter to returned data.
*/
static int
struct ses_log_call_struct *lib_param)
{
int err;
char *pairName;
char fileName[MAXPATHLEN];
char format_time[30];
int output_count;
/*
* Determine how many bytes will be written out with this response,
* pass this count to a function that will determine whether or not
* to roll the logs, and will return the name of the file path to use.
*/
if (err == 0) {
}
}
/* Format the time to prepend to the log entry */
/*
* For each entry returned, generate an ereport if the severity
* is at or above the target level, then append all entries to
* the appropriate log file.
*/
/*
* Process each entry in the result data returned from
* the library call. These are log entries and may
* warrant an ereport.
*/
format_time, fp);
}
}
/* Close the log file */
if (fp) {
}
/* Free the space used for the result and the fmri. */
return (0);
}
/*
* This function performs the log read and processing of the logs for a target
* as well as writing the data to the filesystem. Ereports are generated
* as needed by calling slt_post_ereport.
*
* Access the log data for a specific ses.
* If a log entry should generate an ereport, call slt_post_ereport
* Format and store the data at the appropriate location.
*/
static int
{
struct ses_log_call_struct lib_param;
int err;
int status = 0;
char *target_path = NULL;
char *product_id = NULL;
char *sas_address = NULL;
/* Not the type of node we are looking for */
return (TOPO_WALK_NEXT);
}
/* Allocate space for the holder structure */
sizeof (expander_t), FMD_SLEEP);
&err)) == 0) {
} else {
}
&target_path, &err)) == 0) {
} else {
"Error collecting ses-devfs-path\n");
}
&product_id, &err)) == 0) {
} else {
}
&sas_address, &err)) == 0) {
"sas-address length is not 16: (%s)", sas_address);
status |= 1;
} else {
}
} else {
}
/* Obtain the fmri for this node and save a reference to it. */
topo_strerror(err));
return (TOPO_WALK_NEXT);
} else {
}
if (status == 0) {
"Error retrieving logs: %d\n", err);
return (TOPO_WALK_NEXT);
}
"Error processing logs: %d\n", err);
}
}
/* Free the expander structure whether this is a success or failure. */
return (TOPO_WALK_NEXT);
}
/*
* Called by the FMD after the specified timeout has expired.
* This initiates the processing of the SES device logs.
* slt_process_ses_log() performs the actual log retrieval and analysis.
*
* The last action is to reset the timer so that this method is called again.
*/
/*ARGSUSED*/
static void
{
int err;
/* Retrieve the SES log monitor structure. */
return;
}
/*
* This initializes a topology walk structure for stepping through
* the snapshot associated with thp. Note that a callback function
* is supplied (slt_process_ses_log in this case).
*/
topo_strerror(err));
return;
}
/*
* This function walks through the snapshot and invokes the callback
* function supplied when it was set up above.
*/
return;
}
/* This releases the walk structure. */
/* Reset the timer for the next iteration. */
slmp->slt_interval);
}
/*
* Entry points for the FMD to access this transport.
*/
static const fmd_hdl_ops_t fmd_ops = {
NULL, /* fmdo_recv */
slt_timeout, /* fmdo_timeout */
NULL, /* fmdo_close */
NULL, /* fmdo_stats */
NULL, /* fmdo_gc */
NULL, /* fmdo_send */
NULL, /* fmdo_topo_change */
};
static const fmd_hdl_info_t fmd_info = {
};
/*
* Initialize the transport.
*/
void
{
int error;
return;
sizeof (slt_stats) / sizeof (fmd_stat_t),
(fmd_stat_t *)&slt_stats);
"Unable to obtain a reference to the transport");
return;
}
/*
* interval is validity checked by the framework since it is of type
* FMD_TYPE_TIME.
*/
/*
* Use default the severity if it is out of range.
* Setting the severity too high is allowed as this has the effect
* of preventing any ereports from being generated.
*/
}
}
}
/* Invalid paths will be handled by logging and skipping log creation */
/* Allocate space for the expander id holder */
"Error allocating space for the expander list: %d", error);
return;
}
/*
* Call our initial timer routine, starting the periodic timeout.
*/
}
/*
* Shut down the transport. The primary responsibility is to release any
* allocated memory.
*/
void
{
if (slmp) {
}
}