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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <devfsadm.h> 28 #include <stdio.h> 29 #include <strings.h> 30 #include <stdlib.h> 31 #include <stdarg.h> 32 #include <limits.h> 33 #include <unistd.h> 34 #include <config_admin.h> 35 #include <cfg_link.h> 36 #include <sys/types.h> 37 #include <sys/mkdev.h> 38 #include <sys/hotplug/pci/pcihp.h> 39 40 #ifdef DEBUG 41 #define dprint(args) devfsadm_errprint args 42 /* 43 * for use in print routine arg list as a shorthand way to locate node via 44 * "prtconf -D" to avoid messy and cluttered debugging code 45 * don't forget the corresponding "%s%d" format 46 */ 47 #define DRVINST(node) di_driver_name(node), di_instance(node) 48 #else 49 #define dprint(args) 50 #endif 51 52 53 static int scsi_cfg_creat_cb(di_minor_t minor, di_node_t node); 54 static int sbd_cfg_creat_cb(di_minor_t minor, di_node_t node); 55 static int usb_cfg_creat_cb(di_minor_t minor, di_node_t node); 56 static char *get_roothub(const char *path, void *cb_arg); 57 static int pci_cfg_creat_cb(di_minor_t minor, di_node_t node); 58 static int ib_cfg_creat_cb(di_minor_t minor, di_node_t node); 59 static int sata_cfg_creat_cb(di_minor_t minor, di_node_t node); 60 static int sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node); 61 62 static di_node_t pci_cfg_chassis_node(di_node_t, di_prom_handle_t); 63 static char *pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t); 64 static int pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t, 65 char *, int, int); 66 static int pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t, 67 char *, int); 68 static minor_t pci_cfg_pcidev(di_node_t, di_prom_handle_t); 69 static int pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t, 70 char *, int, char **); 71 static char *pci_cfg_info_data(char *); 72 static int pci_cfg_is_ap_path(di_node_t, di_prom_handle_t); 73 static int pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t, 74 char *, int); 75 static void pci_cfg_rm_invalid_links(char *, char *); 76 static void pci_cfg_rm_link(char *); 77 static void pci_cfg_rm_all(char *); 78 static char *pci_cfg_devpath(di_node_t, di_minor_t); 79 static di_node_t pci_cfg_snapshot(di_node_t, di_minor_t, 80 di_node_t *, di_minor_t *); 81 82 /* flag definitions for di_propall_*(); value "0" is always the default flag */ 83 #define DIPROP_PRI_NODE 0x0 84 #define DIPROP_PRI_PROM 0x1 85 static int di_propall_lookup_ints(di_prom_handle_t, int, 86 dev_t, di_node_t, const char *, int **); 87 static int di_propall_lookup_strings(di_prom_handle_t, int, 88 dev_t, di_node_t, const char *, char **); 89 static int serid_printable(uint64_t *seridp); 90 static int di_propall_lookup_slot_names(di_prom_handle_t, int, 91 dev_t, di_node_t, di_slot_name_t **); 92 93 94 /* 95 * NOTE: The CREATE_DEFER flag is private to this module. 96 * NOT to be used by other modules 97 */ 98 static devfsadm_create_t cfg_create_cbt[] = { 99 { "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL, 100 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 101 }, 102 { "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL, 103 TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb 104 }, 105 { "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL, 106 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 107 }, 108 { "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL, 109 TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb 110 }, 111 { "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL, 112 TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb 113 }, 114 { "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL, 115 TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb 116 }, 117 { "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL, 118 TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb 119 }, 120 { "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL, 121 TYPE_EXACT, ILEVEL_0, sdcard_cfg_creat_cb 122 } 123 }; 124 125 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt); 126 127 static devfsadm_remove_t cfg_remove_cbt[] = { 128 { "attachment-point", SCSI_CFG_LINK_RE, RM_POST, 129 ILEVEL_0, devfsadm_rm_all 130 }, 131 { "attachment-point", SBD_CFG_LINK_RE, RM_POST, 132 ILEVEL_0, devfsadm_rm_all 133 }, 134 { "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST, 135 ILEVEL_0, devfsadm_rm_all 136 }, 137 { "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 138 ILEVEL_0, devfsadm_rm_all 139 }, 140 { "attachment-point", PCI_CFG_LINK_RE, RM_POST, 141 ILEVEL_0, devfsadm_rm_all 142 }, 143 { "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT, 144 ILEVEL_0, pci_cfg_rm_all 145 }, 146 { "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 147 ILEVEL_0, devfsadm_rm_all 148 }, 149 { "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 150 ILEVEL_0, devfsadm_rm_all 151 }, 152 { "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 153 ILEVEL_0, devfsadm_rm_all 154 }, 155 }; 156 157 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt); 158 159 static int 160 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node) 161 { 162 char path[PATH_MAX + 1]; 163 char *c_num = NULL, *devfs_path, *mn; 164 devfsadm_enumerate_t rules[3] = { 165 {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 166 {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 167 {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 168 }; 169 170 mn = di_minor_name(minor); 171 172 if ((devfs_path = di_devfs_path(node)) == NULL) { 173 return (DEVFSADM_CONTINUE); 174 } 175 (void) strcpy(path, devfs_path); 176 (void) strcat(path, ":"); 177 (void) strcat(path, mn); 178 di_devfs_path_free(devfs_path); 179 180 if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3) 181 == DEVFSADM_FAILURE) { 182 /* 183 * Unlike the disks module we don't retry on failure. 184 * If we have multiple "c" numbers for a single physical 185 * controller due to bug 4045879, we will not assign a 186 * c-number/symlink for the controller. 187 */ 188 return (DEVFSADM_CONTINUE); 189 } 190 191 (void) strcpy(path, CFG_DIRNAME); 192 (void) strcat(path, "/c"); 193 (void) strcat(path, c_num); 194 195 free(c_num); 196 197 (void) devfsadm_mklink(path, node, minor, 0); 198 199 return (DEVFSADM_CONTINUE); 200 } 201 202 static int 203 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node) 204 { 205 char path[PATH_MAX + 1]; 206 207 (void) strcpy(path, CFG_DIRNAME); 208 (void) strcat(path, "/"); 209 (void) strcat(path, di_minor_name(minor)); 210 (void) devfsadm_mklink(path, node, minor, 0); 211 return (DEVFSADM_CONTINUE); 212 } 213 214 215 static int 216 usb_cfg_creat_cb(di_minor_t minor, di_node_t node) 217 { 218 char *cp, path[PATH_MAX + 1]; 219 devfsadm_enumerate_t rules[1] = 220 {"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub}; 221 222 if ((cp = di_devfs_path(node)) == NULL) { 223 return (DEVFSADM_CONTINUE); 224 } 225 226 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 227 di_devfs_path_free(cp); 228 229 if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) { 230 return (DEVFSADM_CONTINUE); 231 } 232 233 /* create usbN and the symlink */ 234 (void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp, 235 di_minor_name(minor)); 236 free(cp); 237 238 (void) devfsadm_mklink(path, node, minor, 0); 239 240 return (DEVFSADM_CONTINUE); 241 } 242 243 244 static int 245 sata_cfg_creat_cb(di_minor_t minor, di_node_t node) 246 { 247 char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath; 248 char *minor_nm; 249 devfsadm_enumerate_t rules[1] = 250 {"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR}; 251 252 minor_nm = di_minor_name(minor); 253 if (minor_nm == NULL) 254 return (DEVFSADM_CONTINUE); 255 256 devfspath = di_devfs_path(node); 257 if (devfspath == NULL) 258 return (DEVFSADM_CONTINUE); 259 260 (void) strlcpy(path, devfspath, sizeof (path)); 261 (void) strlcat(path, ":", sizeof (path)); 262 (void) strlcat(path, minor_nm, sizeof (path)); 263 di_devfs_path_free(devfspath); 264 265 /* build the physical path from the components */ 266 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) == 267 DEVFSADM_FAILURE) { 268 return (DEVFSADM_CONTINUE); 269 } 270 271 (void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME, 272 buf, minor_nm); 273 free(buf); 274 275 (void) devfsadm_mklink(l_path, node, minor, 0); 276 277 return (DEVFSADM_CONTINUE); 278 } 279 280 static int 281 sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node) 282 { 283 char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath; 284 char *minor_nm; 285 devfsadm_enumerate_t rules[1] = 286 {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR}; 287 288 minor_nm = di_minor_name(minor); 289 if (minor_nm == NULL) 290 return (DEVFSADM_CONTINUE); 291 292 devfspath = di_devfs_path(node); 293 if (devfspath == NULL) 294 return (DEVFSADM_CONTINUE); 295 296 (void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm); 297 di_devfs_path_free(devfspath); 298 299 /* build the physical path from the components */ 300 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) == 301 DEVFSADM_FAILURE) { 302 return (DEVFSADM_CONTINUE); 303 } 304 305 (void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s", 306 CFG_DIRNAME, buf, minor_nm); 307 free(buf); 308 309 (void) devfsadm_mklink(l_path, node, minor, 0); 310 311 return (DEVFSADM_CONTINUE); 312 } 313 314 /* 315 * get_roothub: 316 * figure out the root hub path to calculate /dev/cfg/usbN 317 */ 318 /* ARGSUSED */ 319 static char * 320 get_roothub(const char *path, void *cb_arg) 321 { 322 int i, count = 0; 323 char *physpath, *cp; 324 325 /* make a copy */ 326 if ((physpath = strdup(path)) == NULL) { 327 return (NULL); 328 } 329 330 /* 331 * physpath must always have a minor name component 332 */ 333 if ((cp = strrchr(physpath, ':')) == NULL) { 334 free(physpath); 335 return (NULL); 336 } 337 *cp++ = '\0'; 338 339 /* 340 * No '.' in the minor name indicates a roothub port. 341 */ 342 if (strchr(cp, '.') == NULL) { 343 /* roothub device */ 344 return (physpath); 345 } 346 347 while (*cp) { 348 if (*cp == '.') 349 count++; 350 cp++; 351 } 352 353 /* Remove as many trailing path components as there are '.'s */ 354 for (i = 0; i < count; i++) { 355 if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) { 356 free(physpath); 357 return (NULL); 358 } 359 /* 360 * Check if there is any usb_mid node in the middle 361 * and remove the node as if there is an extra '.' 362 */ 363 if (strstr(cp, "miscellaneous") != NULL) { 364 count++; 365 } 366 *cp = '\0'; 367 } 368 369 /* Remove the usb_mid node immediately before the trailing path */ 370 if ((cp = strrchr(physpath, '/')) != NULL && (cp != physpath)) { 371 if (strstr(cp, "miscellaneous") != NULL) { 372 *cp = '\0'; 373 } 374 } 375 376 return (physpath); 377 } 378 379 380 /* 381 * returns an allocted string containing the device path for <node> and 382 * <minor> 383 */ 384 static char * 385 pci_cfg_devpath(di_node_t node, di_minor_t minor) 386 { 387 char *path; 388 char *bufp; 389 char *minor_nm; 390 int buflen; 391 392 path = di_devfs_path(node); 393 minor_nm = di_minor_name(minor); 394 buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1; 395 396 bufp = malloc(sizeof (char) * buflen); 397 if (bufp != NULL) 398 (void) snprintf(bufp, buflen, "%s:%s", path, minor_nm); 399 400 di_devfs_path_free(path); 401 return (bufp); 402 } 403 404 405 static int 406 di_propall_lookup_ints(di_prom_handle_t ph, int flags, 407 dev_t dev, di_node_t node, const char *prop_name, int **prop_data) 408 { 409 int rv; 410 411 if (flags & DIPROP_PRI_PROM) { 412 rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data); 413 if (rv < 0) 414 rv = di_prop_lookup_ints(dev, node, prop_name, 415 prop_data); 416 } else { 417 rv = di_prop_lookup_ints(dev, node, prop_name, prop_data); 418 if (rv < 0) 419 rv = di_prom_prop_lookup_ints(ph, node, prop_name, 420 prop_data); 421 } 422 return (rv); 423 } 424 425 426 static int 427 di_propall_lookup_strings(di_prom_handle_t ph, int flags, 428 dev_t dev, di_node_t node, const char *prop_name, char **prop_data) 429 { 430 int rv; 431 432 if (flags & DIPROP_PRI_PROM) { 433 rv = di_prom_prop_lookup_strings(ph, node, prop_name, 434 prop_data); 435 if (rv < 0) 436 rv = di_prop_lookup_strings(dev, node, prop_name, 437 prop_data); 438 } else { 439 rv = di_prop_lookup_strings(dev, node, prop_name, prop_data); 440 if (rv < 0) 441 rv = di_prom_prop_lookup_strings(ph, node, prop_name, 442 prop_data); 443 } 444 return (rv); 445 } 446 447 448 static di_node_t 449 pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph) 450 { 451 di_node_t curnode = node; 452 int *firstchas; 453 454 do { 455 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode, 456 DI_PROP_FIRST_CHAS, &firstchas) >= 0) 457 return (curnode); 458 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 459 460 return (DI_NODE_NIL); 461 } 462 463 464 static int 465 di_propall_lookup_slot_names(di_prom_handle_t ph, int flags, 466 dev_t dev, di_node_t node, di_slot_name_t **prop_data) 467 { 468 int rv; 469 470 if (flags & DIPROP_PRI_PROM) { 471 rv = di_prom_prop_lookup_slot_names(ph, node, prop_data); 472 if (rv < 0) 473 rv = di_prop_lookup_slot_names(dev, node, prop_data); 474 } else { 475 rv = di_prop_lookup_slot_names(dev, node, prop_data); 476 if (rv < 0) 477 rv = di_prom_prop_lookup_slot_names(ph, node, 478 prop_data); 479 } 480 return (rv); 481 } 482 483 /* 484 * returns an allocated string containing the slot name for the slot with 485 * device number <pci_dev> on bus <node> 486 */ 487 static char * 488 pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev) 489 { 490 #ifdef DEBUG 491 char *fnm = "pci_cfg_slotname"; 492 #endif 493 int i, count; 494 char *name = NULL; 495 di_slot_name_t *slot_names = NULL; 496 497 count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node, 498 &slot_names); 499 if (count < 0) 500 return (NULL); 501 502 for (i = 0; i < count; i++) { 503 if (slot_names[i].num == (int)pci_dev) { 504 name = strdup(slot_names[i].name); 505 break; 506 } 507 } 508 #ifdef DEBUG 509 if (name == NULL) 510 dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n", 511 fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node))); 512 #endif 513 if (count > 0) 514 di_slot_names_free(count, slot_names); 515 return (name); 516 } 517 518 519 /* 520 * returns non-zero if we can return a valid attachment point name for <node>, 521 * for its slot identified by child pci device number <pci_dev>, through <buf> 522 * 523 * prioritized naming scheme: 524 * 1) <DI_PROP_SLOT_NAMES property> (see pci_cfg_slotname()) 525 * 2) <device-type><DI_PROP_PHYS_SLOT property> 526 * 3) <drv name><drv inst>.<device-type><pci_dev> 527 * 528 * where <device-type> is derived from the DI_PROP_DEV_TYPE property: 529 * if its value is "pciex" then <device-type> is "pcie" 530 * else the raw value is used 531 * 532 * if <flags> contains APNODE_DEFNAME, then scheme (3) is used 533 */ 534 static int 535 pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph, 536 char *buf, int bufsz, int flags) 537 { 538 int *nump; 539 int rv; 540 char *str, *devtype; 541 542 rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node, 543 DI_PROP_DEV_TYPE, &devtype); 544 if (rv < 1) 545 return (0); 546 547 if (strcmp(devtype, PROPVAL_PCIEX) == 0) 548 devtype = DEVTYPE_PCIE; 549 550 if (flags & APNODE_DEFNAME) 551 goto DEF; 552 553 str = pci_cfg_slotname(node, ph, pci_dev); 554 if (str != NULL) { 555 (void) strlcpy(buf, str, bufsz); 556 free(str); 557 return (1); 558 } 559 560 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, 561 DI_PROP_PHYS_SLOT, &nump) > 0) { 562 if (*nump > 0) { 563 (void) snprintf(buf, bufsz, "%s%d", devtype, *nump); 564 return (1); 565 } 566 } 567 DEF: 568 (void) snprintf(buf, bufsz, "%s%d.%s%d", 569 di_driver_name(node), di_instance(node), devtype, pci_dev); 570 571 return (1); 572 } 573 574 575 /* 576 * returns non-zero if we can return a valid expansion chassis name for <node> 577 * through <buf> 578 * 579 * prioritized naming scheme: 580 * 1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion> 581 * 2) <IOB_PRE string><full DI_PROP_SERID property in hex> 582 * 3) <IOB_PRE string> 583 * 584 * DI_PROP_SERID encoding <64-bit int: msb ... lsb>: 585 * <24 bits: IEEE company id><40 bits: serial number> 586 * 587 * sun encoding of 40 bit serial number: 588 * first byte = device type indicator 589 * next 4 bytes = 4 ascii characters 590 * 591 * In the unlikely event that serial id contains non-printable characters 592 * the full 64 bit raw hex string will be used for the attachment point. 593 */ 594 /*ARGSUSED*/ 595 static int 596 pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 597 char *buf, int bufsz) 598 { 599 int64_t *seridp; 600 uint64_t serid; 601 char *idstr; 602 603 if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID, 604 &seridp) < 1) { 605 (void) strlcpy(buf, IOB_PRE, bufsz); 606 return (1); 607 } 608 609 serid = (uint64_t)*seridp; 610 611 if ((serid >> 40) != (uint64_t)IEEE_SUN_ID || 612 !serid_printable(&serid)) { 613 (void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid); 614 return (1); 615 } 616 617 /* 618 * the serial id is constructed from lower 40 bits of the serialid 619 * property and is represented by 5 ascii characters. The first 620 * character indicates if the IO Box is PCIe or PCI-X. 621 */ 622 623 serid <<= 24; 624 idstr = (char *)&serid; 625 idstr[sizeof (serid) -1] = '\0'; 626 627 (void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr); 628 629 return (1); 630 } 631 632 633 /* 634 * returns the pci device number for <node> if found, else returns PCIDEV_NIL 635 */ 636 static minor_t 637 pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph) 638 { 639 int rv; 640 int *regp; 641 642 rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG, 643 ®p); 644 645 if (rv < 1) { 646 dprint(("pci_cfg_pcidev: property %s not found " 647 "for %s%d\n", DI_PROP_REG, DRVINST(node))); 648 return (PCIDEV_NIL); 649 } 650 651 return (REG_PCIDEV(regp)); 652 } 653 654 655 /* 656 * returns non-zero when it can successfully return an attachment point 657 * through <ap_path> whose length is less than <ap_pathsz>; returns the full 658 * path of the AP through <pathret> which may be larger than <ap_pathsz>. 659 * Callers need to free <pathret>. If it cannot return the full path through 660 * <pathret> it will be set to NULL 661 * 662 * The ap path reflects a subset of the device path from an onboard host slot 663 * up to <node>. We traverse up the device tree starting from <node>, naming 664 * each component using pci_cfg_ap_node(). If we detect that a certain 665 * segment is contained within an expansion chassis, then we skip any bus 666 * nodes in between our current node and the topmost node of the chassis, 667 * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name 668 * of the expansion chassis as given by pci_cfg_iob_name() 669 * 670 * This scheme is always used for <pathret>. If however, the size of 671 * <pathret> is greater than <ap_pathsz> then only the default name as given 672 * by pci_cfg_ap_node() for <node> will be used 673 */ 674 static int 675 pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 676 char *ap_path, int ap_pathsz, char **pathret) 677 { 678 #ifdef DEBUG 679 char *fnm = "pci_cfg_ap_path"; 680 #endif 681 #define seplen (sizeof (AP_PATH_SEP) - 1) 682 #define iob_pre_len (sizeof (IOB_PRE) - 1) 683 #define ap_path_iob_sep_len (sizeof (AP_PATH_IOB_SEP) - 1) 684 685 char *bufptr; 686 char buf[MAXPATHLEN]; 687 char pathbuf[MAXPATHLEN]; 688 int bufsz; 689 char *pathptr; 690 char *pathend = NULL; 691 int len; 692 int rv = 0; 693 int chasflag = 0; 694 di_node_t curnode = node; 695 di_node_t chasnode = DI_NODE_NIL; 696 minor_t pci_dev; 697 698 buf[0] = '\0'; 699 pathbuf[0] = '\0'; 700 pathptr = &pathbuf[sizeof (pathbuf) - 1]; 701 *pathptr = '\0'; 702 703 /* 704 * as we traverse up the device tree, we prepend components of our 705 * path inside pathbuf, using pathptr and decrementing 706 */ 707 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 708 do { 709 bufptr = buf; 710 bufsz = sizeof (buf); 711 712 chasnode = pci_cfg_chassis_node(curnode, ph); 713 if (chasnode != DI_NODE_NIL) { 714 rv = pci_cfg_iob_name(minor, chasnode, ph, 715 bufptr, bufsz); 716 if (rv == 0) { 717 dprint(("%s: cannot create iob name " 718 "for %s%d\n", fnm, DRVINST(node))); 719 *pathptr = '\0'; 720 goto OUT; 721 } 722 723 (void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz); 724 len = strlen(bufptr); 725 bufptr += len; 726 bufsz -= len - 1; 727 728 /* set chasflag when the leaf node is within an iob */ 729 if ((curnode == node) != NULL) 730 chasflag = 1; 731 } 732 rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0); 733 if (rv == 0) { 734 dprint(("%s: cannot create ap node name " 735 "for %s%d\n", fnm, DRVINST(node))); 736 *pathptr = '\0'; 737 goto OUT; 738 } 739 740 /* 741 * if we can't fit the entire path in our pathbuf, then use 742 * the default short name and nullify pathptr; also, since 743 * we prepend in the buffer, we must avoid adding a null char 744 */ 745 if (curnode != node) { 746 pathptr -= seplen; 747 if (pathptr < pathbuf) { 748 pathptr = pathbuf; 749 *pathptr = '\0'; 750 goto DEF; 751 } 752 (void) memcpy(pathptr, AP_PATH_SEP, seplen); 753 } 754 len = strlen(buf); 755 pathptr -= len; 756 if (pathptr < pathbuf) { 757 pathptr = pathbuf; 758 *pathptr = '\0'; 759 goto DEF; 760 } 761 (void) memcpy(pathptr, buf, len); 762 763 /* remember the leaf component */ 764 if (curnode == node) 765 pathend = pathptr; 766 767 /* 768 * go no further than the hosts' onboard slots 769 */ 770 if (chasnode == DI_NODE_NIL) 771 break; 772 curnode = chasnode; 773 774 /* 775 * the pci device number of the current node is used to 776 * identify which slot of the parent's bus (next iteration) 777 * the current node is on 778 */ 779 pci_dev = pci_cfg_pcidev(curnode, ph); 780 if (pci_dev == PCIDEV_NIL) { 781 dprint(("%s: cannot obtain pci device number " 782 "for %s%d\n", fnm, DRVINST(node))); 783 *pathptr = '\0'; 784 goto OUT; 785 } 786 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 787 788 pathbuf[sizeof (pathbuf) - 1] = '\0'; 789 if (strlen(pathptr) < ap_pathsz) { 790 (void) strlcpy(ap_path, pathptr, ap_pathsz); 791 rv = 1; 792 goto OUT; 793 } 794 795 DEF: 796 /* 797 * when our name won't fit <ap_pathsz> we use the endpoint/leaf 798 * <node>'s name ONLY IF it has a serialid# which will make the apid 799 * globally unique 800 */ 801 if (chasflag && pathend != NULL) { 802 if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP, 803 ap_path_iob_sep_len) != 0) && 804 (strlen(pathend) < ap_pathsz)) { 805 (void) strlcpy(ap_path, pathend, ap_pathsz); 806 rv = 1; 807 goto OUT; 808 } 809 } 810 811 /* 812 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s 813 * default name 814 */ 815 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 816 rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME); 817 if (rv == 0) { 818 dprint(("%s: cannot create default ap node name for %s%d\n", 819 fnm, DRVINST(node))); 820 *pathptr = '\0'; 821 goto OUT; 822 } 823 if (strlen(buf) < ap_pathsz) { 824 (void) strlcpy(ap_path, buf, ap_pathsz); 825 rv = 1; 826 goto OUT; 827 } 828 829 /* 830 * in this case, cfgadm goes through an expensive process to generate 831 * a purely dynamic logical apid: the framework will look through 832 * the device tree for attachment point minor nodes and will invoke 833 * each plugin responsible for that attachment point class, and if 834 * the plugin returns a logical apid that matches the queried apid 835 * or matches the default apid generated by the cfgadm framework for 836 * that driver/class (occurs when plugin returns an empty logical apid) 837 * then that is what it will use 838 * 839 * it is doubly expensive because the cfgadm pci plugin itself will 840 * also search the entire device tree in the absence of a link 841 */ 842 rv = 0; 843 dprint(("%s: cannot create apid for %s%d within length of %d\n", 844 fnm, DRVINST(node), ap_pathsz)); 845 846 OUT: 847 ap_path[ap_pathsz - 1] = '\0'; 848 *pathret = (*pathptr == '\0') ? NULL : strdup(pathptr); 849 return (rv); 850 851 #undef seplen 852 #undef iob_pre_len 853 #undef ap_path_iob_sep_len 854 } 855 856 857 /* 858 * the DI_PROP_AP_NAMES property contains the first integer section of the 859 * ieee1275 "slot-names" property and functions as a bitmask; see comment for 860 * pci_cfg_slotname() 861 * 862 * we use the name of the attachment point minor node if its pci device 863 * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES 864 * 865 * returns non-zero if we return a valid attachment point through <path> 866 */ 867 static int 868 pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 869 char *ap_path, int ap_pathsz) 870 { 871 minor_t pci_dev; 872 int *anp; 873 874 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES, 875 &anp) < 1) 876 return (0); 877 878 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 879 if ((*anp & (1 << pci_dev)) == 0) 880 return (0); 881 882 (void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz); 883 return (1); 884 } 885 886 887 /* 888 * determine if <node> qualifies for a path style apid 889 */ 890 static int 891 pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph) 892 { 893 char *devtype; 894 di_node_t curnode = node; 895 896 do { 897 if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode, 898 DI_PROP_DEV_TYPE, &devtype) > 0) 899 if (strcmp(devtype, PROPVAL_PCIEX) == 0) 900 return (1); 901 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 902 903 return (0); 904 } 905 906 907 /* 908 * takes a full path as returned by <pathret> from pci_cfg_ap_path() and 909 * returns an allocated string intendend to be stored in a devlink info (dli) 910 * file 911 * 912 * data format: "Location: <transformed path>" 913 * where <transformed path> is <path> with occurrances of AP_PATH_SEP 914 * replaced by "/" 915 */ 916 static char * 917 pci_cfg_info_data(char *path) 918 { 919 #define head "Location: " 920 #define headlen (sizeof (head) - 1) 921 #define seplen (sizeof (AP_PATH_SEP) - 1) 922 923 char *sep, *prev, *np; 924 char *newpath; 925 int pathlen = strlen(path); 926 int len; 927 928 newpath = malloc(sizeof (char) * (headlen + pathlen + 1)); 929 np = newpath; 930 (void) strcpy(np, head); 931 np += headlen; 932 933 prev = path; 934 while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) { 935 len = sep - prev; 936 (void) memcpy(np, prev, len); 937 np += len; 938 *np++ = '/'; 939 prev = sep + seplen; 940 } 941 (void) strcpy(np, prev); 942 return (newpath); 943 944 #undef head 945 #undef headlen 946 #undef seplen 947 } 948 949 950 static void 951 pci_cfg_rm_link(char *file) 952 { 953 char *dlipath; 954 955 dlipath = di_dli_name(file); 956 (void) unlink(dlipath); 957 958 devfsadm_rm_all(file); 959 free(dlipath); 960 } 961 962 /* 963 * removes all registered devlinks to physical path <physpath> except for 964 * the devlink <valid> if not NULL; 965 * <physpath> must include the minor node 966 */ 967 static void 968 pci_cfg_rm_invalid_links(char *physpath, char *valid) 969 { 970 char **dnp; 971 char *cp, *vcp; 972 int i, dnlen; 973 974 dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen); 975 if (dnp == NULL) 976 return; 977 978 if (valid != NULL) { 979 if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0) 980 vcp = valid + DEV_LEN + 1; 981 else 982 vcp = valid; 983 } 984 985 for (i = 0; i < dnlen; i++) { 986 if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0) 987 cp = dnp[i] + DEV_LEN + 1; 988 else 989 cp = dnp[i]; 990 991 if (valid != NULL) { 992 if (strcmp(vcp, cp) == 0) 993 continue; 994 } 995 pci_cfg_rm_link(cp); 996 } 997 devfsadm_free_dev_names(dnp, dnlen); 998 } 999 1000 1001 /* 1002 * takes a complete devinfo snapshot and returns the root node; 1003 * callers must do a di_fini() on the returned node; 1004 * if the snapshot failed, DI_NODE_NIL is returned instead 1005 * 1006 * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node 1007 * in the new snapshot and return it through <ret_node> if it is found, 1008 * else DI_NODE_NIL is returned instead 1009 * 1010 * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return 1011 * the matching minor in the new snapshot through <ret_minor> if it is found, 1012 * else DI_MINOR_NIL is returned instead 1013 */ 1014 static di_node_t 1015 pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor, 1016 di_node_t *ret_node, di_minor_t *ret_minor) 1017 { 1018 di_node_t root_node; 1019 di_node_t node; 1020 di_minor_t minor; 1021 int pci_inst; 1022 dev_t pci_devt; 1023 1024 *ret_node = DI_NODE_NIL; 1025 *ret_minor = DI_MINOR_NIL; 1026 1027 root_node = di_init("/", DINFOCPYALL); 1028 if (root_node == DI_NODE_NIL) 1029 return (DI_NODE_NIL); 1030 1031 /* 1032 * narrow down search by driver, then instance, then minor 1033 */ 1034 if (pci_node == DI_NODE_NIL) 1035 return (root_node); 1036 1037 pci_inst = di_instance(pci_node); 1038 node = di_drv_first_node(di_driver_name(pci_node), root_node); 1039 do { 1040 if (pci_inst == di_instance(node)) { 1041 *ret_node = node; 1042 break; 1043 } 1044 } while ((node = di_drv_next_node(node)) != DI_NODE_NIL); 1045 1046 if (node == DI_NODE_NIL) 1047 return (root_node); 1048 1049 /* 1050 * found node, now search minors 1051 */ 1052 if (pci_minor == DI_MINOR_NIL) 1053 return (root_node); 1054 1055 pci_devt = di_minor_devt(pci_minor); 1056 minor = DI_MINOR_NIL; 1057 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 1058 if (pci_devt == di_minor_devt(minor)) { 1059 *ret_minor = minor; 1060 break; 1061 } 1062 } 1063 return (root_node); 1064 } 1065 1066 1067 static int 1068 pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node) 1069 { 1070 #ifdef DEBUG 1071 char *fnm = "pci_cfg_creat_cb"; 1072 #endif 1073 #define ap_pathsz (sizeof (ap_path)) 1074 1075 char ap_path[CFGA_LOG_EXT_LEN]; 1076 char linkbuf[MAXPATHLEN]; 1077 char *fullpath = NULL; 1078 char *pathinfo = NULL; 1079 char *devpath = NULL; 1080 int rv, fd = -1; 1081 size_t sz; 1082 di_prom_handle_t ph; 1083 di_node_t node; 1084 di_node_t root_node = DI_NODE_NIL; 1085 di_minor_t minor; 1086 1087 ph = di_prom_init(); 1088 if (ph == DI_PROM_HANDLE_NIL) { 1089 dprint(("%s: di_prom_init() failed for %s%d\n", 1090 fnm, DRVINST(pci_node))); 1091 goto OUT; 1092 } 1093 1094 /* 1095 * Since incoming nodes from hotplug events are from snapshots that 1096 * do NOT contain parent/ancestor data, we must retake our own 1097 * snapshot and search for the target node 1098 */ 1099 root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor); 1100 if (root_node == DI_NODE_NIL || node == DI_NODE_NIL || 1101 minor == DI_MINOR_NIL) { 1102 dprint(("%s: devinfo snapshot or search failed for %s%d\n", 1103 fnm, DRVINST(pci_node))); 1104 goto OUT; 1105 } 1106 1107 if (pci_cfg_is_ap_path(node, ph)) { 1108 rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz, 1109 &fullpath); 1110 if (rv == 0) 1111 goto OUT; 1112 1113 (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s", 1114 CFG_DIRNAME, ap_path); 1115 1116 /* 1117 * We must remove existing links because we may have invalid 1118 * apids that are valid links. Since these are not dangling, 1119 * devfsadm will not invoke the remove callback on them. 1120 * 1121 * What are "invalid apids with valid links"? Consider swapping 1122 * an attachment point bus with another while the system is 1123 * down, on the same device path bound to the same drivers 1124 * but with the new AP bus having different properties 1125 * (e.g. serialid#). If the previous apid is not removed, 1126 * there will now be two different links pointing to the same 1127 * attachment point, but only one reflects the correct 1128 * logical apid 1129 */ 1130 devpath = pci_cfg_devpath(node, minor); 1131 if (devpath == NULL) 1132 goto OUT; 1133 pci_cfg_rm_invalid_links(devpath, linkbuf); 1134 free(devpath); 1135 1136 (void) devfsadm_mklink(linkbuf, node, minor, 0); 1137 1138 /* 1139 * we store the full logical path of the attachment point for 1140 * cfgadm to display in its info field which is useful when 1141 * the full logical path exceeds the size limit for logical 1142 * apids (CFGA_LOG_EXT_LEN) 1143 * 1144 * for the cfgadm pci plugin to do the same would be expensive 1145 * (i.e. devinfo snapshot + top down exhaustive minor search + 1146 * equivalent of pci_cfg_ap_path() on every invocation) 1147 * 1148 * note that if we do not create a link (pci_cfg_ap_path() is 1149 * not successful), that is what cfgadm will do anyways to 1150 * create a purely dynamic apid 1151 */ 1152 pathinfo = pci_cfg_info_data(fullpath); 1153 fd = di_dli_openw(linkbuf); 1154 if (fd < 0) 1155 goto OUT; 1156 1157 sz = strlen(pathinfo) + 1; 1158 rv = write(fd, pathinfo, sz); 1159 if (rv < sz) { 1160 dprint(("%s: could not write full pathinfo to dli " 1161 "file for %s%d\n", fnm, DRVINST(node))); 1162 goto OUT; 1163 } 1164 di_dli_close(fd); 1165 } else { 1166 rv = pci_cfg_ap_legacy(minor, node, ph, ap_path, 1167 ap_pathsz); 1168 if (rv == 0) 1169 goto OUT; 1170 1171 (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s", 1172 CFG_DIRNAME, ap_path); 1173 (void) devfsadm_mklink(linkbuf, node, minor, 0); 1174 } 1175 1176 OUT: 1177 if (fd >= 0) 1178 di_dli_close(fd); 1179 if (fullpath != NULL) 1180 free(fullpath); 1181 if (pathinfo != NULL) 1182 free(pathinfo); 1183 if (ph != DI_PROM_HANDLE_NIL) 1184 di_prom_fini(ph); 1185 if (root_node != DI_NODE_NIL) 1186 di_fini(root_node); 1187 return (DEVFSADM_CONTINUE); 1188 1189 #undef ap_pathsz 1190 } 1191 1192 1193 static void 1194 pci_cfg_rm_all(char *file) 1195 { 1196 pci_cfg_rm_link(file); 1197 } 1198 1199 1200 /* 1201 * ib_cfg_creat_cb() creates two types of links 1202 * One for the fabric as /dev/cfg/ib 1203 * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID> 1204 */ 1205 static int 1206 ib_cfg_creat_cb(di_minor_t minor, di_node_t node) 1207 { 1208 char *cp; 1209 char path[PATH_MAX + 1]; 1210 1211 if ((cp = di_devfs_path(node)) == NULL) { 1212 return (DEVFSADM_CONTINUE); 1213 } 1214 1215 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 1216 di_devfs_path_free(cp); 1217 1218 /* create fabric or hca:GUID and the symlink */ 1219 if (strstr(path, "ib:fabric") != NULL) { 1220 (void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME); 1221 } else { 1222 (void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME, 1223 di_minor_name(minor)); 1224 } 1225 1226 (void) devfsadm_mklink(path, node, minor, 0); 1227 return (DEVFSADM_CONTINUE); 1228 } 1229 1230 /* 1231 * This function verifies if the serial id is printable. 1232 */ 1233 1234 static int 1235 serid_printable(uint64_t *seridp) 1236 { 1237 1238 char *ptr; 1239 int i = 0; 1240 1241 for (ptr = (char *)seridp+3; i < 5; ptr++, i++) 1242 if (*ptr < 0x21 || *ptr >= 0x7f) 1243 return (0); 1244 1245 return (1); 1246 1247 } 1248