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 * Plugin Library for PCI Hot-Plug Controller 31 */ 32 33 #include <stddef.h> 34 #include <locale.h> 35 #include <ctype.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <fcntl.h> 40 #include <unistd.h> 41 #include <errno.h> 42 #include <locale.h> 43 #include <langinfo.h> 44 #include <time.h> 45 #include <sys/param.h> 46 #include <stdarg.h> 47 #include <libdevinfo.h> 48 #include <libdevice.h> 49 50 #define CFGA_PLUGIN_LIB 51 52 #include <config_admin.h> 53 54 #include <sys/types.h> 55 #include <sys/stat.h> 56 #include <sys/ioctl.h> 57 #include <sys/dditypes.h> 58 #include <sys/devctl.h> 59 #include <sys/modctl.h> 60 #include <sys/hotplug/hpctrl.h> 61 #include <sys/pci.h> 62 #include <libintl.h> 63 64 #include <dirent.h> 65 #include <limits.h> 66 #include <sys/mkdev.h> 67 #include <librcm.h> 68 69 /* 70 * Set the version number 71 */ 72 int cfga_version = CFGA_HSL_V2; 73 74 #ifdef DEBUG 75 #define PCIHP_DBG 1 76 #endif 77 78 #if !defined(TEXT_DOMAIN) 79 #define TEXT_DOMAIN "SYS_TEST" 80 #endif 81 82 /* 83 * DEBUGING LEVEL 84 * 85 * External routines: 1 - 2 86 * Internal routines: 3 - 4 87 */ 88 #ifdef PCIHP_DBG 89 int pcihp_debug = 1; 90 #define DBG(level, args) \ 91 { if (pcihp_debug >= (level)) printf args; } 92 #define DBG_F(level, args) \ 93 { if (pcihp_debug >= (level)) fprintf args; } 94 #else 95 #define DBG(level, args) /* nothing */ 96 #define DBG_F(level, args) /* nothing */ 97 #endif 98 99 #define CMD_ACQUIRE 0 100 #define CMD_GETSTAT 1 101 #define CMD_LIST 2 102 #define CMD_SLOT_CONNECT 3 103 #define CMD_SLOT_DISCONNECT 4 104 #define CMD_SLOT_CONFIGURE 5 105 #define CMD_SLOT_UNCONFIGURE 6 106 #define CMD_SLOT_INSERT 7 107 #define CMD_SLOT_REMOVE 8 108 #define CMD_OPEN 9 109 #define CMD_FSTAT 10 110 #define ERR_CMD_INVAL 11 111 #define ERR_AP_INVAL 12 112 #define ERR_AP_ERR 13 113 #define ERR_OPT_INVAL 14 114 115 static char * 116 cfga_errstrs[] = { 117 /* n */ "acquire ", 118 /* n */ "get-status ", 119 /* n */ "list ", 120 /* n */ "connect ", 121 /* n */ "disconnect ", 122 /* n */ "configure ", 123 /* n */ "unconfigure ", 124 /* n */ "insert ", 125 /* n */ "remove ", 126 /* n */ "open ", 127 /* n */ "fstat ", 128 /* y */ "invalid command ", 129 /* y */ "invalid attachment point ", 130 /* y */ "invalid transition ", 131 /* y */ "invalid option ", 132 NULL 133 }; 134 135 #define HELP_HEADER 1 136 #define HELP_CONFIG 2 137 #define HELP_ENABLE_SLOT 3 138 #define HELP_DISABLE_SLOT 4 139 #define HELP_ENABLE_AUTOCONF 5 140 #define HELP_DISABLE_AUTOCONF 6 141 #define HELP_LED_CNTRL 7 142 #define HELP_UNKNOWN 8 143 #define SUCCESS 9 144 #define FAILED 10 145 #define UNKNOWN 11 146 147 #define MAXLINE 256 148 149 /* for type string assembly in get_type() */ 150 #define TPCT(s) (void) strlcat(buf, (s), CFGA_TYPE_LEN) 151 152 extern int errno; 153 154 static void cfga_err(char **errstring, ...); 155 static cfga_err_t fix_ap_name(char *ap_log_id, const char *ap_id, 156 char *slot_name, char **errstring); 157 static void build_control_data(struct hpc_control_data *iocdata, uint_t cmd, 158 void *retdata); 159 static cfga_err_t check_options(const char *options); 160 static void cfga_msg(struct cfga_msg *msgp, const char *str); 161 162 static char * 163 cfga_strs[] = { 164 NULL, 165 "\nPCI hotplug specific commands:", 166 "\t-c [connect|disconnect|configure|unconfigure|insert|remove] " 167 "ap_id [ap_id...]", 168 "\t-x enable_slot ap_id [ap_id...]", 169 "\t-x disable_slot ap_id [ap_id...]", 170 "\t-x enable_autoconfig ap_id [ap_id...]", 171 "\t-x disable_autoconfig ap_id [ap_id...]", 172 "\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]", 173 "\tunknown command or option: ", 174 "success ", 175 "failed ", 176 "unknown", 177 NULL 178 }; 179 180 #define MAX_FORMAT 80 181 182 /* 183 * PCI CLASS CODE/SUBCLASS CODE 184 */ 185 186 187 /* 188 * when adding subclasses, update this to the max number of strings 189 * and pad the rest of them out to that length with "unknown" 190 * this type string may not exceed 7 characters since it, the / delimiter 191 * and the board capabilities must all fit into CFGA_TYPE_LEN 192 */ 193 194 #define PCISO_MAX_SUBCLASS 9 195 196 static char * 197 pci_masstrg [] = { 198 /* n */ "scsi", 199 /* n */ "ide", 200 /* n */ "flpydis", 201 /* n */ "ipi", 202 /* n */ "raid", 203 /* n */ "unknown", 204 /* n */ "unknown", 205 /* n */ "unknown", 206 /* n */ "unknown", 207 /* n */ "unknown", 208 /* n */ NULL 209 }; 210 211 static char * 212 pci_network [] = { 213 /* n */ "etherne", 214 /* n */ "tokenrg", 215 /* n */ "fddi", 216 /* n */ "atm", 217 /* n */ "isdn", 218 /* n */ "unknown", 219 /* n */ "mcd", 220 /* n */ "unknown", 221 /* n */ "unknown", 222 /* n */ "unknown", 223 /* n */ NULL 224 }; 225 226 static char * 227 pci_display [] = { 228 /* n */ "vgs8514", 229 /* n */ "xga", 230 /* n */ "3d", 231 /* n */ "unknown", 232 /* n */ "unknown", 233 /* n */ "unknown", 234 /* n */ "unknown", 235 /* n */ "unknown", 236 /* n */ "unknown", 237 /* n */ "unknown", 238 /* n */ NULL 239 }; 240 241 static char * 242 pci_multimd [] = { 243 /* n */ "video", 244 /* n */ "audio", 245 /* n */ "teleph", 246 /* n */ "unknown", 247 /* n */ "unknown", 248 /* n */ "unknown", 249 /* n */ "unknown", 250 /* n */ "unknown", 251 /* n */ "unknown", 252 /* n */ "unknown", 253 /* n */ NULL 254 }; 255 256 static char * 257 pci_memory [] = { 258 /* n */ "ram", 259 /* n */ "flash", 260 /* n */ "unknown", 261 /* n */ "unknown", 262 /* n */ "unknown", 263 /* n */ "unknown", 264 /* n */ "unknown", 265 /* n */ "unknown", 266 /* n */ "unknown", 267 /* n */ "unknown", 268 /* n */ NULL 269 }; 270 271 static char * 272 pci_bridge [] = { 273 /* n */ "hostpci", 274 /* n */ "pci-isa", 275 /* n */ "pcieisa", 276 /* n */ "pci-mca", 277 /* n */ "pci-pci", 278 /* n */ "pcipcmc", 279 /* n */ "pcinubu", 280 /* n */ "pcicard", 281 /* n */ "pcirace", 282 /* n */ "stpci", 283 /* n */ NULL 284 }; 285 286 static char * 287 pci_comm [] = { 288 /* n */ "serial", 289 /* n */ "paralle", 290 /* n */ "multise", 291 /* n */ "modem", 292 /* n */ "unknown", 293 /* n */ "unknown", 294 /* n */ "unknown", 295 /* n */ "unknown", 296 /* n */ "unknown", 297 /* n */ "unknown", 298 /* n */ NULL 299 }; 300 301 static char * 302 pci_periph [] = { 303 /* n */ "pic", 304 /* n */ "dma", 305 /* n */ "timer", 306 /* n */ "rtc", 307 /* n */ "unknown", 308 /* n */ "unknown", 309 /* n */ "unknown", 310 /* n */ "unknown", 311 /* n */ "unknown", 312 /* n */ "unknown", 313 /* n */ NULL 314 }; 315 316 static char * 317 pci_input [] = { 318 /* n */ "keyboar", 319 /* n */ "tablet", 320 /* n */ "mouse", 321 /* n */ "scanner", 322 /* n */ "gamepor", 323 /* n */ "unknown", 324 /* n */ "unknown", 325 /* n */ "unknown", 326 /* n */ "unknown", 327 /* n */ "unknown", 328 /* n */ NULL 329 }; 330 331 static char * 332 pci_dock [] = { 333 /* n */ "docking", 334 /* n */ "unknown", 335 /* n */ "unknown", 336 /* n */ "unknown", 337 /* n */ "unknown", 338 /* n */ "unknown", 339 /* n */ "unknown", 340 /* n */ "unknown", 341 /* n */ "unknown", 342 /* n */ "unknown", 343 /* n */ NULL 344 }; 345 346 static char * 347 pci_processor [] = { 348 /* n */ "386", 349 /* n */ "486", 350 /* n */ "pentium", 351 /* n */ "alpha", 352 /* n */ "powerpc", 353 /* n */ "mips", 354 /* n */ "coproc", 355 /* n */ "unknown", 356 /* n */ "unknown", 357 /* n */ "unknown", 358 /* n */ NULL 359 }; 360 361 static char * 362 pci_serial [] = { 363 /* n */ "1394", 364 /* n */ "access", 365 /* n */ "ssa", 366 /* n */ "usb", 367 /* n */ "fibre", 368 /* n */ "smbus", 369 /* n */ "unknown", 370 /* n */ "unknown", 371 /* n */ "unknown", 372 /* n */ "unknown", 373 /* n */ NULL 374 }; 375 376 static char * 377 pci_wireless [] = { 378 /* n */ "irda", 379 /* n */ "ir", 380 /* n */ "rf", 381 /* n */ "unknown", 382 /* n */ "unknown", 383 /* n */ "unknown", 384 /* n */ "unknown", 385 /* n */ "unknown", 386 /* n */ "unknown", 387 /* n */ "unknown", 388 /* n */ NULL 389 }; 390 391 static char * 392 pci_intio [] = { 393 /* n */ "i2o", 394 /* n */ "unknown", 395 /* n */ "unknown", 396 /* n */ "unknown", 397 /* n */ "unknown", 398 /* n */ "unknown", 399 /* n */ "unknown", 400 /* n */ "unknown", 401 /* n */ "unknown", 402 /* n */ "unknown", 403 /* n */ NULL 404 }; 405 406 static char * 407 pci_satellite [] = { 408 /* n */ "tv", 409 /* n */ "audio", 410 /* n */ "voice", 411 /* n */ "data", 412 /* n */ "unknown", 413 /* n */ "unknown", 414 /* n */ "unknown", 415 /* n */ "unknown", 416 /* n */ "unknown", 417 /* n */ "unknown", 418 /* n */ NULL 419 }; 420 421 static char * 422 pci_crypt [] = { 423 /* n */ "netcryp", 424 /* n */ "entcryp", 425 /* n */ "unknown", 426 /* n */ "unknown", 427 /* n */ "unknown", 428 /* n */ "unknown", 429 /* n */ "unknown", 430 /* n */ "unknown", 431 /* n */ "unknown", 432 /* n */ "unknown", 433 /* n */ NULL 434 }; 435 436 static char * 437 pci_signal [] = { 438 /* n */ "dpio", 439 /* n */ "unknown", 440 /* n */ "unknown", 441 /* n */ "unknown", 442 /* n */ "unknown", 443 /* n */ "unknown", 444 /* n */ "unknown", 445 /* n */ "unknown", 446 /* n */ "unknown", 447 /* n */ "unknown", 448 /* n */ NULL 449 }; 450 451 /* 452 * Board Type 453 */ 454 static char * 455 board_strs[] = { 456 /* n */ "???", /* HPC_BOARD_UNKNOWN */ 457 /* n */ "hp", /* HPC_BOARD_PCI_HOTPLUG */ 458 /* n */ "nhs", /* HPC_BOARD_CPCI_NON_HS */ 459 /* n */ "bhs", /* HPC_BOARD_CPCI_BASIC_HS */ 460 /* n */ "fhs", /* HPC_BOARD_CPCI_FULL_HS */ 461 /* n */ "hs", /* HPC_BOARD_CPCI_HS */ 462 /* n */ NULL 463 }; 464 465 /* 466 * HW functions 467 */ 468 static char * 469 func_strs[] = { 470 /* n */ "enable_slot", 471 /* n */ "disable_slot", 472 /* n */ "enable_autoconfig", 473 /* n */ "disable_autoconfig", 474 /* n */ "led", 475 /* n */ "mode", 476 /* n */ NULL 477 }; 478 479 #define PCISO_SUBCLASS_OTHER 0x80 /* generic subclass */ 480 481 /* 482 * other subclass types 483 */ 484 485 static char * 486 other_strs[] = { 487 /* n */ "none", 488 /* n */ "storage", 489 /* n */ "network", 490 /* n */ "display", 491 /* n */ "mmedia", 492 /* n */ "memory", 493 /* n */ "bridge", 494 /* n */ "unknown", 495 /* n */ "unknown", 496 /* n */ "unknown", 497 /* n */ NULL 498 }; 499 500 501 #define ENABLE_SLOT 0 502 #define DISABLE_SLOT 1 503 #define ENABLE_AUTOCNF 2 504 #define DISABLE_AUTOCNF 3 505 #define LED 4 506 #define MODE 5 507 508 /* 509 * LED strings 510 */ 511 static char * 512 led_strs[] = { 513 /* n */ "fault", /* HPC_FAULT_LED */ 514 /* n */ "power", /* HPC_POWER_LED */ 515 /* n */ "attn", /* HPC_ATTN_LED */ 516 /* n */ "active", /* HPC_ACTIVE_LED */ 517 /* n */ NULL 518 }; 519 520 #define FAULT 0 521 #define POWER 1 522 #define ATTN 2 523 #define ACTIVE 3 524 525 static char * 526 mode_strs[] = { 527 /* n */ "off", /* HPC_LED_OFF */ 528 /* n */ "on", /* HPC_LED_ON */ 529 /* n */ "blink", /* HPC_LED_BLINK */ 530 /* n */ NULL 531 }; 532 533 #define OFF 0 534 #define ON 1 535 #define BLINK 2 536 537 #define cfga_errstrs(i) cfga_errstrs[(i)] 538 539 #define cfga_eid(a, b) (((a) << 8) + (b)) 540 #define MAXDEVS 32 541 542 typedef enum { 543 SOLARIS_SLT_NAME, 544 PROM_SLT_NAME 545 } slt_name_src_t; 546 547 struct searcharg { 548 char *devpath; 549 char slotnames[MAXDEVS][MAXNAMELEN]; 550 int minor; 551 di_prom_handle_t promp; 552 slt_name_src_t slt_name_src; 553 }; 554 555 static void *private_check; 556 557 static int 558 get_occupants(const char *ap_id, hpc_occupant_info_t *occupant) 559 { 560 int rv; 561 int fd; 562 di_node_t ap_node; 563 char *prop_data; 564 char *tmp; 565 char *ptr; 566 struct stat statbuf; 567 dev_t devt; 568 569 if ((fd = open(ap_id, O_RDWR)) == -1) { 570 DBG(2, ("open = ap_id%s, fd%d\n", ap_id, fd)); 571 DBG_F(2, (stderr, "open on %s failed\n", ap_id)); 572 return (CFGA_ERROR); 573 } 574 575 if (fstat(fd, &statbuf) == -1) { 576 DBG(1, ("stat failed: %i\n", errno)); 577 (void) close(fd); 578 return (CFGA_ERROR); 579 } 580 (void) close(fd); 581 582 devt = statbuf.st_rdev; 583 584 tmp = (char *)(ap_id + sizeof ("/devices") - 1); 585 if ((ptr = strrchr(tmp, ':')) != NULL) 586 *ptr = '\0'; 587 588 ap_node = di_init(tmp, DINFOPROP | DINFOMINOR); 589 if (ap_node == DI_NODE_NIL) { 590 DBG(1, ("dead %i\n", errno)); 591 return (CFGA_ERROR); 592 } 593 594 #ifdef PCIHP_DBG 595 ptr = di_devfs_path(ap_node); 596 DBG(1, ("get_occupants: %s\n", ptr)); 597 di_devfs_path_free(ptr); 598 #endif 599 600 if ((rv = di_prop_lookup_strings(devt, ap_node, "pci-occupant", 601 &prop_data)) == -1) { 602 DBG(1, ("get_occupants: prop_lookup failed: %i\n", errno)); 603 di_fini(ap_node); 604 return (CFGA_ERROR); 605 } 606 607 if (prop_data && (strcmp(prop_data, "") == 0)) { 608 di_fini(ap_node); 609 occupant->i = 0; 610 occupant->id[0] = NULL; 611 return (CFGA_OK); 612 } 613 614 DBG(1, ("get_occupants: %i devices found\n", rv)); 615 for (occupant->i = 0; occupant->i < rv; occupant->i++) { 616 if (occupant->i >= (HPC_MAX_OCCUPANTS - 1)) { 617 occupant->i--; 618 break; 619 } 620 occupant->id[occupant->i] = (char *)malloc( 621 strlen(prop_data) + sizeof ("/devices")); 622 (void) snprintf(occupant->id[occupant->i], strlen(prop_data) + 623 sizeof ("/devices"), "/devices%s", prop_data); 624 DBG(1, ("%s\n", occupant->id[occupant->i])); 625 prop_data += strlen(prop_data) + 1; 626 } 627 di_fini(ap_node); 628 629 occupant->id[occupant->i] = NULL; 630 631 return (CFGA_OK); 632 } 633 634 /* 635 * let rcm know that the device has indeed been removed and clean 636 * up rcm data 637 */ 638 static void 639 confirm_rcm(hpc_occupant_info_t *occupant, rcm_handle_t *rhandle) 640 { 641 DBG(1, ("confirm_rcm\n")); 642 643 if (occupant->i == 0) /* nothing was found to ask rcm about */ 644 return; 645 646 (void) rcm_notify_remove_list(rhandle, occupant->id, 0, NULL); 647 (void) rcm_free_handle(rhandle); 648 649 for (; occupant->i >= 0; occupant->i--) 650 free(occupant->id[occupant->i]); 651 } 652 653 static void 654 fail_rcm(hpc_occupant_info_t *occupant, rcm_handle_t *rhandle) 655 { 656 DBG(1, ("fail_rcm\n")); 657 658 if (occupant->i == 0) /* nothing was found to ask rcm about */ 659 return; 660 661 (void) rcm_notify_online_list(rhandle, occupant->id, 0, NULL); 662 (void) rcm_free_handle(rhandle); 663 664 for (; occupant->i >= 0; occupant->i--) 665 free(occupant->id[occupant->i]); 666 } 667 668 /* 669 * copied from scsi_rcm_info_table 670 * 671 * Takes an opaque rcm_info_t pointer and a character pointer, and appends 672 * the rcm_info_t data in the form of a table to the given character pointer. 673 */ 674 static void 675 pci_rcm_info_table(rcm_info_t *rinfo, char **table) 676 { 677 int i; 678 size_t w; 679 size_t width = 0; 680 size_t w_rsrc = 0; 681 size_t w_info = 0; 682 size_t table_size = 0; 683 uint_t tuples = 0; 684 rcm_info_tuple_t *tuple = NULL; 685 char *rsrc; 686 char *info; 687 char *newtable; 688 static char format[MAX_FORMAT]; 689 const char *infostr; 690 691 /* Protect against invalid arguments */ 692 if (rinfo == NULL || table == NULL) 693 return; 694 695 /* Set localized table header strings */ 696 rsrc = dgettext(TEXT_DOMAIN, "Resource"); 697 info = dgettext(TEXT_DOMAIN, "Information"); 698 699 /* A first pass, to size up the RCM information */ 700 while (tuple = rcm_info_next(rinfo, tuple)) { 701 if ((infostr = rcm_info_info(tuple)) != NULL) { 702 tuples++; 703 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc) 704 w_rsrc = w; 705 if ((w = strlen(infostr)) > w_info) 706 w_info = w; 707 } 708 } 709 710 /* If nothing was sized up above, stop early */ 711 if (tuples == 0) 712 return; 713 714 /* Adjust column widths for column headings */ 715 if ((w = strlen(rsrc)) > w_rsrc) 716 w_rsrc = w; 717 else if ((w_rsrc - w) % 2) 718 w_rsrc++; 719 if ((w = strlen(info)) > w_info) 720 w_info = w; 721 else if ((w_info - w) % 2) 722 w_info++; 723 724 /* 725 * Compute the total line width of each line, 726 * accounting for intercolumn spacing. 727 */ 728 width = w_info + w_rsrc + 4; 729 730 /* Allocate space for the table */ 731 table_size = (2 + tuples) * (width + 1) + 2; 732 if (*table == NULL) { 733 /* zero fill for the strcat() call below */ 734 *table = calloc(table_size, sizeof (char)); 735 if (*table == NULL) 736 return; 737 } else { 738 newtable = realloc(*table, strlen(*table) + table_size); 739 if (newtable == NULL) 740 return; 741 else 742 *table = newtable; 743 } 744 745 /* Place a table header into the string */ 746 747 /* The resource header */ 748 (void) strcat(*table, "\n"); 749 w = strlen(rsrc); 750 for (i = 0; i < ((w_rsrc - w) / 2); i++) 751 (void) strcat(*table, " "); 752 (void) strcat(*table, rsrc); 753 for (i = 0; i < ((w_rsrc - w) / 2); i++) 754 (void) strcat(*table, " "); 755 756 /* The information header */ 757 (void) strcat(*table, " "); 758 w = strlen(info); 759 for (i = 0; i < ((w_info - w) / 2); i++) 760 (void) strcat(*table, " "); 761 (void) strcat(*table, info); 762 for (i = 0; i < ((w_info - w) / 2); i++) 763 (void) strcat(*table, " "); 764 /* Underline the headers */ 765 (void) strcat(*table, "\n"); 766 for (i = 0; i < w_rsrc; i++) 767 (void) strcat(*table, "-"); 768 (void) strcat(*table, " "); 769 for (i = 0; i < w_info; i++) 770 (void) strcat(*table, "-"); 771 772 /* Construct the format string */ 773 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 774 (int)w_rsrc, (int)w_info); 775 776 /* Add the tuples to the table string */ 777 tuple = NULL; 778 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 779 if ((infostr = rcm_info_info(tuple)) != NULL) { 780 (void) strcat(*table, "\n"); 781 (void) sprintf(&((*table)[strlen(*table)]), 782 format, rcm_info_rsrc(tuple), 783 infostr); 784 } 785 } 786 } 787 788 /* 789 * Figure out what device is about to be unconfigured or disconnected 790 * and make sure rcm is ok with it. 791 * hangs on to a list of handles so they can then be confirmed or denied 792 * if either getting the occupant list or talking to rcm fails 793 * return CFGA_ERROR so that things can go on without rcm 794 */ 795 static int 796 check_rcm(const char *ap_id, hpc_occupant_info_t *occupant, 797 rcm_handle_t **rhandlep, char **errstring, cfga_flags_t flags) 798 { 799 int rv; 800 rcm_info_t *rinfo; 801 rcm_handle_t *rhandle; 802 uint_t rcmflags; 803 804 if (get_occupants(ap_id, occupant) != 0) { 805 DBG(1, ("check_rcm: failed to get occupants\n")); 806 return (CFGA_ERROR); 807 } 808 809 if (occupant->i == 0) { 810 DBG(1, ("check_rcm: no drivers attaching to occupants\n")); 811 return (CFGA_OK); 812 } 813 814 if (rcm_alloc_handle(NULL, 0, NULL, &rhandle) 815 != RCM_SUCCESS) { 816 DBG(1, ("check_rcm: blocked by rcm failure\n")); 817 return (CFGA_ERROR); 818 } 819 820 rcmflags = (flags & CFGA_FLAG_FORCE) ? RCM_FORCE : 0; 821 rv = rcm_request_offline_list(rhandle, occupant->id, rcmflags, &rinfo); 822 823 if (rv == RCM_FAILURE) { 824 DBG(1, ("check_rcm: blocked by rcm failure 2\n")); 825 pci_rcm_info_table(rinfo, errstring); 826 rcm_free_info(rinfo); 827 fail_rcm(occupant, rhandle); 828 return (CFGA_BUSY); 829 } 830 if (rv == RCM_CONFLICT) { 831 DBG(1, ("check_rcm: blocked by %i\n", 832 rcm_info_pid(rinfo))); 833 pci_rcm_info_table(rinfo, errstring); 834 rcm_free_info(rinfo); 835 (void) rcm_free_handle(rhandle); 836 for (; occupant->i >= 0; occupant->i--) 837 free(occupant->id[occupant->i]); 838 return (CFGA_BUSY); 839 } 840 841 rcm_free_info(rinfo); 842 *rhandlep = rhandle; 843 844 /* else */ 845 return (CFGA_OK); 846 } 847 848 849 /* 850 * Transitional Diagram: 851 * 852 * empty unconfigure 853 * (remove) ^| (physically insert card) 854 * |V 855 * disconnect configure 856 * "-c DISCONNECT" ^| "-c CONNECT" 857 * |V "-c CONFIGURE" 858 * connect unconfigure -> connect configure 859 * <- 860 * "-c UNCONFIGURE" 861 * 862 */ 863 /*ARGSUSED*/ 864 cfga_err_t 865 cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id, 866 const char *options, struct cfga_confirm *confp, 867 struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 868 { 869 int rv; 870 devctl_hdl_t dcp; 871 devctl_ap_state_t state; 872 ap_rstate_t rs; 873 ap_ostate_t os; 874 hpc_occupant_info_t occupants; 875 rcm_handle_t *rhandle; 876 877 if ((rv = check_options(options)) != CFGA_OK) { 878 return (rv); 879 } 880 881 if (errstring != NULL) 882 *errstring = NULL; 883 884 rv = CFGA_OK; 885 DBG(1, ("cfga_change_state:(%s)\n", ap_id)); 886 887 if ((dcp = devctl_ap_acquire((char *)ap_id, 0)) == NULL) { 888 if (rv == EBUSY) { 889 cfga_err(errstring, CMD_ACQUIRE, ap_id, 0); 890 DBG(1, ("cfga_change_state: device is busy\n")); 891 rv = CFGA_BUSY; 892 } else 893 rv = CFGA_ERROR; 894 return (rv); 895 } 896 897 if (devctl_ap_getstate(dcp, NULL, &state) == -1) { 898 DBG(2, ("cfga_change_state: devctl ap getstate failed\n")); 899 cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 900 devctl_release((devctl_hdl_t)dcp); 901 if (rv == EBUSY) 902 rv = CFGA_BUSY; 903 else 904 rv = CFGA_ERROR; 905 return (rv); 906 } 907 908 rs = state.ap_rstate; 909 os = state.ap_ostate; 910 911 DBG(1, ("cfga_change_state: rs is %d\n", state.ap_rstate)); 912 DBG(1, ("cfga_change_state: os is %d\n", state.ap_ostate)); 913 switch (state_change_cmd) { 914 case CFGA_CMD_CONNECT: 915 if ((rs == AP_RSTATE_CONNECTED) || 916 (os == AP_OSTATE_CONFIGURED)) { 917 cfga_err(errstring, ERR_AP_ERR, 0); 918 rv = CFGA_INVAL; 919 } else { 920 /* Lets connect the slot */ 921 if (devctl_ap_connect(dcp, NULL) == -1) { 922 rv = CFGA_ERROR; 923 cfga_err(errstring, 924 CMD_SLOT_CONNECT, 0); 925 } 926 } 927 928 break; 929 930 case CFGA_CMD_DISCONNECT: 931 DBG(1, ("disconnect\n")); 932 933 if (os == AP_OSTATE_CONFIGURED) { 934 if ((rv = check_rcm(ap_id, &occupants, &rhandle, 935 errstring, flags)) == CFGA_BUSY) { 936 break; 937 } else if (rv == CFGA_OK) { 938 if (devctl_ap_unconfigure(dcp, NULL) == -1) { 939 if (errno == EBUSY) 940 rv = CFGA_BUSY; 941 else 942 rv = CFGA_ERROR; 943 cfga_err(errstring, 944 CMD_SLOT_DISCONNECT, 0); 945 fail_rcm(&occupants, rhandle); 946 break; 947 } else { 948 confirm_rcm(&occupants, rhandle); 949 } 950 } else { /* rv == CFGA_ERROR */ 951 if (devctl_ap_unconfigure(dcp, NULL) == -1) { 952 if (errno == EBUSY) 953 rv = CFGA_BUSY; 954 else 955 rv = CFGA_ERROR; 956 break; 957 } else { 958 rv = CFGA_OK; 959 } 960 } 961 } 962 963 if (rs == AP_RSTATE_CONNECTED) { 964 if (devctl_ap_disconnect(dcp, NULL) == -1) { 965 rv = CFGA_ERROR; 966 cfga_err(errstring, CMD_SLOT_DISCONNECT, 0); 967 break; 968 } 969 } else { 970 cfga_err(errstring, ERR_AP_ERR, 0); 971 rv = CFGA_INVAL; 972 } 973 974 break; 975 976 case CFGA_CMD_CONFIGURE: 977 if (rs == AP_RSTATE_DISCONNECTED) { 978 if (devctl_ap_connect(dcp, NULL) == -1) { 979 rv = CFGA_ERROR; 980 cfga_err(errstring, CMD_SLOT_CONNECT, 0); 981 break; 982 } 983 } 984 985 /* 986 * for multi-func device we allow multiple 987 * configure on the same slot because one 988 * func can be configured and other one won't 989 */ 990 if (devctl_ap_configure(dcp, NULL) == -1) { 991 rv = CFGA_ERROR; 992 cfga_err(errstring, CMD_SLOT_CONFIGURE, 0); 993 if (devctl_ap_disconnect(dcp, NULL) == -1) { 994 rv = CFGA_ERROR; 995 cfga_err(errstring, 996 CMD_SLOT_CONFIGURE, 0); 997 } 998 break; 999 } 1000 1001 break; 1002 1003 case CFGA_CMD_UNCONFIGURE: 1004 DBG(1, ("unconfigure\n")); 1005 1006 if (os == AP_OSTATE_CONFIGURED) { 1007 if ((rv = check_rcm(ap_id, &occupants, &rhandle, 1008 errstring, flags)) == CFGA_BUSY) { 1009 break; 1010 } else if (rv == CFGA_OK) { 1011 if (devctl_ap_unconfigure(dcp, NULL) == -1) { 1012 if (errno == EBUSY) 1013 rv = CFGA_BUSY; 1014 else { 1015 if (errno == ENOTSUP) 1016 rv = CFGA_OPNOTSUPP; 1017 else 1018 rv = CFGA_ERROR; 1019 } 1020 cfga_err(errstring, 1021 CMD_SLOT_UNCONFIGURE, 0); 1022 fail_rcm(&occupants, rhandle); 1023 } else { 1024 confirm_rcm(&occupants, rhandle); 1025 } 1026 } else { /* rv == CFGA_ERROR */ 1027 if (devctl_ap_unconfigure(dcp, NULL) == -1) { 1028 if (errno == EBUSY) 1029 rv = CFGA_BUSY; 1030 else { 1031 if (errno == ENOTSUP) 1032 rv = CFGA_OPNOTSUPP; 1033 else 1034 rv = CFGA_ERROR; 1035 } 1036 cfga_err(errstring, 1037 CMD_SLOT_UNCONFIGURE, 0); 1038 } else { 1039 rv = CFGA_OK; 1040 } 1041 } 1042 } else { 1043 cfga_err(errstring, ERR_AP_ERR, 0); 1044 rv = CFGA_INVAL; 1045 } 1046 1047 DBG(1, ("uncofigure rv:(%i)\n", rv)); 1048 break; 1049 1050 case CFGA_CMD_LOAD: 1051 if ((os == AP_OSTATE_UNCONFIGURED) && 1052 (rs == AP_RSTATE_DISCONNECTED)) { 1053 if (devctl_ap_insert(dcp, NULL) == -1) { 1054 rv = CFGA_ERROR; 1055 cfga_err(errstring, CMD_SLOT_INSERT, 0); 1056 } 1057 } else { 1058 cfga_err(errstring, ERR_AP_ERR, 0); 1059 rv = CFGA_INVAL; 1060 } 1061 1062 break; 1063 1064 case CFGA_CMD_UNLOAD: 1065 if ((os == AP_OSTATE_UNCONFIGURED) && 1066 (rs == AP_RSTATE_DISCONNECTED)) { 1067 if (devctl_ap_remove(dcp, NULL) == -1) { 1068 rv = CFGA_ERROR; 1069 cfga_err(errstring, CMD_SLOT_REMOVE, 0); 1070 } 1071 } else { 1072 cfga_err(errstring, ERR_AP_ERR, 0); 1073 rv = CFGA_INVAL; 1074 } 1075 1076 break; 1077 1078 default: 1079 rv = CFGA_OPNOTSUPP; 1080 break; 1081 } 1082 1083 devctl_release((devctl_hdl_t)dcp); 1084 return (rv); 1085 } 1086 1087 /* 1088 * Building iocdatat to pass it to nexus 1089 * 1090 * iocdata->cmd == HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT 1091 * HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG 1092 * HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE 1093 * HPC_CTRL_GET_SLOT_STATE/HPC_CTRL_GET_SLOT_INFO 1094 * HPC_CTRL_DEV_CONFIGURE/HPC_CTRL_DEV_UNCONFIGURE 1095 * HPC_CTRL_GET_BOARD_TYPE 1096 * 1097 */ 1098 static void 1099 build_control_data(struct hpc_control_data *iocdata, uint_t cmd, 1100 void *retdata) 1101 { 1102 iocdata->cmd = cmd; 1103 iocdata->data = retdata; 1104 } 1105 1106 /* 1107 * building logical name from ap_id 1108 */ 1109 /*ARGSUSED2*/ 1110 static void 1111 get_logical_name(const char *ap_id, char *buf, dev_t rdev) 1112 { 1113 char *bufptr, *bufptr2, *pci, *apid; 1114 1115 DBG(1, ("get_logical_name: %s\n", ap_id)); 1116 1117 if ((apid = malloc(MAXPATHLEN)) == NULL) { 1118 DBG(1, ("malloc failed\n")); 1119 return; 1120 } 1121 1122 (void) memset(apid, 0, MAXPATHLEN); 1123 (void) strncpy(apid, ap_id, strlen(ap_id)); 1124 1125 /* needs to look for last /, not first */ 1126 bufptr = strrchr(apid, '/'); 1127 1128 bufptr2 = strrchr(apid, ':'); 1129 pci = ++bufptr; 1130 bufptr = strchr(pci, ','); 1131 if (bufptr != NULL) { 1132 *bufptr = '\0'; 1133 } 1134 1135 bufptr = strchr(pci, '@'); 1136 if (bufptr != NULL) { 1137 *bufptr = '\0'; 1138 bufptr++; 1139 } 1140 1141 DBG(1, ("%s\n%s\n%s\n", pci, bufptr, bufptr2)); 1142 1143 (void) strcat(buf, pci); 1144 (void) strcat(buf, bufptr); 1145 (void) strcat(buf, bufptr2); 1146 free(apid); 1147 } 1148 1149 static cfga_err_t 1150 prt_led_mode(const char *ap_id, int repeat, char **errstring, 1151 struct cfga_msg *msgp) 1152 { 1153 hpc_led_info_t power_led_info = {HPC_POWER_LED, 0}; 1154 hpc_led_info_t fault_led_info = {HPC_FAULT_LED, 0}; 1155 hpc_led_info_t attn_led_info = {HPC_ATTN_LED, 0}; 1156 hpc_led_info_t active_led_info = {HPC_ACTIVE_LED, 0}; 1157 struct hpc_control_data iocdata; 1158 struct stat statbuf; 1159 char *buff; 1160 int fd; 1161 hpc_slot_info_t slot_info; 1162 char *cp, line[MAXLINE]; 1163 int len = MAXLINE; 1164 1165 DBG(1, ("prt_led_mod function\n")); 1166 if (!repeat) 1167 cfga_msg(msgp, "Ap_Id\t\t\tLed"); 1168 1169 if ((fd = open(ap_id, O_RDWR)) == -1) { 1170 DBG(2, ("open = ap_id%s, fd%d\n", ap_id, fd)); 1171 DBG_F(2, (stderr, "open on %s failed\n", ap_id)); 1172 cfga_err(errstring, CMD_OPEN, ap_id, 0); 1173 return (CFGA_ERROR); 1174 } 1175 1176 if (fstat(fd, &statbuf) == -1) { 1177 DBG(2, ("fstat = ap_id%s, fd%d\n", ap_id, fd)); 1178 DBG_F(2, (stderr, "fstat on %s failed\n", ap_id)); 1179 cfga_err(errstring, CMD_FSTAT, ap_id, 0); 1180 return (CFGA_ERROR); 1181 } 1182 1183 if ((buff = malloc(MAXPATHLEN)) == NULL) { 1184 cfga_err(errstring, "malloc ", 0); 1185 return (CFGA_ERROR); 1186 } 1187 1188 (void) memset(buff, 0, MAXPATHLEN); 1189 1190 DBG(1, ("ioctl boardtype\n")); 1191 1192 build_control_data(&iocdata, HPC_CTRL_GET_SLOT_INFO, 1193 (void *)&slot_info); 1194 1195 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1196 get_logical_name(ap_id, slot_info.pci_slot_name, 0); 1197 DBG(1, ("ioctl failed slotinfo: %s\n", 1198 slot_info.pci_slot_name)); 1199 } else { 1200 1201 /* 1202 * the driver will report back things like hpc0_slot0 1203 * this needs to be changed to things like pci1:hpc0_slot0 1204 */ 1205 if (fix_ap_name(buff, ap_id, slot_info.pci_slot_name, 1206 errstring) != CFGA_OK) { 1207 free(buff); 1208 (void) close(fd); 1209 return (CFGA_ERROR); 1210 } 1211 DBG(1, ("ioctl slotinfo: %s\n", buff)); 1212 } 1213 1214 cp = line; 1215 (void) snprintf(cp, len, "%s\t\t", buff); 1216 len -= strlen(cp); 1217 cp += strlen(cp); 1218 1219 free(buff); 1220 1221 build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &power_led_info); 1222 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1223 (void) snprintf(cp, len, "%s=%s,", 1224 led_strs[power_led_info.led], cfga_strs[UNKNOWN]); 1225 len -= strlen(cp); 1226 cp += strlen(cp); 1227 } else { 1228 (void) snprintf(cp, len, "%s=%s,", led_strs[power_led_info.led], 1229 mode_strs[power_led_info.state]); 1230 len -= strlen(cp); 1231 cp += strlen(cp); 1232 } 1233 1234 DBG(1, ("%s:%d\n", led_strs[power_led_info.led], power_led_info.state)); 1235 1236 build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &fault_led_info); 1237 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1238 (void) snprintf(cp, len, "%s=%s,", 1239 led_strs[fault_led_info.led], cfga_strs[UNKNOWN]); 1240 len -= strlen(cp); 1241 cp += strlen(cp); 1242 } else { 1243 (void) snprintf(cp, len, "%s=%s,", 1244 led_strs[fault_led_info.led], 1245 mode_strs[fault_led_info.state]); 1246 len -= strlen(cp); 1247 cp += strlen(cp); 1248 } 1249 DBG(1, ("%s:%d\n", led_strs[fault_led_info.led], fault_led_info.state)); 1250 1251 build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &attn_led_info); 1252 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1253 (void) snprintf(cp, len, "%s=%s,", 1254 led_strs[attn_led_info.led], cfga_strs[UNKNOWN]); 1255 len -= strlen(cp); 1256 cp += strlen(cp); 1257 } else { 1258 (void) snprintf(cp, len, "%s=%s,", 1259 led_strs[attn_led_info.led], 1260 mode_strs[attn_led_info.state]); 1261 len -= strlen(cp); 1262 cp += strlen(cp); 1263 } 1264 DBG(1, ("%s:%d\n", led_strs[attn_led_info.led], attn_led_info.state)); 1265 1266 build_control_data(&iocdata, HPC_CTRL_GET_LED_STATE, &active_led_info); 1267 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1268 (void) snprintf(cp, len, "%s=%s", led_strs[active_led_info.led], 1269 cfga_strs[UNKNOWN]); 1270 } else { 1271 (void) snprintf(cp, len, "%s=%s", 1272 led_strs[active_led_info.led], 1273 mode_strs[active_led_info.state]); 1274 } 1275 cfga_msg(msgp, line); /* print the message */ 1276 DBG(1, ("%s:%d\n", led_strs[active_led_info.led], 1277 active_led_info.state)); 1278 1279 (void) close(fd); 1280 1281 return (CFGA_OK); 1282 } 1283 1284 /*ARGSUSED*/ 1285 cfga_err_t 1286 cfga_private_func(const char *function, const char *ap_id, 1287 const char *options, struct cfga_confirm *confp, 1288 struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 1289 { 1290 char *str; 1291 int len, fd, i = 0, repeat = 0; 1292 char buf[MAXNAMELEN]; 1293 char ptr; 1294 hpc_led_info_t led_info; 1295 struct hpc_control_data iocdata; 1296 cfga_err_t rv; 1297 1298 DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id)); 1299 DBG(2, (" options: %s\n", (options == NULL)?"null":options)); 1300 DBG(2, (" confp: %x\n", confp)); 1301 DBG(2, (" cfga_msg: %x\n", cfga_msg)); 1302 DBG(2, (" flag: %d\n", flags)); 1303 1304 if ((rv = check_options(options)) != CFGA_OK) { 1305 return (rv); 1306 } 1307 1308 if (private_check == confp) 1309 repeat = 1; 1310 else 1311 private_check = (void*)confp; 1312 1313 /* XXX change const 6 to func_str[i] != NULL */ 1314 for (i = 0, str = func_strs[i], len = strlen(str); i < 6; i++) { 1315 str = func_strs[i]; 1316 len = strlen(str); 1317 if (strncmp(function, str, len) == 0) 1318 break; 1319 } 1320 1321 switch (i) { 1322 case ENABLE_SLOT: 1323 build_control_data(&iocdata, 1324 HPC_CTRL_ENABLE_SLOT, 0); 1325 break; 1326 case DISABLE_SLOT: 1327 build_control_data(&iocdata, 1328 HPC_CTRL_DISABLE_SLOT, 0); 1329 break; 1330 case ENABLE_AUTOCNF: 1331 build_control_data(&iocdata, 1332 HPC_CTRL_ENABLE_AUTOCFG, 0); 1333 break; 1334 case DISABLE_AUTOCNF: 1335 build_control_data(&iocdata, 1336 HPC_CTRL_DISABLE_AUTOCFG, 0); 1337 break; 1338 case LED: 1339 /* set mode */ 1340 ptr = function[len++]; 1341 if (ptr == '=') { 1342 str = (char *)function; 1343 for (str = (str+len++), i = 0; *str != ','; 1344 i++, str++) { 1345 if (i == (MAXNAMELEN - 1)) 1346 break; 1347 1348 buf[i] = *str; 1349 DBG_F(2, (stdout, "%c\n", buf[i])); 1350 } 1351 buf[i] = '\0'; str++; 1352 DBG(2, ("buf = %s\n", buf)); 1353 1354 /* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */ 1355 if (strcmp(buf, led_strs[POWER]) == 0) 1356 led_info.led = HPC_POWER_LED; 1357 else if (strcmp(buf, led_strs[FAULT]) == 0) 1358 led_info.led = HPC_FAULT_LED; 1359 else if (strcmp(buf, led_strs[ATTN]) == 0) 1360 led_info.led = HPC_ATTN_LED; 1361 else if (strcmp(buf, led_strs[ACTIVE]) == 0) 1362 led_info.led = HPC_ACTIVE_LED; 1363 else return (CFGA_INVAL); 1364 1365 len = strlen(func_strs[MODE]); 1366 if ((strncmp(str, func_strs[MODE], len) == 0) && 1367 (*(str+(len)) == '=')) { 1368 for (str = (str+(++len)), i = 0; 1369 *str != NULL; i++, str++) { 1370 buf[i] = *str; 1371 1372 } 1373 } 1374 buf[i] = '\0'; 1375 DBG(2, ("buf_mode= %s\n", buf)); 1376 1377 /* ON = 1, OFF = 0 */ 1378 if (strcmp(buf, mode_strs[ON]) == 0) 1379 led_info.state = HPC_LED_ON; 1380 else if (strcmp(buf, mode_strs[OFF]) == 0) 1381 led_info.state = HPC_LED_OFF; 1382 else if (strcmp(buf, mode_strs[BLINK]) == 0) 1383 led_info.state = HPC_LED_BLINK; 1384 else return (CFGA_INVAL); 1385 1386 /* sendin */ 1387 build_control_data(&iocdata, 1388 HPC_CTRL_SET_LED_STATE, 1389 (void *)&led_info); 1390 break; 1391 } else if (ptr == '\0') { 1392 /* print mode */ 1393 DBG(1, ("Print mode\n")); 1394 return (prt_led_mode(ap_id, repeat, errstring, 1395 msgp)); 1396 } 1397 default: 1398 DBG(1, ("default\n")); 1399 errno = EINVAL; 1400 return (CFGA_INVAL); 1401 } 1402 1403 if ((fd = open(ap_id, O_RDWR)) == -1) { 1404 DBG(1, ("open failed\n")); 1405 return (CFGA_ERROR); 1406 } 1407 1408 DBG(1, ("open = ap_id=%s, fd=%d\n", ap_id, fd)); 1409 1410 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1411 DBG(1, ("ioctl failed\n")); 1412 (void) close(fd); 1413 return (CFGA_ERROR); 1414 } 1415 1416 (void) close(fd); 1417 1418 return (CFGA_OK); 1419 } 1420 1421 /*ARGSUSED*/ 1422 cfga_err_t cfga_test(const char *ap_id, const char *options, 1423 struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 1424 { 1425 cfga_err_t rv; 1426 if (errstring != NULL) 1427 *errstring = NULL; 1428 1429 if ((rv = check_options(options)) != CFGA_OK) { 1430 return (rv); 1431 } 1432 1433 DBG(1, ("cfga_test:(%s)\n", ap_id)); 1434 /* will need to implement pci CTRL command */ 1435 return (CFGA_NOTSUPP); 1436 } 1437 1438 static int 1439 fixup_slotname(int rval, int *intp, struct searcharg *slotarg) 1440 { 1441 1442 /* 1443 * The slot-names property describes the external labeling of add-in slots. 1444 * This property is an encoded array, an integer followed by a list of 1445 * strings. The return value from di_prop_lookup_ints for slot-names is -1. 1446 * The expected return value should be the number of elements. 1447 * Di_prop_decode_common does not decode encoded data from software, 1448 * such as the solaris device tree, unlike from the prom. 1449 * Di_prop_decode_common takes the size of the encoded data and mods 1450 * it with the size of int. The size of the encoded data for slot-names is 9 1451 * and the size of int is 4, yielding a non zero result. A value of -1 is used 1452 * to indicate that the number of elements can not be determined. 1453 * Di_prop_decode_common can be modified to decode encoded data from the solaris 1454 * device tree. 1455 */ 1456 1457 if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) { 1458 return (DI_WALK_TERMINATE); 1459 } else { 1460 int i; 1461 char *tmptr = (char *)(intp+1); 1462 DBG(1, ("slot-bitmask: %x \n", *intp)); 1463 1464 rval = (rval -1) * 4; 1465 1466 for (i = 0; i <= slotarg->minor; i++) { 1467 DBG(2, ("curr slot-name: %s \n", tmptr)); 1468 1469 if (i >= MAXDEVS) 1470 return (DI_WALK_TERMINATE); 1471 1472 if ((*intp >> i) & 1) { 1473 /* assign tmptr */ 1474 DBG(2, ("slot-name: %s \n", tmptr)); 1475 if (i == slotarg->minor) 1476 (void) strcpy(slotarg->slotnames[i], 1477 tmptr); 1478 /* wind tmptr to next \0 */ 1479 while (*tmptr != '\0') { 1480 tmptr++; 1481 } 1482 tmptr++; 1483 } else { 1484 /* point at unknown string */ 1485 if (i == slotarg->minor) 1486 (void) strcpy(slotarg->slotnames[i], 1487 "unknown"); 1488 } 1489 } 1490 } 1491 return (DI_WALK_TERMINATE); 1492 } 1493 1494 static int 1495 find_slotname(di_node_t din, di_minor_t dim, void *arg) 1496 { 1497 struct searcharg *slotarg = (struct searcharg *)arg; 1498 di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp; 1499 di_prom_prop_t prom_prop; 1500 di_prop_t solaris_prop; 1501 int *intp, rval; 1502 char *devname; 1503 char fulldevname[MAXNAMELEN]; 1504 1505 slotarg->minor = dim->dev_minor % 256; 1506 1507 DBG(2, ("minor number:(%i)\n", slotarg->minor)); 1508 DBG(2, ("hot plug slots found so far:(%i)\n", 0)); 1509 1510 if ((devname = di_devfs_path(din)) != NULL) { 1511 (void) snprintf(fulldevname, MAXNAMELEN, 1512 "/devices%s:%s", devname, di_minor_name(dim)); 1513 di_devfs_path_free(devname); 1514 } 1515 1516 if (strcmp(fulldevname, slotarg->devpath) == 0) { 1517 1518 /* 1519 * Check the Solaris device tree first 1520 * in the case of a DR operation 1521 */ 1522 solaris_prop = di_prop_hw_next(din, DI_PROP_NIL); 1523 while (solaris_prop != DI_PROP_NIL) { 1524 if (strcmp("slot-names", di_prop_name(solaris_prop)) 1525 == 0) { 1526 rval = di_prop_lookup_ints(DDI_DEV_T_ANY, 1527 din, di_prop_name(solaris_prop), &intp); 1528 slotarg->slt_name_src = SOLARIS_SLT_NAME; 1529 1530 return (fixup_slotname(rval, intp, slotarg)); 1531 } 1532 solaris_prop = di_prop_hw_next(din, solaris_prop); 1533 } 1534 1535 /* 1536 * Check the prom device tree which is populated at boot. 1537 * If this fails, give up and set the slot name to null. 1538 */ 1539 prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL); 1540 while (prom_prop != DI_PROM_PROP_NIL) { 1541 if (strcmp("slot-names", di_prom_prop_name(prom_prop)) 1542 == 0) { 1543 rval = di_prom_prop_lookup_ints(ph, 1544 din, di_prom_prop_name(prom_prop), &intp); 1545 slotarg->slt_name_src = PROM_SLT_NAME; 1546 1547 return (fixup_slotname(rval, intp, slotarg)); 1548 } 1549 prom_prop = di_prom_prop_next(ph, din, prom_prop); 1550 } 1551 *slotarg->slotnames[slotarg->minor] = '\0'; 1552 return (DI_WALK_TERMINATE); 1553 } else 1554 return (DI_WALK_CONTINUE); 1555 } 1556 1557 static int 1558 find_physical_slot_names(const char *devcomp, struct searcharg *slotarg) 1559 { 1560 di_node_t root_node; 1561 1562 DBG(1, ("find_physical_slot_names\n")); 1563 1564 if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH)) 1565 == DI_NODE_NIL) { 1566 DBG(1, ("di_init() failed\n")); 1567 return (NULL); 1568 } 1569 1570 slotarg->devpath = (char *)devcomp; 1571 1572 if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) { 1573 DBG(1, ("di_prom_init() failed\n")); 1574 di_fini(root_node); 1575 return (NULL); 1576 } 1577 1578 (void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci", 1579 0, (void *)slotarg, find_slotname); 1580 1581 di_prom_fini(slotarg->promp); 1582 di_fini(root_node); 1583 if (slotarg->slotnames[0] != NULL) 1584 return (0); 1585 else 1586 return (-1); 1587 } 1588 1589 static void 1590 get_type(hpc_board_type_t boardtype, hpc_card_info_t cardinfo, char *buf) 1591 { 1592 1593 DBG(1, ("class: %i\n", cardinfo.base_class)); 1594 DBG(1, ("subclass: %i\n", cardinfo.sub_class)); 1595 1596 if (cardinfo.base_class == PCI_CLASS_NONE) { 1597 TPCT("unknown"); 1598 return; 1599 } 1600 1601 if (cardinfo.sub_class == PCISO_SUBCLASS_OTHER) { 1602 if (cardinfo.base_class < PCISO_MAX_SUBCLASS) 1603 TPCT(other_strs[cardinfo.base_class]); 1604 else 1605 TPCT("unknown"); 1606 } else { 1607 if (cardinfo.sub_class > PCISO_MAX_SUBCLASS) { 1608 TPCT("unknown"); 1609 } else { 1610 if (cardinfo.header_type != PCI_HEADER_MULTI) { 1611 switch (cardinfo.base_class) { 1612 case PCI_CLASS_MASS: 1613 TPCT(pci_masstrg[cardinfo.sub_class]); 1614 break; 1615 case PCI_CLASS_NET: 1616 TPCT(pci_network[cardinfo.sub_class]); 1617 break; 1618 case PCI_CLASS_DISPLAY: 1619 TPCT(pci_display[cardinfo.sub_class]); 1620 break; 1621 case PCI_CLASS_MM: 1622 TPCT(pci_multimd[cardinfo.sub_class]); 1623 break; 1624 case PCI_CLASS_MEM: 1625 TPCT(pci_memory[cardinfo.sub_class]); 1626 break; 1627 case PCI_CLASS_BRIDGE: 1628 TPCT(pci_bridge[cardinfo.sub_class]); 1629 break; 1630 case PCI_CLASS_COMM: 1631 TPCT(pci_comm[cardinfo.sub_class]); 1632 break; 1633 case PCI_CLASS_PERIPH: 1634 TPCT(pci_periph[cardinfo.sub_class]); 1635 break; 1636 case PCI_CLASS_INPUT: 1637 TPCT(pci_input[cardinfo.sub_class]); 1638 break; 1639 case PCI_CLASS_DOCK: 1640 TPCT(pci_dock[cardinfo.sub_class]); 1641 break; 1642 case PCI_CLASS_PROCESSOR: 1643 TPCT(pci_processor[cardinfo.sub_class]); 1644 break; 1645 case PCI_CLASS_SERIALBUS: 1646 TPCT(pci_serial[cardinfo.sub_class]); 1647 break; 1648 case PCI_CLASS_WIRELESS: 1649 TPCT(pci_wireless[cardinfo.sub_class]); 1650 break; 1651 case PCI_CLASS_INTIO: 1652 TPCT(pci_intio[cardinfo.sub_class]); 1653 break; 1654 case PCI_CLASS_SATELLITE: 1655 TPCT(pci_satellite[cardinfo.sub_class]); 1656 break; 1657 case PCI_CLASS_CRYPT: 1658 TPCT(pci_crypt[cardinfo.sub_class]); 1659 break; 1660 case PCI_CLASS_SIGNAL: 1661 TPCT(pci_signal[cardinfo.sub_class]); 1662 break; 1663 case PCI_CLASS_NONE: 1664 default: 1665 TPCT("unknown"); 1666 return; 1667 } 1668 } else 1669 TPCT("mult"); 1670 } 1671 } 1672 1673 TPCT("/"); 1674 switch (boardtype) { 1675 case HPC_BOARD_PCI_HOTPLUG: 1676 case HPC_BOARD_CPCI_NON_HS: 1677 case HPC_BOARD_CPCI_BASIC_HS: 1678 case HPC_BOARD_CPCI_FULL_HS: 1679 case HPC_BOARD_CPCI_HS: 1680 TPCT(board_strs[boardtype]); 1681 break; 1682 case HPC_BOARD_UNKNOWN: 1683 default: 1684 TPCT(board_strs[HPC_BOARD_UNKNOWN]); 1685 } 1686 } 1687 1688 /* 1689 * call-back function for di_devlink_walk 1690 * if the link lives in /dev/cfg copy its name 1691 */ 1692 static int 1693 found_devlink(di_devlink_t link, void *ap_log_id) 1694 { 1695 if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) { 1696 /* copy everything but /dev/cfg/ */ 1697 (void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9); 1698 DBG(1, ("found_devlink: %s\n", (char *)ap_log_id)); 1699 return (DI_WALK_TERMINATE); 1700 } 1701 return (DI_WALK_CONTINUE); 1702 } 1703 1704 /* 1705 * Walk throught the cached /dev link tree looking for links to the ap 1706 * if none are found return an error 1707 */ 1708 static cfga_err_t 1709 check_devlinks(char *ap_log_id, const char *ap_id) 1710 { 1711 di_devlink_handle_t hdl; 1712 1713 DBG(1, ("check_devlinks: %s\n", ap_id)); 1714 1715 hdl = di_devlink_init(NULL, 0); 1716 1717 if (strncmp("/devices/", ap_id, 9) == 0) { 1718 /* ap_id is a valid minor_path with /devices prepended */ 1719 (void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK, 1720 (void *)ap_log_id, found_devlink); 1721 } else { 1722 DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id)); 1723 return (CFGA_ERROR); 1724 } 1725 1726 (void) di_devlink_fini(&hdl); 1727 1728 if (ap_log_id[0] != '\0') 1729 return (CFGA_OK); 1730 else 1731 return (CFGA_ERROR); 1732 } 1733 1734 /* 1735 * most of this is needed to compensate for 1736 * differences between various platforms 1737 */ 1738 static cfga_err_t 1739 fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name, 1740 char **errstring) 1741 { 1742 char *buf; 1743 char *tmp; 1744 char *ptr; 1745 1746 di_node_t ap_node; 1747 1748 ap_log_id[0] = '\0'; 1749 1750 if (check_devlinks(ap_log_id, ap_id) == CFGA_OK) 1751 return (CFGA_OK); 1752 1753 DBG(1, ("fix_ap_name: %s\n", ap_id)); 1754 1755 if ((buf = malloc(strlen(ap_id) + 1)) == NULL) { 1756 DBG(1, ("malloc failed\n")); 1757 return (CFGA_ERROR); 1758 } 1759 (void) strcpy(buf, ap_id); 1760 tmp = buf + sizeof ("/devices") - 1; 1761 1762 ptr = strchr(tmp, ':'); 1763 ptr[0] = '\0'; 1764 1765 DBG(1, ("fix_ap_name: %s\n", tmp)); 1766 1767 ap_node = di_init(tmp, DINFOMINOR); 1768 if (ap_node == DI_NODE_NIL) { 1769 cfga_err(errstring, "di_init ", 0); 1770 DBG(1, ("fix_ap_name: failed to snapshot node\n")); 1771 return (CFGA_ERROR); 1772 } 1773 1774 (void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s", 1775 di_driver_name(ap_node), di_instance(ap_node), slot_name); 1776 1777 DBG(1, ("fix_ap_name: %s\n", ap_log_id)); 1778 1779 di_fini(ap_node); 1780 1781 free(buf); 1782 return (CFGA_OK); 1783 } 1784 1785 /*ARGSUSED*/ 1786 cfga_err_t 1787 cfga_list_ext(const char *ap_id, cfga_list_data_t **cs, 1788 int *nlist, const char *options, const char *listopts, char **errstring, 1789 cfga_flags_t flags) 1790 { 1791 devctl_hdl_t dcp; 1792 struct hpc_control_data iocdata; 1793 devctl_ap_state_t state; 1794 hpc_board_type_t boardtype; 1795 hpc_card_info_t cardinfo; 1796 hpc_slot_info_t slot_info; 1797 struct searcharg slotname_arg; 1798 int fd; 1799 int rv = CFGA_OK; 1800 1801 if ((rv = check_options(options)) != CFGA_OK) { 1802 return (rv); 1803 } 1804 1805 if (errstring != NULL) 1806 *errstring = NULL; 1807 1808 (void) memset(&slot_info, 0, sizeof (hpc_slot_info_t)); 1809 1810 DBG(1, ("cfga_list_ext:(%s)\n", ap_id)); 1811 1812 if (cs == NULL || nlist == NULL) { 1813 rv = CFGA_ERROR; 1814 return (rv); 1815 } 1816 1817 *nlist = 1; 1818 1819 if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) { 1820 cfga_err(errstring, "malloc ", 0); 1821 DBG(1, ("malloc failed\n")); 1822 rv = CFGA_ERROR; 1823 return (rv); 1824 } 1825 1826 if ((dcp = devctl_ap_acquire((char *)ap_id, 0)) == NULL) { 1827 cfga_err(errstring, CMD_GETSTAT, 0); 1828 DBG(2, ("cfga_list_ext::(devctl_ap_acquire())\n")); 1829 rv = CFGA_ERROR; 1830 return (rv); 1831 } 1832 1833 if (devctl_ap_getstate(dcp, NULL, &state) == -1) { 1834 cfga_err(errstring, ERR_AP_ERR, ap_id, 0); 1835 devctl_release((devctl_hdl_t)dcp); 1836 DBG(2, ("cfga_list_ext::(devctl_ap_getstate())\n")); 1837 rv = CFGA_ERROR; 1838 return (rv); 1839 } 1840 1841 switch (state.ap_rstate) { 1842 case AP_RSTATE_EMPTY: 1843 (*cs)->ap_r_state = CFGA_STAT_EMPTY; 1844 DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n")); 1845 break; 1846 case AP_RSTATE_DISCONNECTED: 1847 (*cs)->ap_r_state = CFGA_STAT_DISCONNECTED; 1848 DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n")); 1849 break; 1850 case AP_RSTATE_CONNECTED: 1851 (*cs)->ap_r_state = CFGA_STAT_CONNECTED; 1852 DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n")); 1853 break; 1854 default: 1855 cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 1856 rv = CFGA_ERROR; 1857 devctl_release((devctl_hdl_t)dcp); 1858 return (rv); 1859 } 1860 1861 switch (state.ap_ostate) { 1862 case AP_OSTATE_CONFIGURED: 1863 (*cs)->ap_o_state = CFGA_STAT_CONFIGURED; 1864 DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n")); 1865 break; 1866 case AP_OSTATE_UNCONFIGURED: 1867 (*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED; 1868 DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n")); 1869 break; 1870 default: 1871 cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 1872 rv = CFGA_ERROR; 1873 devctl_release((devctl_hdl_t)dcp); 1874 return (rv); 1875 } 1876 1877 switch (state.ap_condition) { 1878 case AP_COND_OK: 1879 (*cs)->ap_cond = CFGA_COND_OK; 1880 DBG(2, ("ap_cond = CFGA_COND_OK\n")); 1881 break; 1882 case AP_COND_FAILING: 1883 (*cs)->ap_cond = CFGA_COND_FAILING; 1884 DBG(2, ("ap_cond = CFGA_COND_FAILING\n")); 1885 break; 1886 case AP_COND_FAILED: 1887 (*cs)->ap_cond = CFGA_COND_FAILED; 1888 DBG(2, ("ap_cond = CFGA_COND_FAILED\n")); 1889 break; 1890 case AP_COND_UNUSABLE: 1891 (*cs)->ap_cond = CFGA_COND_UNUSABLE; 1892 DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n")); 1893 break; 1894 case AP_COND_UNKNOWN: 1895 (*cs)->ap_cond = CFGA_COND_UNKNOWN; 1896 DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n")); 1897 break; 1898 default: 1899 cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 1900 rv = CFGA_ERROR; 1901 devctl_release((devctl_hdl_t)dcp); 1902 return (rv); 1903 } 1904 (*cs)->ap_busy = (int)state.ap_in_transition; 1905 1906 devctl_release((devctl_hdl_t)dcp); 1907 1908 if ((fd = open(ap_id, O_RDWR)) == -1) { 1909 cfga_err(errstring, ERR_AP_ERR, ap_id, 0); 1910 (*cs)->ap_status_time = 0; 1911 boardtype = HPC_BOARD_UNKNOWN; 1912 cardinfo.base_class = PCI_CLASS_NONE; 1913 get_logical_name(ap_id, slot_info.pci_slot_name, 0); 1914 DBG(2, ("open on %s failed\n", ap_id)); 1915 goto cont; 1916 } 1917 DBG(1, ("open = ap_id=%s, fd=%d\n", ap_id, fd)); 1918 1919 (*cs)->ap_status_time = state.ap_last_change; 1920 1921 /* need board type and a way to get to hpc_slot_info */ 1922 build_control_data(&iocdata, HPC_CTRL_GET_BOARD_TYPE, 1923 (void *)&boardtype); 1924 1925 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1926 boardtype = HPC_BOARD_UNKNOWN; 1927 } 1928 DBG(1, ("ioctl boardtype\n")); 1929 1930 build_control_data(&iocdata, HPC_CTRL_GET_SLOT_INFO, 1931 (void *)&slot_info); 1932 1933 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1934 get_logical_name(ap_id, slot_info.pci_slot_name, 0); 1935 DBG(1, ("ioctl failed slotinfo: %s\n", 1936 slot_info.pci_slot_name)); 1937 } else { 1938 1939 /* 1940 * the driver will report back things like hpc0_slot0 1941 * this needs to be changed to things like pci1:hpc0_slot0 1942 */ 1943 rv = fix_ap_name((*cs)->ap_log_id, 1944 ap_id, slot_info.pci_slot_name, errstring); 1945 DBG(1, ("ioctl slotinfo: %s\n", (*cs)->ap_log_id)); 1946 } 1947 1948 build_control_data(&iocdata, HPC_CTRL_GET_CARD_INFO, 1949 (void *)&cardinfo); 1950 1951 if (ioctl(fd, DEVCTL_AP_CONTROL, &iocdata) == -1) { 1952 DBG(1, ("ioctl failed\n")); 1953 cardinfo.base_class = PCI_CLASS_NONE; 1954 } 1955 1956 DBG(1, ("ioctl cardinfo: %d\n", cardinfo.base_class)); 1957 DBG(1, ("ioctl subclass: %d\n", cardinfo.sub_class)); 1958 DBG(1, ("ioctl headertype: %d\n", cardinfo.header_type)); 1959 1960 (void) close(fd); 1961 1962 cont: 1963 (void) strcpy((*cs)->ap_phys_id, ap_id); /* physical path of AP */ 1964 if ((*cs)->ap_log_id[0] == '\0') 1965 (void) strcpy((*cs)->ap_log_id, slot_info.pci_slot_name); 1966 1967 /* slot_names of bus node */ 1968 if (find_physical_slot_names(ap_id, &slotname_arg) != -1) 1969 (void) strcpy((*cs)->ap_info, 1970 slotname_arg.slotnames[slotname_arg.minor]); 1971 1972 (void) memset((*cs)->ap_type, 0, CFGA_TYPE_LEN); 1973 /* class_code/subclass/boardtype */ 1974 get_type(boardtype, cardinfo, (*cs)->ap_type); 1975 1976 DBG(1, ("cfga_list_ext return success\n")); 1977 rv = CFGA_OK; 1978 1979 return (rv); 1980 } 1981 1982 /* 1983 * This routine prints a single line of help message 1984 */ 1985 static void 1986 cfga_msg(struct cfga_msg *msgp, const char *str) 1987 { 1988 DBG(2, ("<%s>", str)); 1989 1990 if (msgp == NULL || msgp->message_routine == NULL) 1991 return; 1992 1993 (*msgp->message_routine)(msgp->appdata_ptr, str); 1994 (*msgp->message_routine)(msgp->appdata_ptr, "\n"); 1995 } 1996 1997 static cfga_err_t 1998 check_options(const char *options) 1999 { 2000 struct cfga_msg *msgp = NULL; 2001 2002 if (options) { 2003 cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 2004 cfga_msg(msgp, options); 2005 return (CFGA_INVAL); 2006 } 2007 return (CFGA_OK); 2008 } 2009 2010 /*ARGSUSED*/ 2011 cfga_err_t 2012 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 2013 { 2014 if (options) { 2015 cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 2016 cfga_msg(msgp, options); 2017 } 2018 DBG(1, ("cfga_help\n")); 2019 2020 cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER])); 2021 cfga_msg(msgp, cfga_strs[HELP_CONFIG]); 2022 cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]); 2023 cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]); 2024 cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]); 2025 cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]); 2026 cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]); 2027 return (CFGA_OK); 2028 } 2029 2030 /* 2031 * cfga_err() accepts a variable number of message IDs and constructs 2032 * a corresponding error string which is returned via the errstring argument. 2033 * cfga_err() calls gettext() to internationalize proper messages. 2034 */ 2035 static void 2036 cfga_err(char **errstring, ...) 2037 { 2038 int a; 2039 int i; 2040 int n; 2041 int len; 2042 int flen; 2043 char *p; 2044 char *q; 2045 char *s[32]; 2046 char *failed; 2047 va_list ap; 2048 2049 /* 2050 * If errstring is null it means user in not interested in getting 2051 * error status. So we don't do all the work 2052 */ 2053 if (errstring == NULL) { 2054 return; 2055 } 2056 va_start(ap, errstring); 2057 2058 failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]); 2059 flen = strlen(failed); 2060 2061 for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) { 2062 switch (a) { 2063 case CMD_GETSTAT: 2064 case CMD_LIST: 2065 case CMD_SLOT_CONNECT: 2066 case CMD_SLOT_DISCONNECT: 2067 case CMD_SLOT_CONFIGURE: 2068 case CMD_SLOT_UNCONFIGURE: 2069 p = cfga_errstrs(a); 2070 len += (strlen(p) + flen); 2071 s[n] = p; 2072 s[++n] = cfga_strs[FAILED]; 2073 2074 DBG(2, ("<%s>", p)); 2075 DBG(2, (cfga_strs[FAILED])); 2076 break; 2077 2078 case ERR_CMD_INVAL: 2079 case ERR_AP_INVAL: 2080 case ERR_OPT_INVAL: 2081 case ERR_AP_ERR: 2082 switch (a) { 2083 case ERR_CMD_INVAL: 2084 p = dgettext(TEXT_DOMAIN, 2085 cfga_errstrs[ERR_CMD_INVAL]); 2086 break; 2087 case ERR_AP_INVAL: 2088 p = dgettext(TEXT_DOMAIN, 2089 cfga_errstrs[ERR_AP_INVAL]); 2090 break; 2091 case ERR_OPT_INVAL: 2092 p = dgettext(TEXT_DOMAIN, 2093 cfga_errstrs[ERR_OPT_INVAL]); 2094 break; 2095 case ERR_AP_ERR: 2096 p = dgettext(TEXT_DOMAIN, 2097 cfga_errstrs[ERR_AP_ERR]); 2098 break; 2099 } 2100 2101 if ((q = va_arg(ap, char *)) != NULL) { 2102 len += (strlen(p) + strlen(q)); 2103 s[n] = p; 2104 s[++n] = q; 2105 DBG(2, ("<%s>", p)); 2106 DBG(2, ("<%s>", q)); 2107 break; 2108 } else { 2109 len += strlen(p); 2110 s[n] = p; 2111 2112 } 2113 DBG(2, ("<%s>", p)); 2114 break; 2115 2116 default: 2117 n--; 2118 break; 2119 } 2120 } 2121 2122 DBG(2, ("\n")); 2123 va_end(ap); 2124 2125 if ((p = calloc(len + 1, 1)) == NULL) 2126 return; 2127 2128 for (i = 0; i < n; i++) { 2129 (void) strlcat(p, s[i], len + 1); 2130 DBG(2, ("i:%d, %s\n", i, s[i])); 2131 } 2132 2133 *errstring = p; 2134 #ifdef DEBUG 2135 printf("%s\n", *errstring); 2136 free(*errstring); 2137 #endif 2138 } 2139 2140 /* 2141 * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm 2142 */ 2143