xref: /titanic_50/usr/src/cmd/picl/plugins/sun4u/snowbird/frutree/piclkstat.c (revision 8682d1ef2a0960ed5a9f05b9448eaa3e68ac931f)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Implementation to get PORT nodes state and condition information
29  */
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <strings.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <stropts.h>
37 #include <locale.h>
38 #include <syslog.h>
39 #include <sys/types.h>
40 #include <sys/termios.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <kstat.h>
44 #include <signal.h>
45 #include <assert.h>
46 #include <config_admin.h>
47 
48 #include <picl.h>
49 #include "piclfrutree.h"
50 
51 #define	LINK_UP 	"link_up"
52 #define	DUPLEX		"duplex"
53 #define	IF_SPEED	"ifspeed"
54 #define	IERRORS		"ierrors"
55 #define	IPACKETS	"ipackets"
56 #define	OERRORS		"oerrors"
57 #define	OPACKETS	"opackets"
58 #define	NOCANPUT	"nocanput"
59 #define	RUNT_ERRORS	"runt_errors"
60 #define	COLLISIONS	"collisions"
61 
62 typedef int (*funcp)(kstat_ctl_t *, char *, int);
63 
64 static kstat_named_t *kstat_name_lookup(kstat_ctl_t *, char *, int, char *);
65 static int kstat_network_port_state(kstat_ctl_t *kc, char *, int);
66 static int kstat_network_port_cond(kstat_ctl_t *kc, char *, int);
67 static int serial_port_state(kstat_ctl_t *, char *, int);
68 static int serial_port_cond(kstat_ctl_t *kc, char *, int);
69 static int parallel_port_state(kstat_ctl_t *, char *, int);
70 static int parallel_port_cond(kstat_ctl_t *kc, char *, int);
71 static void		sig_alarm_handler(int);
72 
73 static funcp port_state[] = {
74 	kstat_network_port_state,
75 	serial_port_state,
76 	parallel_port_state
77 };
78 
79 static funcp port_cond[] = {
80 	kstat_network_port_cond,
81 	serial_port_cond,
82 	parallel_port_cond
83 };
84 
85 /*
86  * kstat_port_state: returns ethernet, or serial, or parallel port status
87  * 1 = up, 0 = down, anything else = unknown
88  */
89 int
kstat_port_state(frutree_port_type_t port_type,char * driver_name,int driver_instance)90 kstat_port_state(frutree_port_type_t port_type, char *driver_name,
91 	int driver_instance)
92 {
93 	int rc = -1;
94 	kstat_ctl_t	*kc = NULL;
95 
96 	switch (port_type) {
97 	case NETWORK_PORT:
98 	case SERIAL_PORT:
99 	case PARALLEL_PORT:
100 		if ((kc = kstat_open()) == NULL) {
101 			return (-1);
102 		}
103 		rc = port_state[port_type](kc, driver_name, driver_instance);
104 		kstat_close(kc);
105 		return (rc);
106 	default:
107 		return (-1);
108 	}
109 }
110 
111 /*
112  * kstat_port_cond: returns ethernet, or serial, or parallel port condition
113  */
114 int
kstat_port_cond(frutree_port_type_t port_type,char * driver_name,int driver_instance)115 kstat_port_cond(frutree_port_type_t port_type, char *driver_name,
116 	int driver_instance)
117 {
118 	int rc = -1;
119 	kstat_ctl_t	*kc = NULL;
120 	switch (port_type) {
121 	case NETWORK_PORT:
122 	case SERIAL_PORT:
123 	case PARALLEL_PORT:
124 		if ((kc = kstat_open()) == NULL) {
125 			return (-1);
126 		}
127 		rc = port_cond[port_type](kc, driver_name, driver_instance);
128 		kstat_close(kc);
129 		return (rc);
130 	default:
131 		return (-1);
132 	}
133 }
134 
135 static kstat_named_t *
kstat_name_lookup(kstat_ctl_t * kc,char * ks_module,int ks_instance,char * name)136 kstat_name_lookup(kstat_ctl_t *kc, char *ks_module, int ks_instance, char *name)
137 {
138 	kstat_t		*ksp;
139 
140 	assert(kc);
141 	assert(ks_module);
142 	assert(name);
143 
144 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
145 		if (strcmp(ksp->ks_module, ks_module) == 0 &&
146 		    ksp->ks_instance == ks_instance &&
147 		    ksp->ks_type == KSTAT_TYPE_NAMED &&
148 		    kstat_read(kc, ksp, NULL) != -1 &&
149 		    kstat_data_lookup(ksp, name)) {
150 
151 			ksp = kstat_lookup(kc, ks_module, ks_instance,
152 			    ksp->ks_name);
153 			if (!ksp)
154 				return (NULL);
155 			if (kstat_read(kc, ksp, NULL) == -1)
156 				return (NULL);
157 			return ((kstat_named_t *)kstat_data_lookup(ksp, name));
158 		}
159 	}
160 	return (NULL);
161 }
162 
163 /*
164  * kstat_network_port_state: returns kstat info of a network port
165  * 1 = up, 0 = down, anything else = unknown
166  */
167 static int
kstat_network_port_state(kstat_ctl_t * kc,char * ks_module,int ks_instance)168 kstat_network_port_state(kstat_ctl_t *kc, char *ks_module, int ks_instance)
169 {
170 	kstat_named_t	*port_datap = NULL;
171 
172 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
173 	    LINK_UP)) == NULL) {
174 		return (-1);
175 	}
176 	if (port_datap == NULL) {
177 		return (-1);
178 	}
179 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
180 		if (port_datap->value.ui32 == 1) {
181 			return (1);
182 		} else if (port_datap->value.ui32 == 0) {
183 			return (0);
184 		} else {
185 			return (-1);
186 		}
187 	} else {
188 		if (port_datap->value.ui64 == 1) {
189 			return (1);
190 		} else if (port_datap->value.ui64 == 0) {
191 			return (0);
192 		} else {
193 			return (-1);
194 		}
195 	}
196 }
197 
198 /*
199  * kstat_network_port_cond: returns kstat info of a network port
200  * 0 = OK, 1 = FAILING, 2 = FAILED, 3 = TESTING, -1 = unknown
201  */
202 static int
kstat_network_port_cond(kstat_ctl_t * kc,char * ks_module,int ks_instance)203 kstat_network_port_cond(kstat_ctl_t *kc, char *ks_module, int ks_instance)
204 {
205 	kstat_named_t	*port_datap = NULL;
206 	uint64_t	collisions, runt, link_up, link_duplex;
207 	uint64_t	ifspeed, ierrors, ipackets, oerrors, opackets;
208 
209 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
210 	    LINK_UP)) == NULL) {
211 		return (-1);
212 	}
213 
214 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
215 		link_up = port_datap->value.ui32;
216 	} else {
217 		link_up = port_datap->value.ui64;
218 	}
219 	if (link_up == 0) {
220 		return (2);
221 	}
222 
223 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
224 	    DUPLEX)) == NULL) {
225 		return (-1);
226 	}
227 
228 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
229 		link_duplex = port_datap->value.ui32;
230 	} else {
231 		link_duplex = port_datap->value.ui64;
232 	}
233 	if (link_duplex == 0) {
234 		return (2);
235 	}
236 
237 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
238 	    IF_SPEED)) == NULL) {
239 		return (-1);
240 	}
241 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
242 		ifspeed = port_datap->value.ui32;
243 	} else {
244 		ifspeed = port_datap->value.ui64;
245 	}
246 	if (ifspeed == 0) {
247 		return (2);
248 	}
249 
250 	/* check for FAILING conditions */
251 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
252 	    IERRORS)) == NULL) {
253 		return (-1);
254 	}
255 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
256 		ierrors = port_datap->value.ui32;
257 	} else {
258 		ierrors = port_datap->value.ui64;
259 	}
260 
261 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
262 	    IPACKETS)) == NULL) {
263 		return (-1);
264 	}
265 
266 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
267 		ipackets = port_datap->value.ui32;
268 	} else {
269 		ipackets = port_datap->value.ui64;
270 	}
271 	if (ierrors > ipackets/10) {
272 		return (1);
273 	}
274 
275 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
276 	    OERRORS)) == NULL) {
277 		return (-1);
278 	}
279 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
280 		oerrors = port_datap->value.ui32;
281 	} else {
282 		oerrors = port_datap->value.ui64;
283 	}
284 
285 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
286 	    OPACKETS)) == NULL) {
287 		return (-1);
288 	}
289 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
290 		opackets = port_datap->value.ui32;
291 	} else {
292 		opackets = port_datap->value.ui64;
293 	}
294 	if (oerrors > opackets/10) {
295 		return (1);
296 	}
297 
298 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
299 	    RUNT_ERRORS)) == NULL) {
300 		return (-1);
301 	}
302 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
303 		runt = port_datap->value.ui32;
304 	} else {
305 		runt = port_datap->value.ui64;
306 	}
307 	if (runt > ipackets/10) {
308 		return (1);
309 	}
310 
311 	if ((port_datap = kstat_name_lookup(kc, ks_module, ks_instance,
312 	    COLLISIONS)) == NULL) {
313 		return (-1);
314 	}
315 	if (port_datap->data_type == KSTAT_DATA_UINT32) {
316 		collisions = port_datap->value.ui32;
317 	} else {
318 		collisions = port_datap->value.ui64;
319 	}
320 	if (collisions > (opackets+ipackets)/30) {
321 		return (1);
322 	}
323 	return (0);
324 }
325 
326 /*
327  * serial_port_state: returns status a serial port
328  * 1 = up, 0 = down, anything else = unknown
329  */
330 
331 /* ARGSUSED */
332 static int
serial_port_state(kstat_ctl_t * kc,char * driver,int instance)333 serial_port_state(kstat_ctl_t *kc, char *driver, int instance)
334 {
335 	int			fd;
336 	char			device[20];
337 	struct termios		flags;
338 	struct sigaction	old_sa, new_sa;
339 
340 	(void) memset(&old_sa, 0, sizeof (old_sa));
341 	(void) memset(&new_sa, 0, sizeof (new_sa));
342 	new_sa.sa_handler = sig_alarm_handler;
343 	(void) sigaction(SIGALRM, &new_sa, &old_sa);
344 	(void) alarm(1);
345 
346 	(void) snprintf(device, sizeof (device), "/dev/tty%c", instance+'a');
347 	fd = open(device, O_RDONLY|O_NDELAY|O_NONBLOCK|O_NOCTTY);
348 
349 	/* Restore sig action flags */
350 	(void) sigaction(SIGALRM, &old_sa, (struct sigaction *)0);
351 	/* Disable alarm */
352 	(void) alarm(0);
353 
354 	if (fd == -1) {
355 		return (-1);
356 	}
357 
358 	if (isatty(fd) == 0) {
359 		(void) close(fd);
360 		return (-1);
361 	}
362 	(void) memset(&flags, 0, sizeof (flags));
363 	if (ioctl(fd, TCGETS, &flags) != 0) {
364 		(void) close(fd);
365 		return (-1);
366 	}
367 	(void) close(fd);
368 	return ((flags.c_cflag & TIOCM_LE) ? 1 : 0);
369 }
370 
371 /* ARGSUSED */
372 static void
sig_alarm_handler(int signo)373 sig_alarm_handler(int signo)
374 {
375 }
376 
377 /*
378  * serial_port_cond: returns status of a serial port
379  * 0 = OK, 1 = FAILING, 2 = FAILED, 3 = TESTING, anything else = UNKNOWN
380  */
381 static int
serial_port_cond(kstat_ctl_t * kc,char * driver,int instance)382 serial_port_cond(kstat_ctl_t *kc, char *driver, int instance)
383 {
384 	switch (serial_port_state(kc, driver, instance)) {
385 	case 1:
386 		return (0);
387 	default:
388 		return (-1);
389 	}
390 }
391 
392 /*
393  * parallel_port_state: returns kstat info of a serial port
394  * 1 = up, 0 = down, anything else = unknown
395  */
396 static int
parallel_port_state(kstat_ctl_t * kc,char * ks_module,int ks_instance)397 parallel_port_state(kstat_ctl_t *kc, char *ks_module, int ks_instance)
398 {
399 	kstat_t		*ksp = NULL;
400 	kstat_named_t	*port_datap = NULL;
401 	char		*data_lookup;
402 	char		ks_name[20];
403 
404 	(void) snprintf(ks_name, sizeof (ks_name), "%s%d", ks_module,
405 	    ks_instance);
406 	if ((ksp = kstat_lookup(kc, ks_module, ks_instance, ks_name)) == NULL) {
407 		return (-1);
408 	}
409 	if (kstat_read(kc, ksp, NULL) == -1) {
410 		return (-1);
411 	}
412 	data_lookup = "";
413 	port_datap = (kstat_named_t *)kstat_data_lookup(ksp, data_lookup);
414 	if (port_datap == NULL) {
415 		return (-1);
416 	}
417 	return (-1);
418 }
419 
420 /*
421  * parallel_port_cond: returns kstat info of a serial port
422  * 1 = up, 0 = down, anything else = unknown
423  */
424 static int
parallel_port_cond(kstat_ctl_t * kc,char * ks_module,int ks_instance)425 parallel_port_cond(kstat_ctl_t *kc, char *ks_module, int ks_instance)
426 {
427 	return (parallel_port_state(kc, ks_module, ks_instance));
428 }
429