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