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