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