fcal_leds.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* Copyright (c) 2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This plugin checks the status of FC-AL disks periodically and
* in response to PICL events. It adjusts the state of the FC-AL LEDs
* to match the disk status.
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <alloca.h>
#include <syslog.h>
#include <string.h>
#include <libintl.h>
#include <pthread.h>
#include <sys/systeminfo.h>
#include <poll.h>
#include <errno.h>
#include <libnvpair.h>
#include "fcal_leds.h"
static void fcal_leds_register(void);
static void fcal_leds_init(void);
static void fcal_leds_fini(void);
static void *fcal_poll_thread(void *args);
static FILE *open_config(void);
/*
* Global thread data
*/
volatile int g_event_flag;
static picld_plugin_reg_t my_reg_info = {
"SUNW_fcal_leds",
};
static pthread_t ledsthr_tid;
static pthread_attr_t ledsthr_attr;
static pthread_t pollthr_tid;
static pthread_attr_t pollthr_attr;
/*
* look up table for LED state
*/
static struct {
const led_state_t led_state;
const char *state_str;
} state_lookup[] = {
{ LED_STATE_ON, FCAL_PICL_LED_ON },
};
/*
* executed as part of .init when the plugin is dlopen()ed
*/
#pragma init(fcal_leds_register)
static void
fcal_leds_register(void)
{
(void) picld_plugin_register(&my_reg_info);
}
/* ARGSUSED */
static void
void *cookie)
{
int r;
return;
r = pthread_mutex_lock(&g_mutex);
if (r != 0) {
return;
}
(void) pthread_cond_signal(&g_cv);
(void) pthread_mutex_unlock(&g_mutex);
}
/*
* Locate and open relevant config file
*/
static FILE *
open_config(void)
{
return (NULL);
}
return (fp);
}
/*
* read volatile property function for led State
*/
static int
{
/*
* valbuf has space for a unit address at the end
*/
char valbuf[MAX_LEN_UNIT_ADDRESS];
char *ptr;
/*
* each led-unit node has a UnitAddress property set to the bit
* value associated with the led. Read that property
*/
if (r != PICL_SUCCESS)
return (r);
/* UnitAddress is a string of hex digits, convert to an int */
return (PICL_PROPVALUNAVAILABLE);
/*
* search the leds of each disk for a match with this UnitAddress
*/
break;
}
if (led < FCAL_LED_CNT)
break;
}
return (PICL_PROPVALUNAVAILABLE);
/*
* state_lookup is a table relating led-state enums to equivalent
* text strings. Locate the string for the current state.
*/
for (r = 0; r < state_lkup_len; r++) {
return (PICL_SUCCESS);
}
}
return (PICL_PROPVALUNAVAILABLE);
}
int
{
int r;
int unitlen;
char unitstr[MAXPATHLEN];
return (PICL_NODENOTFOUND);
}
/*
* get search string buffer, allow space for address
*/
return (r);
}
int
{
int r;
if (r != PICL_SUCCESS) {
return (r);
}
r = ptree_create_table(tbl_h);
if (r != PICL_SUCCESS) {
return (r);
}
return (r);
}
/*
* Locate disk-slot nodes and add DeviceTable of LED references
* Also add a volatile State property to each LED node
*/
static void
{
int d, i, r;
int ledlen;
char ledstr[MAXPATHLEN];
return;
}
/* set up search string in buffer with space to append address */
if (r != PICL_SUCCESS)
break;
/*
* locate disk-slot node in frutree
*/
break;
for (i = 0; i < FCAL_LED_CNT; i++) {
/*
* For each disk-slot in frutree, add a device
* table of references to relevant LEDs.
* En passant, add a volatile State property to
* each LED node found.
*/
/*
* append led address to search string
*/
if (r != PICL_SUCCESS) {
break;
}
r = ptree_init_propinfo(&propinfo,
if (r != PICL_SUCCESS) {
break;
}
if (r != PICL_SUCCESS) {
break;
}
r = ptree_init_propinfo(&propinfo,
PICL_READ, sizeof (PICL_CLASS_LED),
if (r != PICL_SUCCESS) {
break;
}
&tbl_prop[0]);
if (r != PICL_SUCCESS) {
break;
}
r = ptree_init_propinfo(&propinfo,
PICL_READ, sizeof (picl_prophdl_t),
if (r != PICL_SUCCESS) {
break;
}
&tbl_prop[1]);
if (r != PICL_SUCCESS) {
break;
}
if (r != PICL_SUCCESS) {
break;
}
}
if (r != PICL_SUCCESS)
break;
}
}
/*
* This is an undo function to match add_led_refs()
* Locate disk-slot nodes and remove Devices table of LED references
* Also remove volatile State property to each LED node
*/
static void
{
int d;
int i;
int r;
int ledlen;
char ledstr[MAXPATHLEN];
return;
continue;
&prop_hdl) != PICL_SUCCESS)
continue;
continue;
(void) ptree_destroy_prop(prop_hdl);
}
for (i = 0; i < FCAL_LED_CNT; i++) {
/*
* find each led node
*/
if (r != PICL_SUCCESS)
continue;
/*
* locate and delete the volatile State property
*/
continue;
continue;
(void) ptree_destroy_prop(prop_hdl);
}
}
}
/*
* Poll thread.
* This thread sits on a poll() call for the fast poll interval.
* At each wake up it determines if a time event should be passed on.
* Poll seems to be reliable when the realtime clock is wound backwards,
* whereas pthread_cond_timedwait() is not.
*/
/*ARGSUSED*/
static void *
fcal_poll_thread(void *args)
{
int c;
int slow_poll_count;
for (;;) {
if (g_finish_now) {
c = pthread_mutex_lock(&g_mutex);
if (c != 0) {
break;
}
(void) pthread_cond_signal(&g_cv_ack);
(void) pthread_mutex_unlock(&g_mutex);
continue;
}
/*
* If picld has been recycled, or if this is the initial
* entry, dtls will not match g_led_dtls.
* In this case, do some resetting.
*/
if (dtls != g_led_dtls) {
dtls = g_led_dtls;
}
if (c == -1) {
break;
}
/*
* dtls->fast_poll_end is the number of fast poll times left
* before we revert to slow polling. If it is non-zero, the
* fcal_leds thread is do fast polling and we pass on every
* poll wakeup.
*/
/*
* If a LED test is underway, fast polling would normally be
* set also. Just in case the timers are configured unusually,
* pass on all poll wakeups while a LED test is current.
*/
if (!do_event) {
/*
* If we get here, the fcal_leds thread is only doing
* slow polls. Count down the slow_poll_count and set
* an event if it expires.
*/
if (--slow_poll_count == 0) {
}
}
if (do_event) {
c = pthread_mutex_lock(&g_mutex);
if (c != 0) {
break;
}
/*
* indicate in the event flag that this is a time event
*/
(void) pthread_cond_signal(&g_cv);
(void) pthread_mutex_unlock(&g_mutex);
}
}
/*
* if picld restarted, allow this thread to be recreated
*/
return ((void *)errno);
}
/*
* Init entry point of the plugin
* Opens and parses config file.
* and starts a new thread for polling FC-AL disk status information.
*/
static void
fcal_leds_init(void)
{
int err = 0;
return;
return;
}
g_event_flag = 0;
if (!cvAndMutexInit) {
} else {
return;
}
}
if (ledsthr_created || pollthr_created) {
/*
* so this is a restart, wake up sleeping threads
*/
if (err != 0) {
return;
}
(void) pthread_cond_broadcast(&g_cv);
(void) pthread_mutex_unlock(&g_mutex);
}
if (!ledsthr_created) {
if ((pthread_attr_init(&ledsthr_attr) != 0) ||
PTHREAD_SCOPE_SYSTEM) != 0))
return;
fcal_leds_thread, g_led_dtls)) != 0) {
mystrerror(err));
return;
}
}
if (pollthr_created == B_FALSE) {
if ((pthread_attr_init(&pollthr_attr) != 0) ||
PTHREAD_SCOPE_SYSTEM) != 0))
return;
fcal_poll_thread, g_led_dtls)) != 0) {
mystrerror(err));
return;
}
}
}
/*
* fini entry point of the plugin
*/
static void
fcal_leds_fini(void)
{
int c;
/* unregister event handlers */
/*
* it's very confusing to leave uncontrolled leds on, so clear them.
*/
if (g_led_dtls != NULL) {
int ledNo;
int diskNo;
break; /* incomplete setup */
}
diskNo++) {
}
}
}
/*
* tell other threads to stop
*/
c = pthread_mutex_lock(&g_mutex);
if (c != 0) {
} else {
(void) pthread_cond_broadcast(&g_cv);
(void) pthread_mutex_unlock(&g_mutex);
/*
* and wait for them to acknowledge
*/
while ((ledsthr_created && !g_leds_thread_ack) ||
(pollthr_created && !poll_thread_ack)) {
c = pthread_mutex_lock(&g_mutex);
if (c != 0) {
mystrerror(c));
break;
}
(void) pthread_mutex_unlock(&g_mutex);
}
}
}
/*
* remove picl nodes created by this plugin
*/
if (g_led_dtls != NULL) {
for (c = 0; c < g_led_dtls->n_disks; c++) {
/*
* remove all disk unit nodes from frutree
*/
}
/*
* remove Devices tables of references to leds
* and led State properties
*/
/*
* finally free the led details
*/
g_led_dtls = NULL;
}
}