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