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