piclplatmod.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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#include <pthread.h>
#include <syslog.h>
#include <picl.h>
#include <picltree.h>
#include <picldefs.h>
#include <string.h>
#include <libnvpair.h>
#include <libintl.h>
#include <librcm.h>
#include <stropts.h>
#include <smclib.h>
#include "piclenvmond.h"
#include "picldr.h"
/* local defines */
#define SHUTDOWN_CPU "/usr/sbin/shutdown -y -g 0 -i0"
#define RCM_ABSTRACT_RESOURCE "SUNW_snowbird/board0/CPU1"
#define CPU_SENSOR_GEO_ADDR 0xe
#define IS_HEALTHY 0x01
#define PICL_NODE_SYSMGMT "sysmgmt"
#define BUF_SIZE 7
/* external functions */
int (*readfn)(ptree_rarg_t *, void *),
int (*writefn)(ptree_warg_t *, const void *),
picl_nodehdl_t, picl_prophdl_t *, void *);
uint8_t);
extern void env_handle_sensor_event(void *);
extern int env_open_smc();
/* external variables */
extern int env_debug;
extern uint8_t cpu_geo_addr;
/* locals */
static char *rcm_abstr_cp2300_name = RCM_ABSTRACT_RESOURCE;
static long env_dmc_wait_time = 15;
static pthread_t dmc_thr_tid;
/*
* issue halt or reboot based on the reset_cpu flag
*/
/*ARGSUSED*/
static void
{
if (env_shutdown_system) {
if (env_reset_cpu) {
} else {
}
}
}
/*
* inform RCM framework that the remove op is successful
*/
static void
{
}
/*
* inform RCM framework that the remove op is failed
*/
static void
{
}
/*
* check RCM framework if it is ok to offline a device
*/
static int
{
int rv;
return (RCM_FAILURE);
}
if (rv == RCM_FAILURE) {
return (RCM_FAILURE);
}
if (rv == RCM_CONFLICT) {
return (RCM_CONFLICT);
}
return (RCM_SUCCESS);
}
/*
* utility routine to send response to an IPMI message
*/
static int
{
int rc = SMC_SUCCESS;
/* make a call to ctsmc lib */
(reqseq_lun & 0x03));
if (rc != SMC_SUCCESS)
return (rc);
}
/*
* do all the checks like adminlock check, rcm check and initiate
* shutdown
*/
/*ARGSUSED*/
static int
{
int rv;
if (!env_shutdown_system) {
return (-1);
}
/* check the adminlock prop */
"CPU in use! Cannot shutdown"));
return (-1);
}
if (force) {
}
/* check with rcm framework */
" shutdown"), rv);
return (-1);
}
/*
* force events on chassis node
*/
if (force) {
NO_WAIT) == PICL_SUCCESS) {
/* wait a little for clean up of frutree */
}
/*
* If force option is set, do it right here for now
* since there is no way to pass this info via events
* to frutree framework.
*/
return (0);
}
!= PICL_SUCCESS) {
"the host CPU."));
return (-1);
}
return (0);
}
/*
* get the HEALTHY# line state
* Return -1 for Error
* 0 for HEALTHY# down
* 1 for HEALTHY# up
*/
static int
{
/* initialize the request packet */
DEFAULT_SEQN, size);
/* make a call to smc library to send cmd */
POLL_TIMEOUT) != SMC_SUCCESS) {
return (-1);
}
}
/*
* initialization
*/
{
if (rooth == 0) {
return (rc);
}
}
if (chassis_nodehdl == 0) {
&chassis_nodehdl)) != PICL_SUCCESS) {
return (rc);
}
}
NO_WAIT) != PICL_SUCCESS) {
"Posting configure event for Chassis node"));
rc = PICL_FAILURE;
}
return (rc);
}
/*
* release all the resources
*/
void
{
cpu_geo_addr = 0;
(void) ptree_delete_node(sensorh);
(void) ptree_destroy_node(sensorh);
}
/*
* handle chassis state change
*/
static void
{
return;
}
if (env_chassis_state == FRU_STATE_CONFIGURING ||
/* picl intialization is failed, dont issue shutdown */
return;
}
if (env_reset_cpu) {
} else {
}
return;
}
}
}
/*
* event handler for watchdog state change event
*/
static picl_errno_t
{
char class[PICL_CLASSNAMELEN_MAX];
char value[PICL_PROPNAMELEN_MAX];
PICL_CLASSNAMELEN_MAX)) != PICL_SUCCESS) {
return (rc);
}
/* if the event is not of watchdog-timer, return */
return (PICL_INVALIDARG);
}
PICL_SUCCESS) {
return (rc);
}
/* if action is none, dont do anything */
return (PICL_SUCCESS);
}
/* update CPU condition to failed */
return (rc);
}
/* post dr ap state change event */
return (rc);
}
/*
* rotine that handles all the picl state and condition change events
*/
void
{
picl_nodehdl_t nodeh = 0;
char *value;
char result[PICL_PROPNAMELEN_MAX];
if (!ename) {
return;
}
} else {
ename);
return;
}
/* unpack the nvlist and get the information */
return;
}
return;
}
PICLEVENTARG_CONDITION, &value) != 0) {
return;
}
if (env_debug & PICLEVENTS) {
" node name");
return;
}
}
if (chassis_nodehdl == 0 && state_event) {
return;
}
}
}
return;
}
/* watchdog expiry event */
"watchdog expiry event"));
}
return;
} else {
return;
}
switch (event) {
case LOC_STATE_EMPTY:
break;
case LOC_STATE_DISCONNECTED:
if (nodeh == cpu_lnodehdl) {
(void) initiate_shutdown(B_FALSE);
}
break;
case LOC_STATE_CONNECTED:
if (nodeh != cpu_lnodehdl) {
break;
}
sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
"initialize CPU node handle %llx"), nodeh);
cpu_nodehdl = 0;
}
break;
case FRU_STATE_CONFIGURED:
if (nodeh != cpu_nodehdl) {
break;
}
PICL_READ, sizeof (status_time),
&status_time);
}
&cond_time);
}
/* if HEALTHY# is UP update the condition to "ok" */
switch (env_get_healthy_status()) {
case 0:
/* update CPU condition to failed */
break;
case 1:
/* update CPU condition to ok */
break;
case -1: /*FALLTHRU*/
default:
/* update the condition to unknown */
"reading HEALTHY# status"));
}
PICL_SUCCESS) {
"updating CPU condition, error = %d"), rc);
}
break;
case FRU_STATE_UNCONFIGURED:
(void) initiate_shutdown(B_FALSE);
}
break;
default:
break;
} /* end of switch */
}
/*
* This thread waits for dmc message to come, as it has to send
* response ACK back to DMC. Otherwise DMC may think that message
* is lost and issues poweroff on a node. So there is a chance for
* CPU to be powered off in the middle of shutdown process. If the
* DMC message didnt come, then process the local shutdown request.
*/
/*ARGSUSED*/
static void *
env_wait_for_dmc_msg(void *args)
{
(void) pthread_mutex_lock(&env_dmc_mutex);
if (env_got_dmc_msg == B_TRUE) {
(void) pthread_mutex_unlock(&env_dmc_mutex);
return (NULL);
}
/*
* wait for specified time to check if dmc sends the
* shutdown request
*/
(void) pthread_cond_timedwait(&env_dmc_cond,
&env_dmc_mutex, &to);
if (env_got_dmc_msg == B_TRUE) {
(void) pthread_mutex_unlock(&env_dmc_mutex);
return (NULL);
}
(void) pthread_mutex_unlock(&env_dmc_mutex);
(void) initiate_shutdown(B_FALSE);
return (NULL);
}
/*
* Handle the Latch open event(shutdown the node)
*/
{
/*
* create a thread to process local event after waiting for DMC CPU
* node state offline message
*/
NULL) != 0) {
"dmc thread"));
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
/*
* For Sanibel, hotswap initialization is not reqd.
*/
{
return (PICL_SUCCESS);
}
/*
* For sanibel this supoort is not required
*/
{
return (PICL_SUCCESS);
}
/*
* For sanibel this supoort is not required
*/
{
return (PICL_SUCCESS);
}
/*
* For sanibel this supoort is not required
*/
/*ARGSUSED*/
void
{
}
/*
* For sanibel this supoort is not required
*/
/*ARGSUSED*/
int
{
return (0);
}
/*
* For sanibel this supoort is not required
*/
/*ARGSUSED*/
int
{
return (0);
}
/*
*/
int
{
int rc = SMC_SUCCESS;
switch (state & 1) {
case CPU_NODE_STATE_OFFLINE:
(void) pthread_mutex_lock(&env_dmc_mutex);
(void) pthread_cond_signal(&env_dmc_cond);
(void) pthread_mutex_unlock(&env_dmc_mutex);
force_flag = B_TRUE;
} else {
}
if (initiate_shutdown(force_flag) == 0) {
return (rc);
}
} else {
return (rc);
}
}
break;
case CPU_NODE_STATE_ONLINE:
return (rc);
}
break;
default:
break;
}
return (0);
}
/*
* Handle change in state of service processor
*/
int
{
int rc = SMC_SUCCESS;
if (rq_addr != SMC_BMC_ADDR) {
return (PICL_FAILURE);
}
switch (state) {
case CPU_NODE_STATE_ONLINE:
/* Send ACK to service processor */
return (rc);
}
break;
case CPU_NODE_STATE_OFFLINE:
/* Send ACK to service processor */
return (rc);
}
break;
default:
return (rc);
}
break;
}
return (0);
}
/*
* For sanibel this supoort is not required
*/
/*ARGSUSED*/
{
return (PICL_SUCCESS);
}
/*
* create the temperature sensor nodes
*/
{
if (rooth == 0) {
return (rc);
}
}
if (platformh == 0) {
&platformh)) != PICL_SUCCESS) {
return (rc);
}
}
if (sysmgmth == 0) {
&sysmgmth)) != PICL_SUCCESS) {
return (rc);
}
}
return (rc);
}
/*
* handler for sensor event
*/
void
{
return;
}
}