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