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 (c) 2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #include <stdio.h> 28 #include <unistd.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <ctype.h> 32 #include <errno.h> 33 #include <libintl.h> 34 #include <syslog.h> 35 #include "fcal_leds.h" 36 37 /* 38 * function templates for static functions 39 */ 40 static token_t get_token(char **pptr, int lineNo, actfun_t *fun); 41 static int get_cstr(str *p_str, cstr *p_cstr_res); 42 static int get_assert(str *p_str, int *assert); 43 static int get_pnz(str *p_str, int *pnz); 44 static int get_mask(str *p_str, int n_disks, int *p_intarray); 45 46 /* 47 * Templates for functions which may be returned by get_token(). 48 * These functions are all called with a pointer to the position just 49 * beyond the token being actioned. 50 */ 51 static int act_version(str *p_str, led_dtls_t *dtls); 52 static int act_leds_board(str *p_str, led_dtls_t *dtls); 53 static int act_status_board(str *p_str, led_dtls_t *dtls); 54 static int act_disk_driver(str *p_str, led_dtls_t *dtls); 55 static int act_n_disks(str *p_str, led_dtls_t *dtls); 56 static int act_asrt_pres(str *p_str, led_dtls_t *dtls); 57 static int act_asrt_fault(str *p_str, led_dtls_t *dtls); 58 static int act_led_on(str *p_str, led_dtls_t *dtls); 59 static int act_disk_present(str *p_str, led_dtls_t *dtls); 60 static int act_disk_fault(str *p_str, led_dtls_t *dtls); 61 static int act_led_id(str *p_str, led_dtls_t *dtls); 62 static int act_slow_poll(str *p_str, led_dtls_t *dtls); 63 static int act_fast_poll(str *p_str, led_dtls_t *dtls); 64 static int act_relax_interval(str *p_str, led_dtls_t *dtls); 65 static int act_test_interval(str *p_str, led_dtls_t *dtls); 66 static int act_disk_parent(str *p_str, led_dtls_t *dtls); 67 static int act_unit_parent(str *p_str, led_dtls_t *dtls); 68 static int act_led_nodes(str *p_str, led_dtls_t *dtls); 69 70 /* 71 * The table below is used to lookup .conf file keywords to yield either 72 * a corresponding enum or a function to process the keyword. 73 */ 74 static lookup_t table[] = { 75 { FCAL_VERSION, "VERSION", act_version }, 76 { FCAL_REMOK_LED, "REMOK", NULL }, 77 { FCAL_FAULT_LED, "FAULT", NULL }, 78 { FCAL_READY_LED, "READY", NULL }, 79 { FCAL_LEDS_BOARD, "FCAL-LEDS", act_leds_board }, 80 { FCAL_STATUS_BOARD, "FCAL-STATUS", act_status_board }, 81 { FCAL_DISK_DRIVER, "FCAL-DISK-DRIVER", act_disk_driver }, 82 { FCAL_N_DISKS, "N-DISKS", act_n_disks }, 83 { FCAL_ASSERT_PRESENT, "ASSERT-PRESENT", act_asrt_pres }, 84 { FCAL_ASSERT_FAULT, "ASSERT-FAULT", act_asrt_fault }, 85 { FCAL_LED_ON, "LED-ON", act_led_on }, 86 { FCAL_DISK_PRESENT, "DISK-PRESENT", act_disk_present }, 87 { FCAL_DISK_FAULT, "DISK-FAULT", act_disk_fault }, 88 { FCAL_LED_ID, "LED", act_led_id }, 89 { FCAL_SLOW_POLL, "SLOW-POLL", act_slow_poll }, 90 { FCAL_FAST_POLL, "FAST-POLL", act_fast_poll }, 91 { FCAL_RELAX_INTERVAL, "RELAX-INTERVAL", act_relax_interval }, 92 { FCAL_TEST_INTERVAL, "LED-TEST-INTERVAL", act_test_interval }, 93 { FCAL_DISK_PARENT, "FCAL-DISK-PARENT", act_disk_parent }, 94 { FCAL_UNIT_PARENT, "DISK-UNIT-PARENT", act_unit_parent }, 95 { FCAL_LED_NODES, "DISK-LED-NODES", act_led_nodes } 96 }; 97 98 /* 99 * length of longest string in table (with space for null terminator) 100 */ 101 #define MAX_FCAL_TOKEN_LEN 18 102 103 static const int tab_len = (sizeof (table))/sizeof (table[0]); 104 105 /* 106 * get_token 107 * Parses the current line of data and returns the next token. 108 * If there are no significant characters in the line, NO_TOKEN is returned. 109 * If a syntax error is encountered, TOKEN_ERROR is returned. 110 * Pointer to position in current line is updated to point to the terminator 111 * of the token, unless TOKEN_ERROR is returned. 112 */ 113 static token_t 114 get_token( 115 char **pptr, /* pointer to pointer to position in current line */ 116 /* *ptr is updated by the function */ 117 int lineNo, /* current line number, used for syslog. If set to */ 118 /* zero, syslogging is supressed */ 119 actfun_t *fun) /* pointer to function variable to receive action */ 120 /* pointer for the token found. NULL may be returned */ 121 { 122 char *ptr; 123 char *token_start; 124 int toklen; 125 int i; 126 int ch; 127 128 *fun = NULL; 129 ptr = *pptr; 130 131 /* strip leading white space */ 132 do { 133 ch = (unsigned)(*ptr++); 134 135 } while (isspace(ch)); 136 137 if ((ch == '\0') || (ch == '#')) { 138 *pptr = ptr; 139 return (NO_TOKEN); /* empty line or comment */ 140 } 141 142 if (!isalpha(ch)) { 143 if (lineNo != 0) 144 SYSLOG(LOG_ERR, EM_NONALF_TOK, lineNo); 145 return (TOKEN_ERROR); 146 } 147 token_start = ptr - 1; 148 toklen = strcspn(token_start, ",: \t"); 149 *pptr = token_start + toklen; 150 /* 151 * got token, now look it up 152 */ 153 for (i = 0; i < tab_len; i++) { 154 if ((strncasecmp(token_start, table[i].tok_str, 155 toklen) == 0) && (table[i].tok_str[toklen] == '\0')) { 156 *fun = table[i].action; 157 return (table[i].tok); 158 } 159 } 160 if (lineNo != 0) 161 SYSLOG(LOG_ERR, EM_UNKN_TOK, lineNo); 162 return (TOKEN_ERROR); 163 } 164 165 static int 166 act_version(str *p_str, led_dtls_t *dtls) 167 { 168 dtls->ver_maj = strtoul(*p_str, p_str, 0); 169 if (*(*p_str)++ != '.') { 170 SYSLOG(LOG_ERR, EM_VER_FRMT); 171 return (-1); 172 } 173 dtls->ver_min = strtoul(*p_str, p_str, 0); 174 if ((**p_str != '\0') && !isspace(**p_str)) { 175 SYSLOG(LOG_ERR, EM_VER_FRMT); 176 return (-1); 177 } 178 if ((dtls->ver_maj != 1) || (dtls->ver_min != 0)) { 179 SYSLOG(LOG_ERR, EM_WRNGVER, dtls->ver_maj, dtls->ver_min); 180 return (-1); 181 } 182 return (0); 183 } 184 185 /* 186 * get space to hold white-space terminated string at *p_str 187 * advance *p_str to point to terminator 188 * return copy of string, null terminated 189 */ 190 static int 191 get_cstr(str *p_str, cstr *p_cstr_res) 192 { 193 int ch; 194 int len; 195 char *ptr; 196 197 while (isspace(**p_str)) 198 (*p_str)++; 199 ptr = *p_str; 200 201 do { 202 ch = *++ptr; 203 } while ((ch != '\0') && (!isspace(ch))); 204 205 len = ptr - *p_str; 206 if (*p_cstr_res != NULL) 207 free((void *)(*p_cstr_res)); 208 ptr = malloc(len + 1); 209 *p_cstr_res = ptr; 210 if (ptr == NULL) { 211 return (ENOMEM); 212 } 213 (void) memcpy(ptr, *p_str, len); 214 ptr[len] = '\0'; 215 (*p_str) += len; 216 return (0); 217 } 218 219 static int 220 act_leds_board(str *p_str, led_dtls_t *dtls) 221 { 222 int res = get_cstr(p_str, &dtls->fcal_leds); 223 if (res == 0) { 224 if (dtls->fcal_leds[0] != '/') { 225 free((void *)dtls->fcal_leds); 226 dtls->fcal_leds = NULL; 227 SYSLOG(LOG_ERR, EM_REL_PATH); 228 return (-1); 229 } 230 } 231 return (res); 232 } 233 234 static int 235 act_status_board(str *p_str, led_dtls_t *dtls) 236 { 237 int res = get_cstr(p_str, &dtls->fcal_status); 238 if (res == 0) { 239 if (dtls->fcal_status[0] != '/') { 240 free((void *)dtls->fcal_status); 241 dtls->fcal_status = NULL; 242 SYSLOG(LOG_ERR, EM_REL_PATH); 243 return (-1); 244 } 245 } 246 return (res); 247 } 248 249 static int 250 act_disk_driver(str *p_str, led_dtls_t *dtls) 251 { 252 return (get_cstr(p_str, &dtls->fcal_driver)); 253 } 254 255 static int 256 act_disk_parent(str *p_str, led_dtls_t *dtls) 257 { 258 return (get_cstr(p_str, &dtls->fcal_disk_parent)); 259 } 260 261 static int 262 act_unit_parent(str *p_str, led_dtls_t *dtls) 263 { 264 return (get_cstr(p_str, &dtls->disk_unit_parent)); 265 } 266 267 static int 268 act_led_nodes(str *p_str, led_dtls_t *dtls) 269 { 270 return (get_cstr(p_str, &dtls->disk_led_nodes)); 271 } 272 273 /* 274 * A number of fields in the led_dtls_t structure have per-disk copies. 275 * This action routine creates the space for all such fields. 276 * Following any failure, an error is returned and the calling routine 277 * must handle the fact that only a subset of these fields are populated. 278 * In practice, this function is only called by get_token() on behalf of 279 * fc_led_parse(). fc_led_parse calls free_led_dtls() after any error. 280 */ 281 static int 282 act_n_disks(str *p_str, led_dtls_t *dtls) 283 { 284 int i; 285 286 if (dtls->n_disks != 0) { 287 SYSLOG(LOG_ERR, EM_NDISKS_DBL); 288 return (-1); 289 } 290 dtls->n_disks = strtoul(*p_str, p_str, 0); 291 if ((**p_str != '\0') && !isspace(**p_str)) { 292 SYSLOG(LOG_ERR, EM_NUM_TERM); 293 return (-1); 294 } 295 if (dtls->n_disks < 1) { 296 SYSLOG(LOG_ERR, EM_NO_DISKS); 297 return (-1); 298 } 299 dtls->presence = calloc(dtls->n_disks, sizeof (int)); 300 if (dtls->presence == NULL) 301 return (ENOMEM); 302 dtls->faults = calloc(dtls->n_disks, sizeof (int)); 303 if (dtls->faults == NULL) 304 return (ENOMEM); 305 dtls->disk_detected = calloc(dtls->n_disks, sizeof (int)); 306 if (dtls->disk_detected == NULL) 307 return (ENOMEM); 308 dtls->disk_ready = calloc(dtls->n_disks, sizeof (int)); 309 if (dtls->disk_ready == NULL) 310 return (ENOMEM); 311 dtls->disk_prev = calloc(dtls->n_disks, sizeof (int)); 312 if (dtls->disk_prev == NULL) 313 return (ENOMEM); 314 dtls->led_test_end = calloc(dtls->n_disks, sizeof (int)); 315 if (dtls->led_test_end == NULL) 316 return (ENOMEM); 317 dtls->picl_retry = calloc(dtls->n_disks, sizeof (boolean_t)); 318 if (dtls->picl_retry == NULL) 319 return (ENOMEM); 320 dtls->disk_port = calloc(dtls->n_disks, sizeof (char *)); 321 if (dtls->disk_port == NULL) { 322 return (ENOMEM); 323 } 324 for (i = 0; i < FCAL_LED_CNT; i++) { 325 dtls->led_addr[i] = calloc(dtls->n_disks, sizeof (int)); 326 if (dtls->led_addr[i] == NULL) 327 return (ENOMEM); 328 dtls->led_state[i] = calloc(dtls->n_disks, 329 sizeof (led_state_t)); 330 if (dtls->led_state[i] == NULL) 331 return (ENOMEM); 332 } 333 return (0); 334 } 335 336 static int 337 get_assert(str *p_str, int *assert) 338 { 339 int i = strtoul(*p_str, p_str, 0); 340 if ((**p_str != '\0') && !isspace(**p_str)) { 341 SYSLOG(LOG_ERR, EM_NUM_TERM); 342 return (-1); 343 } 344 if ((i != 0) && (i != 1)) { 345 SYSLOG(LOG_ERR, EM_LOGIC_LVL); 346 return (-1); 347 } 348 *assert = i; 349 return (0); 350 } 351 352 static int 353 get_pnz(str *p_str, int *pnz) 354 { 355 int i = strtoul(*p_str, p_str, 0); 356 if ((**p_str != '\0') && !isspace(**p_str)) { 357 SYSLOG(LOG_ERR, EM_NUM_TERM); 358 return (-1); 359 } 360 if (i < 1) { 361 SYSLOG(LOG_ERR, EM_NOTPOS); 362 return (-1); 363 } 364 *pnz = i; 365 return (0); 366 } 367 368 static int 369 act_asrt_pres(str *p_str, led_dtls_t *dtls) 370 { 371 return (get_assert(p_str, &dtls->assert_presence)); 372 } 373 374 static int 375 act_asrt_fault(str *p_str, led_dtls_t *dtls) 376 { 377 return (get_assert(p_str, &dtls->assert_fault)); 378 } 379 380 static int 381 act_led_on(str *p_str, led_dtls_t *dtls) 382 { 383 return (get_assert(p_str, &dtls->assert_led_on)); 384 } 385 386 static int 387 get_mask(str *p_str, int n_disks, int *p_intarray) 388 { 389 int i; 390 int j = strtoul(*p_str, p_str, 0); 391 if (*(*p_str)++ != ',') { 392 SYSLOG(LOG_ERR, EM_NUM_TERM); 393 return (-1); 394 } 395 if ((j < 0) || (j > n_disks)) { 396 SYSLOG(LOG_ERR, EM_DISK_RANGE); 397 return (-1); 398 } 399 i = strtoul(*p_str, p_str, 0); 400 if ((**p_str != '\0') && !isspace(**p_str)) { 401 SYSLOG(LOG_ERR, EM_NUM_TERM); 402 return (-1); 403 } 404 p_intarray[j] = i; 405 return (0); 406 } 407 408 static int 409 act_disk_present(str *p_str, led_dtls_t *dtls) 410 { 411 return (get_mask(p_str, dtls->n_disks, dtls->presence)); 412 } 413 414 static int 415 act_disk_fault(str *p_str, led_dtls_t *dtls) 416 { 417 return (get_mask(p_str, dtls->n_disks, dtls->faults)); 418 } 419 420 static int 421 act_led_id(str *p_str, led_dtls_t *dtls) 422 { 423 token_t tok; 424 actfun_t action; 425 int i; 426 int j = strtoul(*p_str, p_str, 0); 427 428 if (*(*p_str)++ != ',') { 429 SYSLOG(LOG_ERR, EM_NUM_TERM); 430 return (-1); 431 } 432 if ((j < 0) || (j >= dtls->n_disks)) { 433 SYSLOG(LOG_ERR, EM_DISK_RANGE); 434 return (-1); 435 } 436 tok = get_token(p_str, 0, &action); 437 if ((tok <= LED_PROPS_START) || (tok >= LED_PROPS_END)) { 438 SYSLOG(LOG_ERR, EM_NO_LED_PROP); 439 return (-1); 440 } 441 if (*(*p_str)++ != ',') { 442 SYSLOG(LOG_ERR, EM_PROP_TERM); 443 return (-1); 444 } 445 i = strtoul(*p_str, p_str, 0); 446 if ((**p_str != '\0') && !isspace(**p_str)) { 447 SYSLOG(LOG_ERR, EM_NUM_TERM); 448 return (-1); 449 } 450 dtls->led_addr[tok - FCAL_REMOK_LED][j] = i; 451 return (0); 452 } 453 454 static int 455 act_slow_poll(str *p_str, led_dtls_t *dtls) 456 { 457 return (get_pnz(p_str, &dtls->slow_poll_ticks)); 458 } 459 460 static int 461 act_fast_poll(str *p_str, led_dtls_t *dtls) 462 { 463 return (get_pnz(p_str, &dtls->fast_poll)); 464 } 465 466 static int 467 act_relax_interval(str *p_str, led_dtls_t *dtls) 468 { 469 return (get_pnz(p_str, &dtls->relax_time_ticks)); 470 } 471 472 static int 473 act_test_interval(str *p_str, led_dtls_t *dtls) 474 { 475 return (get_pnz(p_str, &dtls->led_test_time)); 476 } 477 478 /* 479 * Create a led_dtls_t structure 480 * Parse configuration file and populate the led_dtls_t 481 * In the event of an error, free the structure and return an error 482 */ 483 int 484 fc_led_parse(FILE *fp, led_dtls_t **p_dtls) 485 { 486 int lineNo = 0; 487 int err = 0; 488 char linebuf[160]; 489 char *ptr; 490 led_dtls_t *dtls = calloc(1, sizeof (led_dtls_t)); 491 actfun_t action; 492 token_t tok; 493 494 *p_dtls = dtls; 495 if (dtls == NULL) { 496 return (ENOMEM); 497 } 498 dtls->ver_min = -1; /* mark as version unknown */ 499 500 while ((ptr = fgets(linebuf, sizeof (linebuf), fp)) != NULL) { 501 lineNo++; 502 tok = get_token(&ptr, lineNo, &action); 503 if (tok == NO_TOKEN) 504 continue; 505 if (tok == TOKEN_ERROR) { 506 err = -1; 507 break; 508 } 509 if (tok == FCAL_VERSION) { 510 if ((err = (*action)(&ptr, dtls)) != 0) 511 break; 512 else 513 continue; 514 } 515 if (dtls->ver_min < 0) { 516 SYSLOG(LOG_ERR, EM_NOVERS); 517 err = -1; 518 break; 519 } 520 if (tok <= LINE_DEFS) { 521 SYSLOG(LOG_ERR, EM_INVAL_TOK, lineNo); 522 err = -1; 523 break; 524 } 525 if (*ptr++ != ':') { 526 SYSLOG(LOG_ERR, EM_NOCOLON, lineNo); 527 err = -1; 528 break; 529 } 530 if ((err = (*action)(&ptr, dtls)) != 0) { 531 SYSLOG(LOG_ERR, EM_ERRLINE, lineNo); 532 break; 533 } 534 else 535 continue; 536 } 537 538 if (err == 0) { 539 err = -1; /* just in case */ 540 if (dtls->ver_min < 0) { 541 SYSLOG(LOG_ERR, EM_NOVERS); 542 } else if (dtls->n_disks == 0) { 543 SYSLOG(LOG_ERR, EM_NO_DISKS); 544 } else if (dtls->fcal_leds == NULL) { 545 SYSLOG(LOG_ERR, EM_STR_NOT_SET, "fcal-leds"); 546 } else if (dtls->fcal_status == NULL) { 547 SYSLOG(LOG_ERR, EM_STR_NOT_SET, "fcal-status"); 548 } else if (dtls->fcal_driver == NULL) { 549 SYSLOG(LOG_ERR, EM_STR_NOT_SET, "fcal-driver"); 550 } else 551 err = 0; 552 } 553 554 if (err != 0) { 555 /* 556 * clean up after error detected 557 */ 558 free_led_dtls(dtls); 559 *p_dtls = NULL; 560 return (err); 561 } 562 563 /* 564 * set any unset timers to default time 565 */ 566 if (dtls->slow_poll_ticks == 0) 567 dtls->slow_poll_ticks = DFLT_SLOW_POLL; 568 if (dtls->fast_poll == 0) 569 dtls->fast_poll = DFLT_FAST_POLL; 570 if (dtls->relax_time_ticks == 0) 571 dtls->relax_time_ticks = DFLT_RELAX_TIME; 572 if (dtls->led_test_time == 0) 573 dtls->led_test_time = DFLT_TEST_TIME; 574 575 /* 576 * set polling flag to avoid a start-up glitch 577 * it will be cleared again if the poll thread fails 578 */ 579 dtls->polling = B_TRUE; 580 581 /* 582 * convert derived timers to multiples of fast poll time 583 */ 584 dtls->slow_poll_ticks += dtls->fast_poll - 1; /* for round up */ 585 dtls->slow_poll_ticks /= dtls->fast_poll; 586 dtls->relax_time_ticks += dtls->fast_poll - 1; 587 dtls->relax_time_ticks /= dtls->fast_poll; 588 dtls->led_test_time += dtls->fast_poll - 1; 589 dtls->led_test_time /= dtls->fast_poll; 590 return (0); 591 } 592 593 void 594 free_led_dtls(led_dtls_t *dtls) 595 { 596 int i; 597 598 if (dtls == NULL) 599 return; 600 if (dtls->fcal_leds != NULL) 601 free((void *)dtls->fcal_leds); 602 if (dtls->fcal_status != NULL) 603 free((void *)dtls->fcal_status); 604 if (dtls->fcal_driver != NULL) 605 free((void *)dtls->fcal_driver); 606 if (dtls->presence != NULL) 607 free((void *)dtls->presence); 608 if (dtls->faults != NULL) 609 free((void *)dtls->faults); 610 if (dtls->disk_detected != NULL) 611 free((void *)dtls->disk_detected); 612 if (dtls->disk_ready != NULL) 613 free((void *)dtls->disk_ready); 614 if (dtls->disk_prev != NULL) 615 free((void *)dtls->disk_prev); 616 if (dtls->led_test_end != NULL) 617 free((void *)dtls->led_test_end); 618 if (dtls->picl_retry != NULL) 619 free((void *)dtls->picl_retry); 620 if (dtls->disk_port != NULL) { 621 for (i = 0; i < dtls->n_disks; i++) { 622 if (dtls->disk_port[i] != NULL) 623 free(dtls->disk_port[i]); 624 } 625 free(dtls->disk_port); 626 } 627 for (i = 0; i < FCAL_LED_CNT; i++) { 628 if (dtls->led_addr[i] != NULL) 629 free((void *)dtls->led_addr[i]); 630 if (dtls->led_state[i] != NULL) 631 free((void *)dtls->led_state[i]); 632 } 633 634 free(dtls); 635 } 636