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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Telco-alarm library, which communicates through libpcp to set/get
27  * alarms.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <libpcp.h>
35 
36 #include "tsalarm.h"
37 
38 /* Message Types */
39 #define	TSALARM_CONTROL		15
40 #define	TSALARM_CONTROL_R	16
41 
42 #define	TSALARM_CHANNEL_TIMEOUT	20
43 #define	TSALARM_MAX_RETRIES	3
44 #define	TSALARM_SERVICE_NAME	"SUNW,sun4v-telco-alarm"
45 
46 int
tsalarm_get(uint32_t alarm_type,uint32_t * alarm_state)47 tsalarm_get(uint32_t alarm_type, uint32_t *alarm_state)
48 {
49 	int		chnl_fd;
50 	tsalarm_req_t	*req_ptr = NULL;
51 	tsalarm_resp_t	*resp_ptr = NULL;
52 	pcp_msg_t	send_msg;
53 	pcp_msg_t	recv_msg;
54 	int		rc = TSALARM_SUCCESS;
55 	int		retries;
56 
57 	/* initialize virtual channel */
58 	for (retries = 1; retries <= TSALARM_MAX_RETRIES; retries++) {
59 		if ((chnl_fd = pcp_init(TSALARM_SERVICE_NAME)) < 0) {
60 			if (retries == TSALARM_MAX_RETRIES) {
61 				rc = TSALARM_CHANNEL_INIT_FAILURE;
62 				goto cleanup;
63 			}
64 			(void) sleep(TSALARM_CHANNEL_TIMEOUT);
65 		} else
66 			break;
67 	}
68 
69 	/* create request message data */
70 	req_ptr = malloc(sizeof (tsalarm_req_t));
71 	if (req_ptr == NULL) {
72 		rc = TSALARM_NULL_REQ_DATA;
73 		goto cleanup;
74 	}
75 	req_ptr->alarm_action = TSALARM_STATUS;
76 	req_ptr->alarm_id = alarm_type;
77 
78 	send_msg.msg_type = TSALARM_CONTROL;
79 	send_msg.sub_type = 0;
80 	send_msg.msg_len = sizeof (tsalarm_req_t);
81 	send_msg.msg_data = (uint8_t *)req_ptr;
82 
83 	/*
84 	 * Send the request and receive the response.
85 	 */
86 	if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
87 	    TSALARM_CHANNEL_TIMEOUT) < 0) {
88 		/* we either timed out or erred; either way try again */
89 		(void) sleep(TSALARM_CHANNEL_TIMEOUT);
90 
91 		if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
92 		    TSALARM_CHANNEL_TIMEOUT) < 0) {
93 			rc = TSALARM_COMM_FAILURE;
94 			goto cleanup;
95 		}
96 	}
97 
98 	/*
99 	 * verify that the Alarm action has taken place
100 	 */
101 	if ((resp_ptr = (tsalarm_resp_t *)recv_msg.msg_data) == NULL)
102 		goto cleanup;
103 
104 	/*
105 	 * validate that this data was meant for us
106 	 */
107 	if (recv_msg.msg_type != TSALARM_CONTROL_R) {
108 		rc = TSALARM_UNBOUND_PACKET_RECVD;
109 		goto cleanup;
110 	}
111 
112 	if (resp_ptr->status == TSALARM_ERROR) {
113 		rc = TSALARM_GET_ERROR;
114 		goto cleanup;
115 	}
116 
117 	if (resp_ptr->alarm_state == TSALARM_STATE_UNKNOWN) {
118 		rc = TSALARM_GET_ERROR;
119 		goto cleanup;
120 	}
121 
122 	*alarm_state = resp_ptr->alarm_state;
123 
124 cleanup:
125 	if (req_ptr != NULL)
126 		free(req_ptr);
127 
128 	/* free recv_msg.msg_data through pointer to make sure it is valid */
129 	if (resp_ptr != NULL)
130 		free(resp_ptr);
131 
132 	/* close virtual channel fd */
133 	(void) pcp_close(chnl_fd);
134 
135 	return (rc);
136 }
137 
138 int
tsalarm_set(uint32_t alarm_type,uint32_t alarm_state)139 tsalarm_set(uint32_t alarm_type, uint32_t alarm_state)
140 {
141 	int		chnl_fd;
142 	tsalarm_req_t   *req_ptr = NULL;
143 	tsalarm_resp_t  *resp_ptr = NULL;
144 	pcp_msg_t	send_msg;
145 	pcp_msg_t	recv_msg;
146 	int		rc = TSALARM_SUCCESS;
147 	int		retries;
148 
149 	/* initialize virtual channel */
150 	for (retries = 1; retries <= TSALARM_MAX_RETRIES; retries++) {
151 		if ((chnl_fd = pcp_init(TSALARM_SERVICE_NAME)) < 0) {
152 			if (retries == TSALARM_MAX_RETRIES) {
153 				rc = TSALARM_CHANNEL_INIT_FAILURE;
154 				goto cleanup;
155 			}
156 			(void) sleep(TSALARM_CHANNEL_TIMEOUT);
157 		} else
158 			break;
159 	}
160 
161 	/* create request message data */
162 	req_ptr = malloc(sizeof (tsalarm_req_t));
163 	if (req_ptr == NULL) {
164 		rc = TSALARM_NULL_REQ_DATA;
165 		goto cleanup;
166 	}
167 	req_ptr->alarm_id = alarm_type;
168 	if (alarm_state == TSALARM_STATE_ON)
169 		req_ptr->alarm_action = TSALARM_ENABLE;
170 	else if (alarm_state == TSALARM_STATE_OFF)
171 		req_ptr->alarm_action = TSALARM_DISABLE;
172 
173 	send_msg.msg_type = TSALARM_CONTROL;
174 	send_msg.sub_type = 0;
175 	send_msg.msg_len = sizeof (tsalarm_req_t);
176 	send_msg.msg_data = (uint8_t *)req_ptr;
177 
178 	/*
179 	 * Send the request and receive the response.
180 	 */
181 	if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
182 	    TSALARM_CHANNEL_TIMEOUT) < 0) {
183 		/* we either timed out or erred; either way try again */
184 		(void) sleep(TSALARM_CHANNEL_TIMEOUT);
185 
186 		if (pcp_send_recv(chnl_fd, &send_msg, &recv_msg,
187 		    TSALARM_CHANNEL_TIMEOUT) < 0) {
188 			rc = TSALARM_COMM_FAILURE;
189 			goto cleanup;
190 		}
191 	}
192 
193 	/*
194 	 * verify that the Alarm action has taken place
195 	 */
196 	if ((resp_ptr = (tsalarm_resp_t *)recv_msg.msg_data) == NULL)
197 		goto cleanup;
198 
199 	/*
200 	 * validate that this data was meant for us
201 	 */
202 	if (recv_msg.msg_type != TSALARM_CONTROL_R) {
203 		rc = TSALARM_UNBOUND_PACKET_RECVD;
204 		goto cleanup;
205 	}
206 
207 	if (resp_ptr->status == TSALARM_ERROR) {
208 		rc = TSALARM_SET_ERROR;
209 		goto cleanup;
210 	}
211 
212 	/*
213 	 * ensure the Alarm action taken is the one requested
214 	 */
215 	if ((req_ptr->alarm_action == TSALARM_DISABLE) &&
216 	    (resp_ptr->alarm_state != TSALARM_STATE_OFF)) {
217 		rc = TSALARM_SET_ERROR;
218 		goto cleanup;
219 	} else if ((req_ptr->alarm_action == TSALARM_ENABLE) &&
220 	    (resp_ptr->alarm_state != TSALARM_STATE_ON)) {
221 		rc = TSALARM_SET_ERROR;
222 		goto cleanup;
223 	} else if (resp_ptr->alarm_state == TSALARM_STATE_UNKNOWN) {
224 		rc = TSALARM_SET_ERROR;
225 		goto cleanup;
226 	}
227 
228 cleanup:
229 	if (req_ptr != NULL)
230 		free(req_ptr);
231 
232 	/* free recv_msg.msg_data through pointer to make sure it is valid */
233 	if (resp_ptr != NULL)
234 		free(resp_ptr);
235 
236 	/* close virtual channel fd */
237 	(void) pcp_close(chnl_fd);
238 
239 	return (rc);
240 }
241