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