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 2008 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 *cp = '\0'; 360 } 361 362 return (physpath); 363 } 364 365 366 /* 367 * returns an allocted string containing the device path for <node> and 368 * <minor> 369 */ 370 static char * 371 pci_cfg_devpath(di_node_t node, di_minor_t minor) 372 { 373 char *path; 374 char *bufp; 375 char *minor_nm; 376 int buflen; 377 378 path = di_devfs_path(node); 379 minor_nm = di_minor_name(minor); 380 buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1; 381 382 bufp = malloc(sizeof (char) * buflen); 383 if (bufp != NULL) 384 (void) snprintf(bufp, buflen, "%s:%s", path, minor_nm); 385 386 di_devfs_path_free(path); 387 return (bufp); 388 } 389 390 391 static int 392 di_propall_lookup_ints(di_prom_handle_t ph, int flags, 393 dev_t dev, di_node_t node, const char *prop_name, int **prop_data) 394 { 395 int rv; 396 397 if (flags & DIPROP_PRI_PROM) { 398 rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data); 399 if (rv < 0) 400 rv = di_prop_lookup_ints(dev, node, prop_name, 401 prop_data); 402 } else { 403 rv = di_prop_lookup_ints(dev, node, prop_name, prop_data); 404 if (rv < 0) 405 rv = di_prom_prop_lookup_ints(ph, node, prop_name, 406 prop_data); 407 } 408 return (rv); 409 } 410 411 412 static int 413 di_propall_lookup_strings(di_prom_handle_t ph, int flags, 414 dev_t dev, di_node_t node, const char *prop_name, char **prop_data) 415 { 416 int rv; 417 418 if (flags & DIPROP_PRI_PROM) { 419 rv = di_prom_prop_lookup_strings(ph, node, prop_name, 420 prop_data); 421 if (rv < 0) 422 rv = di_prop_lookup_strings(dev, node, prop_name, 423 prop_data); 424 } else { 425 rv = di_prop_lookup_strings(dev, node, prop_name, prop_data); 426 if (rv < 0) 427 rv = di_prom_prop_lookup_strings(ph, node, prop_name, 428 prop_data); 429 } 430 return (rv); 431 } 432 433 434 static di_node_t 435 pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph) 436 { 437 di_node_t curnode = node; 438 int *firstchas; 439 440 do { 441 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode, 442 DI_PROP_FIRST_CHAS, &firstchas) >= 0) 443 return (curnode); 444 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 445 446 return (DI_NODE_NIL); 447 } 448 449 450 static int 451 di_propall_lookup_slot_names(di_prom_handle_t ph, int flags, 452 dev_t dev, di_node_t node, di_slot_name_t **prop_data) 453 { 454 int rv; 455 456 if (flags & DIPROP_PRI_PROM) { 457 rv = di_prom_prop_lookup_slot_names(ph, node, prop_data); 458 if (rv < 0) 459 rv = di_prop_lookup_slot_names(dev, node, prop_data); 460 } else { 461 rv = di_prop_lookup_slot_names(dev, node, prop_data); 462 if (rv < 0) 463 rv = di_prom_prop_lookup_slot_names(ph, node, 464 prop_data); 465 } 466 return (rv); 467 } 468 469 /* 470 * returns an allocated string containing the slot name for the slot with 471 * device number <pci_dev> on bus <node> 472 */ 473 static char * 474 pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev) 475 { 476 #ifdef DEBUG 477 char *fnm = "pci_cfg_slotname"; 478 #endif 479 int i, count; 480 char *name = NULL; 481 di_slot_name_t *slot_names = NULL; 482 483 count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node, 484 &slot_names); 485 if (count < 0) 486 return (NULL); 487 488 for (i = 0; i < count; i++) { 489 if (slot_names[i].num == (int)pci_dev) { 490 name = strdup(slot_names[i].name); 491 break; 492 } 493 } 494 #ifdef DEBUG 495 if (name == NULL) 496 dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n", 497 fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node))); 498 #endif 499 if (count > 0) 500 di_slot_names_free(count, slot_names); 501 return (name); 502 } 503 504 505 /* 506 * returns non-zero if we can return a valid attachment point name for <node>, 507 * for its slot identified by child pci device number <pci_dev>, through <buf> 508 * 509 * prioritized naming scheme: 510 * 1) <DI_PROP_SLOT_NAMES property> (see pci_cfg_slotname()) 511 * 2) <device-type><DI_PROP_PHYS_SLOT property> 512 * 3) <drv name><drv inst>.<device-type><pci_dev> 513 * 514 * where <device-type> is derived from the DI_PROP_DEV_TYPE property: 515 * if its value is "pciex" then <device-type> is "pcie" 516 * else the raw value is used 517 * 518 * if <flags> contains APNODE_DEFNAME, then scheme (3) is used 519 */ 520 static int 521 pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph, 522 char *buf, int bufsz, int flags) 523 { 524 int *nump; 525 int rv; 526 char *str, *devtype; 527 528 rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node, 529 DI_PROP_DEV_TYPE, &devtype); 530 if (rv < 1) 531 return (0); 532 533 if (strcmp(devtype, PROPVAL_PCIEX) == 0) 534 devtype = DEVTYPE_PCIE; 535 536 if (flags & APNODE_DEFNAME) 537 goto DEF; 538 539 str = pci_cfg_slotname(node, ph, pci_dev); 540 if (str != NULL) { 541 (void) strlcpy(buf, str, bufsz); 542 free(str); 543 return (1); 544 } 545 546 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, 547 DI_PROP_PHYS_SLOT, &nump) > 0) { 548 if (*nump > 0) { 549 (void) snprintf(buf, bufsz, "%s%d", devtype, *nump); 550 return (1); 551 } 552 } 553 DEF: 554 (void) snprintf(buf, bufsz, "%s%d.%s%d", 555 di_driver_name(node), di_instance(node), devtype, pci_dev); 556 557 return (1); 558 } 559 560 561 /* 562 * returns non-zero if we can return a valid expansion chassis name for <node> 563 * through <buf> 564 * 565 * prioritized naming scheme: 566 * 1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion> 567 * 2) <IOB_PRE string><full DI_PROP_SERID property in hex> 568 * 3) <IOB_PRE string> 569 * 570 * DI_PROP_SERID encoding <64-bit int: msb ... lsb>: 571 * <24 bits: IEEE company id><40 bits: serial number> 572 * 573 * sun encoding of 40 bit serial number: 574 * first byte = device type indicator 575 * next 4 bytes = 4 ascii characters 576 * 577 * In the unlikely event that serial id contains non-printable characters 578 * the full 64 bit raw hex string will be used for the attachment point. 579 */ 580 /*ARGSUSED*/ 581 static int 582 pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 583 char *buf, int bufsz) 584 { 585 int64_t *seridp; 586 uint64_t serid; 587 char *idstr; 588 589 if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID, 590 &seridp) < 1) { 591 (void) strlcpy(buf, IOB_PRE, bufsz); 592 return (1); 593 } 594 595 serid = (uint64_t)*seridp; 596 597 if ((serid >> 40) != (uint64_t)IEEE_SUN_ID || 598 !serid_printable(&serid)) { 599 (void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid); 600 return (1); 601 } 602 603 /* 604 * the serial id is constructed from lower 40 bits of the serialid 605 * property and is represented by 5 ascii characters. The first 606 * character indicates if the IO Box is PCIe or PCI-X. 607 */ 608 609 serid <<= 24; 610 idstr = (char *)&serid; 611 idstr[sizeof (serid) -1] = '\0'; 612 613 (void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr); 614 615 return (1); 616 } 617 618 619 /* 620 * returns the pci device number for <node> if found, else returns PCIDEV_NIL 621 */ 622 static minor_t 623 pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph) 624 { 625 int rv; 626 int *regp; 627 628 rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG, 629 ®p); 630 631 if (rv < 1) { 632 dprint(("pci_cfg_pcidev: property %s not found " 633 "for %s%d\n", DI_PROP_REG, DRVINST(node))); 634 return (PCIDEV_NIL); 635 } 636 637 return (REG_PCIDEV(regp)); 638 } 639 640 641 /* 642 * returns non-zero when it can successfully return an attachment point 643 * through <ap_path> whose length is less than <ap_pathsz>; returns the full 644 * path of the AP through <pathret> which may be larger than <ap_pathsz>. 645 * Callers need to free <pathret>. If it cannot return the full path through 646 * <pathret> it will be set to NULL 647 * 648 * The ap path reflects a subset of the device path from an onboard host slot 649 * up to <node>. We traverse up the device tree starting from <node>, naming 650 * each component using pci_cfg_ap_node(). If we detect that a certain 651 * segment is contained within an expansion chassis, then we skip any bus 652 * nodes in between our current node and the topmost node of the chassis, 653 * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name 654 * of the expansion chassis as given by pci_cfg_iob_name() 655 * 656 * This scheme is always used for <pathret>. If however, the size of 657 * <pathret> is greater than <ap_pathsz> then only the default name as given 658 * by pci_cfg_ap_node() for <node> will be used 659 */ 660 static int 661 pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 662 char *ap_path, int ap_pathsz, char **pathret) 663 { 664 #ifdef DEBUG 665 char *fnm = "pci_cfg_ap_path"; 666 #endif 667 #define seplen (sizeof (AP_PATH_SEP) - 1) 668 #define iob_pre_len (sizeof (IOB_PRE) - 1) 669 #define ap_path_iob_sep_len (sizeof (AP_PATH_IOB_SEP) - 1) 670 671 char *bufptr; 672 char buf[MAXPATHLEN]; 673 char pathbuf[MAXPATHLEN]; 674 int bufsz; 675 char *pathptr; 676 char *pathend = NULL; 677 int len; 678 int rv = 0; 679 int chasflag = 0; 680 di_node_t curnode = node; 681 di_node_t chasnode = DI_NODE_NIL; 682 minor_t pci_dev; 683 684 buf[0] = '\0'; 685 pathbuf[0] = '\0'; 686 pathptr = &pathbuf[sizeof (pathbuf) - 1]; 687 *pathptr = '\0'; 688 689 /* 690 * as we traverse up the device tree, we prepend components of our 691 * path inside pathbuf, using pathptr and decrementing 692 */ 693 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 694 do { 695 bufptr = buf; 696 bufsz = sizeof (buf); 697 698 chasnode = pci_cfg_chassis_node(curnode, ph); 699 if (chasnode != DI_NODE_NIL) { 700 rv = pci_cfg_iob_name(minor, chasnode, ph, 701 bufptr, bufsz); 702 if (rv == 0) { 703 dprint(("%s: cannot create iob name " 704 "for %s%d\n", fnm, DRVINST(node))); 705 *pathptr = '\0'; 706 goto OUT; 707 } 708 709 (void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz); 710 len = strlen(bufptr); 711 bufptr += len; 712 bufsz -= len - 1; 713 714 /* set chasflag when the leaf node is within an iob */ 715 if ((curnode == node) != NULL) 716 chasflag = 1; 717 } 718 rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0); 719 if (rv == 0) { 720 dprint(("%s: cannot create ap node name " 721 "for %s%d\n", fnm, DRVINST(node))); 722 *pathptr = '\0'; 723 goto OUT; 724 } 725 726 /* 727 * if we can't fit the entire path in our pathbuf, then use 728 * the default short name and nullify pathptr; also, since 729 * we prepend in the buffer, we must avoid adding a null char 730 */ 731 if (curnode != node) { 732 pathptr -= seplen; 733 if (pathptr < pathbuf) { 734 pathptr = pathbuf; 735 *pathptr = '\0'; 736 goto DEF; 737 } 738 (void) memcpy(pathptr, AP_PATH_SEP, seplen); 739 } 740 len = strlen(buf); 741 pathptr -= len; 742 if (pathptr < pathbuf) { 743 pathptr = pathbuf; 744 *pathptr = '\0'; 745 goto DEF; 746 } 747 (void) memcpy(pathptr, buf, len); 748 749 /* remember the leaf component */ 750 if (curnode == node) 751 pathend = pathptr; 752 753 /* 754 * go no further than the hosts' onboard slots 755 */ 756 if (chasnode == DI_NODE_NIL) 757 break; 758 curnode = chasnode; 759 760 /* 761 * the pci device number of the current node is used to 762 * identify which slot of the parent's bus (next iteration) 763 * the current node is on 764 */ 765 pci_dev = pci_cfg_pcidev(curnode, ph); 766 if (pci_dev == PCIDEV_NIL) { 767 dprint(("%s: cannot obtain pci device number " 768 "for %s%d\n", fnm, DRVINST(node))); 769 *pathptr = '\0'; 770 goto OUT; 771 } 772 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 773 774 pathbuf[sizeof (pathbuf) - 1] = '\0'; 775 if (strlen(pathptr) < ap_pathsz) { 776 (void) strlcpy(ap_path, pathptr, ap_pathsz); 777 rv = 1; 778 goto OUT; 779 } 780 781 DEF: 782 /* 783 * when our name won't fit <ap_pathsz> we use the endpoint/leaf 784 * <node>'s name ONLY IF it has a serialid# which will make the apid 785 * globally unique 786 */ 787 if (chasflag && pathend != NULL) { 788 if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP, 789 ap_path_iob_sep_len) != 0) && 790 (strlen(pathend) < ap_pathsz)) { 791 (void) strlcpy(ap_path, pathend, ap_pathsz); 792 rv = 1; 793 goto OUT; 794 } 795 } 796 797 /* 798 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s 799 * default name 800 */ 801 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 802 rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME); 803 if (rv == 0) { 804 dprint(("%s: cannot create default ap node name for %s%d\n", 805 fnm, DRVINST(node))); 806 *pathptr = '\0'; 807 goto OUT; 808 } 809 if (strlen(buf) < ap_pathsz) { 810 (void) strlcpy(ap_path, buf, ap_pathsz); 811 rv = 1; 812 goto OUT; 813 } 814 815 /* 816 * in this case, cfgadm goes through an expensive process to generate 817 * a purely dynamic logical apid: the framework will look through 818 * the device tree for attachment point minor nodes and will invoke 819 * each plugin responsible for that attachment point class, and if 820 * the plugin returns a logical apid that matches the queried apid 821 * or matches the default apid generated by the cfgadm framework for 822 * that driver/class (occurs when plugin returns an empty logical apid) 823 * then that is what it will use 824 * 825 * it is doubly expensive because the cfgadm pci plugin itself will 826 * also search the entire device tree in the absence of a link 827 */ 828 rv = 0; 829 dprint(("%s: cannot create apid for %s%d within length of %d\n", 830 fnm, DRVINST(node), ap_pathsz)); 831 832 OUT: 833 ap_path[ap_pathsz - 1] = '\0'; 834 *pathret = (*pathptr == '\0') ? NULL : strdup(pathptr); 835 return (rv); 836 837 #undef seplen 838 #undef iob_pre_len 839 #undef ap_path_iob_sep_len 840 } 841 842 843 /* 844 * the DI_PROP_AP_NAMES property contains the first integer section of the 845 * ieee1275 "slot-names" property and functions as a bitmask; see comment for 846 * pci_cfg_slotname() 847 * 848 * we use the name of the attachment point minor node if its pci device 849 * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES 850 * 851 * returns non-zero if we return a valid attachment point through <path> 852 */ 853 static int 854 pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 855 char *ap_path, int ap_pathsz) 856 { 857 minor_t pci_dev; 858 int *anp; 859 860 if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES, 861 &anp) < 1) 862 return (0); 863 864 pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 865 if ((*anp & (1 << pci_dev)) == 0) 866 return (0); 867 868 (void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz); 869 return (1); 870 } 871 872 873 /* 874 * determine if <node> qualifies for a path style apid 875 */ 876 static int 877 pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph) 878 { 879 char *devtype; 880 di_node_t curnode = node; 881 882 do { 883 if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode, 884 DI_PROP_DEV_TYPE, &devtype) > 0) 885 if (strcmp(devtype, PROPVAL_PCIEX) == 0) 886 return (1); 887 } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 888 889 return (0); 890 } 891 892 893 /* 894 * takes a full path as returned by <pathret> from pci_cfg_ap_path() and 895 * returns an allocated string intendend to be stored in a devlink info (dli) 896 * file 897 * 898 * data format: "Location: <transformed path>" 899 * where <transformed path> is <path> with occurrances of AP_PATH_SEP 900 * replaced by "/" 901 */ 902 static char * 903 pci_cfg_info_data(char *path) 904 { 905 #define head "Location: " 906 #define headlen (sizeof (head) - 1) 907 #define seplen (sizeof (AP_PATH_SEP) - 1) 908 909 char *sep, *prev, *np; 910 char *newpath; 911 int pathlen = strlen(path); 912 int len; 913 914 newpath = malloc(sizeof (char) * (headlen + pathlen + 1)); 915 np = newpath; 916 (void) strcpy(np, head); 917 np += headlen; 918 919 prev = path; 920 while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) { 921 len = sep - prev; 922 (void) memcpy(np, prev, len); 923 np += len; 924 *np++ = '/'; 925 prev = sep + seplen; 926 } 927 (void) strcpy(np, prev); 928 return (newpath); 929 930 #undef head 931 #undef headlen 932 #undef seplen 933 } 934 935 936 static void 937 pci_cfg_rm_link(char *file) 938 { 939 char *dlipath; 940 941 dlipath = di_dli_name(file); 942 (void) unlink(dlipath); 943 944 devfsadm_rm_all(file); 945 free(dlipath); 946 } 947 948 /* 949 * removes all registered devlinks to physical path <physpath> except for 950 * the devlink <valid> if not NULL; 951 * <physpath> must include the minor node 952 */ 953 static void 954 pci_cfg_rm_invalid_links(char *physpath, char *valid) 955 { 956 char **dnp; 957 char *cp, *vcp; 958 int i, dnlen; 959 960 dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen); 961 if (dnp == NULL) 962 return; 963 964 if (valid != NULL) { 965 if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0) 966 vcp = valid + DEV_LEN + 1; 967 else 968 vcp = valid; 969 } 970 971 for (i = 0; i < dnlen; i++) { 972 if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0) 973 cp = dnp[i] + DEV_LEN + 1; 974 else 975 cp = dnp[i]; 976 977 if (valid != NULL) { 978 if (strcmp(vcp, cp) == 0) 979 continue; 980 } 981 pci_cfg_rm_link(cp); 982 } 983 devfsadm_free_dev_names(dnp, dnlen); 984 } 985 986 987 /* 988 * takes a complete devinfo snapshot and returns the root node; 989 * callers must do a di_fini() on the returned node; 990 * if the snapshot failed, DI_NODE_NIL is returned instead 991 * 992 * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node 993 * in the new snapshot and return it through <ret_node> if it is found, 994 * else DI_NODE_NIL is returned instead 995 * 996 * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return 997 * the matching minor in the new snapshot through <ret_minor> if it is found, 998 * else DI_MINOR_NIL is returned instead 999 */ 1000 static di_node_t 1001 pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor, 1002 di_node_t *ret_node, di_minor_t *ret_minor) 1003 { 1004 di_node_t root_node; 1005 di_node_t node; 1006 di_minor_t minor; 1007 int pci_inst; 1008 dev_t pci_devt; 1009 1010 *ret_node = DI_NODE_NIL; 1011 *ret_minor = DI_MINOR_NIL; 1012 1013 root_node = di_init("/", DINFOCPYALL); 1014 if (root_node == DI_NODE_NIL) 1015 return (DI_NODE_NIL); 1016 1017 /* 1018 * narrow down search by driver, then instance, then minor 1019 */ 1020 if (pci_node == DI_NODE_NIL) 1021 return (root_node); 1022 1023 pci_inst = di_instance(pci_node); 1024 node = di_drv_first_node(di_driver_name(pci_node), root_node); 1025 do { 1026 if (pci_inst == di_instance(node)) { 1027 *ret_node = node; 1028 break; 1029 } 1030 } while ((node = di_drv_next_node(node)) != DI_NODE_NIL); 1031 1032 if (node == DI_NODE_NIL) 1033 return (root_node); 1034 1035 /* 1036 * found node, now search minors 1037 */ 1038 if (pci_minor == DI_MINOR_NIL) 1039 return (root_node); 1040 1041 pci_devt = di_minor_devt(pci_minor); 1042 minor = DI_MINOR_NIL; 1043 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 1044 if (pci_devt == di_minor_devt(minor)) { 1045 *ret_minor = minor; 1046 break; 1047 } 1048 } 1049 return (root_node); 1050 } 1051 1052 1053 static int 1054 pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node) 1055 { 1056 #ifdef DEBUG 1057 char *fnm = "pci_cfg_creat_cb"; 1058 #endif 1059 #define ap_pathsz (sizeof (ap_path)) 1060 1061 char ap_path[CFGA_LOG_EXT_LEN]; 1062 char linkbuf[MAXPATHLEN]; 1063 char *fullpath = NULL; 1064 char *pathinfo = NULL; 1065 char *devpath = NULL; 1066 int rv, fd = -1; 1067 size_t sz; 1068 di_prom_handle_t ph; 1069 di_node_t node; 1070 di_node_t root_node = DI_NODE_NIL; 1071 di_minor_t minor; 1072 1073 ph = di_prom_init(); 1074 if (ph == DI_PROM_HANDLE_NIL) { 1075 dprint(("%s: di_prom_init() failed for %s%d\n", 1076 fnm, DRVINST(pci_node))); 1077 goto OUT; 1078 } 1079 1080 /* 1081 * Since incoming nodes from hotplug events are from snapshots that 1082 * do NOT contain parent/ancestor data, we must retake our own 1083 * snapshot and search for the target node 1084 */ 1085 root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor); 1086 if (root_node == DI_NODE_NIL || node == DI_NODE_NIL || 1087 minor == DI_MINOR_NIL) { 1088 dprint(("%s: devinfo snapshot or search failed for %s%d\n", 1089 fnm, DRVINST(pci_node))); 1090 goto OUT; 1091 } 1092 1093 if (pci_cfg_is_ap_path(node, ph)) { 1094 rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz, 1095 &fullpath); 1096 if (rv == 0) 1097 goto OUT; 1098 1099 (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s", 1100 CFG_DIRNAME, ap_path); 1101 1102 /* 1103 * We must remove existing links because we may have invalid 1104 * apids that are valid links. Since these are not dangling, 1105 * devfsadm will not invoke the remove callback on them. 1106 * 1107 * What are "invalid apids with valid links"? Consider swapping 1108 * an attachment point bus with another while the system is 1109 * down, on the same device path bound to the same drivers 1110 * but with the new AP bus having different properties 1111 * (e.g. serialid#). If the previous apid is not removed, 1112 * there will now be two different links pointing to the same 1113 * attachment point, but only one reflects the correct 1114 * logical apid 1115 */ 1116 devpath = pci_cfg_devpath(node, minor); 1117 if (devpath == NULL) 1118 goto OUT; 1119 pci_cfg_rm_invalid_links(devpath, linkbuf); 1120 free(devpath); 1121 1122 (void) devfsadm_mklink(linkbuf, node, minor, 0); 1123 1124 /* 1125 * we store the full logical path of the attachment point for 1126 * cfgadm to display in its info field which is useful when 1127 * the full logical path exceeds the size limit for logical 1128 * apids (CFGA_LOG_EXT_LEN) 1129 * 1130 * for the cfgadm pci plugin to do the same would be expensive 1131 * (i.e. devinfo snapshot + top down exhaustive minor search + 1132 * equivalent of pci_cfg_ap_path() on every invocation) 1133 * 1134 * note that if we do not create a link (pci_cfg_ap_path() is 1135 * not successful), that is what cfgadm will do anyways to 1136 * create a purely dynamic apid 1137 */ 1138 pathinfo = pci_cfg_info_data(fullpath); 1139 fd = di_dli_openw(linkbuf); 1140 if (fd < 0) 1141 goto OUT; 1142 1143 sz = strlen(pathinfo) + 1; 1144 rv = write(fd, pathinfo, sz); 1145 if (rv < sz) { 1146 dprint(("%s: could not write full pathinfo to dli " 1147 "file for %s%d\n", fnm, DRVINST(node))); 1148 goto OUT; 1149 } 1150 di_dli_close(fd); 1151 } else { 1152 rv = pci_cfg_ap_legacy(minor, node, ph, ap_path, 1153 ap_pathsz); 1154 if (rv == 0) 1155 goto OUT; 1156 1157 (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s", 1158 CFG_DIRNAME, ap_path); 1159 (void) devfsadm_mklink(linkbuf, node, minor, 0); 1160 } 1161 1162 OUT: 1163 if (fd >= 0) 1164 di_dli_close(fd); 1165 if (fullpath != NULL) 1166 free(fullpath); 1167 if (pathinfo != NULL) 1168 free(pathinfo); 1169 if (ph != DI_PROM_HANDLE_NIL) 1170 di_prom_fini(ph); 1171 if (root_node != DI_NODE_NIL) 1172 di_fini(root_node); 1173 return (DEVFSADM_CONTINUE); 1174 1175 #undef ap_pathsz 1176 } 1177 1178 1179 static void 1180 pci_cfg_rm_all(char *file) 1181 { 1182 pci_cfg_rm_link(file); 1183 } 1184 1185 1186 /* 1187 * ib_cfg_creat_cb() creates two types of links 1188 * One for the fabric as /dev/cfg/ib 1189 * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID> 1190 */ 1191 static int 1192 ib_cfg_creat_cb(di_minor_t minor, di_node_t node) 1193 { 1194 char *cp; 1195 char path[PATH_MAX + 1]; 1196 1197 if ((cp = di_devfs_path(node)) == NULL) { 1198 return (DEVFSADM_CONTINUE); 1199 } 1200 1201 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 1202 di_devfs_path_free(cp); 1203 1204 /* create fabric or hca:GUID and the symlink */ 1205 if (strstr(path, "ib:fabric") != NULL) { 1206 (void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME); 1207 } else { 1208 (void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME, 1209 di_minor_name(minor)); 1210 } 1211 1212 (void) devfsadm_mklink(path, node, minor, 0); 1213 return (DEVFSADM_CONTINUE); 1214 } 1215 1216 /* 1217 * This function verifies if the serial id is printable. 1218 */ 1219 1220 static int 1221 serid_printable(uint64_t *seridp) 1222 { 1223 1224 char *ptr; 1225 int i = 0; 1226 1227 for (ptr = (char *)seridp+3; i < 5; ptr++, i++) 1228 if (*ptr < 0x21 || *ptr >= 0x7f) 1229 return (0); 1230 1231 return (1); 1232 1233 } 1234