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