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