OpenSolaris_b135/lib/libtsalarm/common/tsalarm.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Telco-alarm library, which communicates through libpcp to set/get
 * alarms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <libpcp.h>

#include "tsalarm.h"

/* Message Types */
#define	TSALARM_CONTROL		15
#define	TSALARM_CONTROL_R	16

#define	TSALARM_CHANNEL_TIMEOUT	20
#define	TSALARM_MAX_RETRIES	3
#define	TSALARM_SERVICE_NAME	"SUNW,sun4v-telco-alarm"

int
tsalarm_get(uint32_t alarm_type, uint32_t *alarm_state)
{
	int		chnl_fd;
	tsalarm_req_t	*req_ptr = NULL;
	tsalarm_resp_t	*resp_ptr = NULL;
	pcp_msg_t	send_msg;
	pcp_msg_t	recv_msg;
	int		rc = TSALARM_SUCCESS;
	int		retries;

	/* initialize virtual channel */
	for (retries = 1; retries <= TSALARM_MAX_RETRIES; retries++) {
		if ((chnl_fd = pcp_init(TSALARM_SERVICE_NAME)) < 0) {
			if (retries == TSALARM_MAX_RETRIES) {
				rc = TSALARM_CHANNEL_INIT_FAILURE;
				goto cleanup;
			}
			(void) sleep(TSALARM_CHANNEL_TIMEOUT);
		} else
			break;
	}

	/* create request message data */
	req_ptr = malloc(sizeof (tsalarm_req_t));
	if (req_ptr == NULL) {
		rc = TSALARM_NULL_REQ_DATA;
		goto cleanup;
	}
	req_ptr->alarm_action = TSALARM_STATUS;
	req_ptr->alarm_id = alarm_type;

	send_msg.msg_type = TSALARM_CONTROL;
	send_msg.sub_type = NULL;
	send_msg.msg_len = sizeof (tsalarm_req_t);
	send_msg.msg_data = (uint8_t *)req_ptr;

	/*
	 * Send the request and receive the response.
	 */
	if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
	    TSALARM_CHANNEL_TIMEOUT) < 0) {
		/* we either timed out or erred; either way try again */
		(void) sleep(TSALARM_CHANNEL_TIMEOUT);

		if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
		    TSALARM_CHANNEL_TIMEOUT) < 0) {
			rc = TSALARM_COMM_FAILURE;
			goto cleanup;
		}
	}

	/*
	 * validate that this data was meant for us
	 */
	if (recv_msg.msg_type != TSALARM_CONTROL_R) {
		rc = TSALARM_UNBOUND_PACKET_RECVD;
		goto cleanup;
	}

	/*
	 * verify that the Alarm action has taken place
	 */
	if ((resp_ptr = (tsalarm_resp_t *)recv_msg.msg_data) == NULL)
		goto cleanup;

	if (resp_ptr->status == TSALARM_ERROR) {
		rc = TSALARM_GET_ERROR;
		goto cleanup;
	}

	if (resp_ptr->alarm_state == TSALARM_STATE_UNKNOWN) {
		rc = TSALARM_GET_ERROR;
		goto cleanup;
	}

	*alarm_state = resp_ptr->alarm_state;

cleanup:
	if (req_ptr != NULL)
		free(req_ptr);
	if (recv_msg.msg_data != NULL)
		free(recv_msg.msg_data);

	/* close virtual channel fd */
	(void) pcp_close(chnl_fd);

	return (rc);
}

int
tsalarm_set(uint32_t alarm_type, uint32_t alarm_state)
{
	int		chnl_fd;
	tsalarm_req_t   *req_ptr = NULL;
	tsalarm_resp_t  *resp_ptr = NULL;
	pcp_msg_t	send_msg;
	pcp_msg_t	recv_msg;
	int		rc = TSALARM_SUCCESS;
	int		retries;

	/* initialize virtual channel */
	for (retries = 1; retries <= TSALARM_MAX_RETRIES; retries++) {
		if ((chnl_fd = pcp_init(TSALARM_SERVICE_NAME)) < 0) {
			if (retries == TSALARM_MAX_RETRIES) {
				rc = TSALARM_CHANNEL_INIT_FAILURE;
				goto cleanup;
			}
			(void) sleep(TSALARM_CHANNEL_TIMEOUT);
		} else
			break;
	}

	/* create request message data */
	req_ptr = malloc(sizeof (tsalarm_req_t));
	if (req_ptr == NULL) {
		rc = TSALARM_NULL_REQ_DATA;
		goto cleanup;
	}
	req_ptr->alarm_id = alarm_type;
	if (alarm_state == TSALARM_STATE_ON)
		req_ptr->alarm_action = TSALARM_ENABLE;
	else if (alarm_state == TSALARM_STATE_OFF)
		req_ptr->alarm_action = TSALARM_DISABLE;

	send_msg.msg_type = TSALARM_CONTROL;
	send_msg.sub_type = NULL;
	send_msg.msg_len = sizeof (tsalarm_req_t);
	send_msg.msg_data = (uint8_t *)req_ptr;

	/*
	 * Send the request and receive the response.
	 */
	if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
	    TSALARM_CHANNEL_TIMEOUT) < 0) {
		/* we either timed out or erred; either way try again */
		(void) sleep(TSALARM_CHANNEL_TIMEOUT);

		if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
		    TSALARM_CHANNEL_TIMEOUT) < 0) {
			rc = TSALARM_COMM_FAILURE;
			goto cleanup;
		}
	}

	/*
	 * validate that this data was meant for us
	 */
	if (recv_msg.msg_type != TSALARM_CONTROL_R) {
		rc = TSALARM_UNBOUND_PACKET_RECVD;
		goto cleanup;
	}

	/*
	 * verify that the Alarm action has taken place
	 */
	if ((resp_ptr = (tsalarm_resp_t *)recv_msg.msg_data) == NULL)
		goto cleanup;

	if (resp_ptr->status == TSALARM_ERROR) {
		rc = TSALARM_SET_ERROR;
		goto cleanup;
	}

	/*
	 * ensure the Alarm action taken is the one requested
	 */
	if ((req_ptr->alarm_action == TSALARM_DISABLE) &&
	    (resp_ptr->alarm_state != TSALARM_STATE_OFF)) {
		rc = TSALARM_SET_ERROR;
		goto cleanup;
	} else if ((req_ptr->alarm_action == TSALARM_ENABLE) &&
	    (resp_ptr->alarm_state != TSALARM_STATE_ON)) {
		rc = TSALARM_SET_ERROR;
		goto cleanup;
	} else if (resp_ptr->alarm_state == TSALARM_STATE_UNKNOWN) {
		rc = TSALARM_SET_ERROR;
		goto cleanup;
	}

cleanup:
	if (req_ptr != NULL)
		free(req_ptr);
	if (recv_msg.msg_data != NULL)
		free(recv_msg.msg_data);

	/* close virtual channel fd */
	(void) pcp_close(chnl_fd);

	return (rc);
}