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