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