xref: /illumos-gate/usr/src/lib/libtsalarm/common/tsalarm.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Telco-alarm library, which communicates through libpcp to set/get
28  * alarms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <libpcp.h>
38 
39 #include "tsalarm.h"
40 
41 /* Message Types */
42 #define	TSALARM_CONTROL		15
43 #define	TSALARM_CONTROL_R	16
44 
45 #define	TSALARM_CHANNEL_TIMEOUT	20
46 #define	TSALARM_MAX_RETRIES	3
47 #define	TSALARM_SERVICE_NAME	"SUNW,sun4v-telco-alarm"
48 
49 int
50 tsalarm_get(uint32_t alarm_type, uint32_t *alarm_state)
51 {
52 	int		chnl_fd;
53 	tsalarm_req_t	*req_ptr = NULL;
54 	tsalarm_resp_t	*resp_ptr = NULL;
55 	pcp_msg_t	send_msg;
56 	pcp_msg_t	recv_msg;
57 	int		rc = TSALARM_SUCCESS;
58 	int		retries;
59 
60 	/* initialize virtual channel */
61 	for (retries = 1; retries <= TSALARM_MAX_RETRIES; retries++) {
62 		if ((chnl_fd = pcp_init(TSALARM_SERVICE_NAME)) < 0) {
63 			if (retries == TSALARM_MAX_RETRIES) {
64 				rc = TSALARM_CHANNEL_INIT_FAILURE;
65 				goto cleanup;
66 			}
67 			(void) sleep(TSALARM_CHANNEL_TIMEOUT);
68 		} else
69 			break;
70 	}
71 
72 	/* create request message data */
73 	req_ptr = malloc(sizeof (tsalarm_req_t));
74 	if (req_ptr == NULL) {
75 		rc = TSALARM_NULL_REQ_DATA;
76 		goto cleanup;
77 	}
78 	req_ptr->alarm_action = TSALARM_STATUS;
79 	req_ptr->alarm_id = alarm_type;
80 
81 	send_msg.msg_type = TSALARM_CONTROL;
82 	send_msg.sub_type = NULL;
83 	send_msg.msg_len = sizeof (tsalarm_req_t);
84 	send_msg.msg_data = (uint8_t *)req_ptr;
85 
86 	/*
87 	 * Send the request and receive the response.
88 	 */
89 	if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
90 	    TSALARM_CHANNEL_TIMEOUT) < 0) {
91 		/* we either timed out or erred; either way try again */
92 		(void) sleep(TSALARM_CHANNEL_TIMEOUT);
93 
94 		if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
95 		    TSALARM_CHANNEL_TIMEOUT) < 0) {
96 			rc = TSALARM_COMM_FAILURE;
97 			goto cleanup;
98 		}
99 	}
100 
101 	/*
102 	 * validate that this data was meant for us
103 	 */
104 	if (recv_msg.msg_type != TSALARM_CONTROL_R) {
105 		rc = TSALARM_UNBOUND_PACKET_RECVD;
106 		goto cleanup;
107 	}
108 
109 	/*
110 	 * verify that the Alarm action has taken place
111 	 */
112 	if ((resp_ptr = (tsalarm_resp_t *)recv_msg.msg_data) == NULL)
113 		goto cleanup;
114 
115 	if (resp_ptr->status == TSALARM_ERROR) {
116 		rc = TSALARM_GET_ERROR;
117 		goto cleanup;
118 	}
119 
120 	if (resp_ptr->alarm_state == TSALARM_STATE_UNKNOWN) {
121 		rc = TSALARM_GET_ERROR;
122 		goto cleanup;
123 	}
124 
125 	*alarm_state = resp_ptr->alarm_state;
126 
127 cleanup:
128 	if (req_ptr != NULL)
129 		free(req_ptr);
130 	if (recv_msg.msg_data != NULL)
131 		free(recv_msg.msg_data);
132 
133 	/* close virtual channel fd */
134 	(void) pcp_close(chnl_fd);
135 
136 	return (rc);
137 }
138 
139 int
140 tsalarm_set(uint32_t alarm_type, uint32_t alarm_state)
141 {
142 	int		chnl_fd;
143 	tsalarm_req_t   *req_ptr = NULL;
144 	tsalarm_resp_t  *resp_ptr = NULL;
145 	pcp_msg_t	send_msg;
146 	pcp_msg_t	recv_msg;
147 	int		rc = TSALARM_SUCCESS;
148 	int		retries;
149 
150 	/* initialize virtual channel */
151 	for (retries = 1; retries <= TSALARM_MAX_RETRIES; retries++) {
152 		if ((chnl_fd = pcp_init(TSALARM_SERVICE_NAME)) < 0) {
153 			if (retries == TSALARM_MAX_RETRIES) {
154 				rc = TSALARM_CHANNEL_INIT_FAILURE;
155 				goto cleanup;
156 			}
157 			(void) sleep(TSALARM_CHANNEL_TIMEOUT);
158 		} else
159 			break;
160 	}
161 
162 	/* create request message data */
163 	req_ptr = malloc(sizeof (tsalarm_req_t));
164 	if (req_ptr == NULL) {
165 		rc = TSALARM_NULL_REQ_DATA;
166 		goto cleanup;
167 	}
168 	req_ptr->alarm_id = alarm_type;
169 	if (alarm_state == TSALARM_STATE_ON)
170 		req_ptr->alarm_action = TSALARM_ENABLE;
171 	else if (alarm_state == TSALARM_STATE_OFF)
172 		req_ptr->alarm_action = TSALARM_DISABLE;
173 
174 	send_msg.msg_type = TSALARM_CONTROL;
175 	send_msg.sub_type = NULL;
176 	send_msg.msg_len = sizeof (tsalarm_req_t);
177 	send_msg.msg_data = (uint8_t *)req_ptr;
178 
179 	/*
180 	 * Send the request and receive the response.
181 	 */
182 	if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
183 	    TSALARM_CHANNEL_TIMEOUT) < 0) {
184 		/* we either timed out or erred; either way try again */
185 		(void) sleep(TSALARM_CHANNEL_TIMEOUT);
186 
187 		if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
188 		    TSALARM_CHANNEL_TIMEOUT) < 0) {
189 			rc = TSALARM_COMM_FAILURE;
190 			goto cleanup;
191 		}
192 	}
193 
194 	/*
195 	 * validate that this data was meant for us
196 	 */
197 	if (recv_msg.msg_type != TSALARM_CONTROL_R) {
198 		rc = TSALARM_UNBOUND_PACKET_RECVD;
199 		goto cleanup;
200 	}
201 
202 	/*
203 	 * verify that the Alarm action has taken place
204 	 */
205 	if ((resp_ptr = (tsalarm_resp_t *)recv_msg.msg_data) == NULL)
206 		goto cleanup;
207 
208 	if (resp_ptr->status == TSALARM_ERROR) {
209 		rc = TSALARM_SET_ERROR;
210 		goto cleanup;
211 	}
212 
213 	/*
214 	 * ensure the Alarm action taken is the one requested
215 	 */
216 	if ((req_ptr->alarm_action == TSALARM_DISABLE) &&
217 	    (resp_ptr->alarm_state != TSALARM_STATE_OFF)) {
218 		rc = TSALARM_SET_ERROR;
219 		goto cleanup;
220 	} else if ((req_ptr->alarm_action == TSALARM_ENABLE) &&
221 	    (resp_ptr->alarm_state != TSALARM_STATE_ON)) {
222 		rc = TSALARM_SET_ERROR;
223 		goto cleanup;
224 	} else if (resp_ptr->alarm_state == TSALARM_STATE_UNKNOWN) {
225 		rc = TSALARM_SET_ERROR;
226 		goto cleanup;
227 	}
228 
229 cleanup:
230 	if (req_ptr != NULL)
231 		free(req_ptr);
232 	if (recv_msg.msg_data != NULL)
233 		free(recv_msg.msg_data);
234 
235 	/* close virtual channel fd */
236 	(void) pcp_close(chnl_fd);
237 
238 	return (rc);
239 }
240