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