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 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 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 * 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 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 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 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 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 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 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 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 }