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