17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 566f9d5cbSmlf * Common Development and Distribution License (the "License"). 666f9d5cbSmlf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2166f9d5cbSmlf 227c478bd9Sstevel@tonic-gate /* 23*ff0e937bSRaymond Chen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <devfsadm.h> 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <strings.h> 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 313c4226f9Spjha #include <stdarg.h> 327c478bd9Sstevel@tonic-gate #include <limits.h> 333c4226f9Spjha #include <unistd.h> 343c4226f9Spjha #include <config_admin.h> 353c4226f9Spjha #include <cfg_link.h> 363c4226f9Spjha #include <sys/types.h> 373c4226f9Spjha #include <sys/mkdev.h> 383c4226f9Spjha #include <sys/hotplug/pci/pcihp.h> 397c478bd9Sstevel@tonic-gate 403c4226f9Spjha #ifdef DEBUG 413c4226f9Spjha #define dprint(args) devfsadm_errprint args 423c4226f9Spjha /* 433c4226f9Spjha * for use in print routine arg list as a shorthand way to locate node via 443c4226f9Spjha * "prtconf -D" to avoid messy and cluttered debugging code 453c4226f9Spjha * don't forget the corresponding "%s%d" format 463c4226f9Spjha */ 473c4226f9Spjha #define DRVINST(node) di_driver_name(node), di_instance(node) 483c4226f9Spjha #else 493c4226f9Spjha #define dprint(args) 503c4226f9Spjha #endif 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static int scsi_cfg_creat_cb(di_minor_t minor, di_node_t node); 547c478bd9Sstevel@tonic-gate static int sbd_cfg_creat_cb(di_minor_t minor, di_node_t node); 557c478bd9Sstevel@tonic-gate static int usb_cfg_creat_cb(di_minor_t minor, di_node_t node); 567c478bd9Sstevel@tonic-gate static char *get_roothub(const char *path, void *cb_arg); 577c478bd9Sstevel@tonic-gate static int pci_cfg_creat_cb(di_minor_t minor, di_node_t node); 587c478bd9Sstevel@tonic-gate static int ib_cfg_creat_cb(di_minor_t minor, di_node_t node); 5966f9d5cbSmlf static int sata_cfg_creat_cb(di_minor_t minor, di_node_t node); 604bb7efa7SGarrett D'Amore static int sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node); 617c478bd9Sstevel@tonic-gate 623c4226f9Spjha static di_node_t pci_cfg_chassis_node(di_node_t, di_prom_handle_t); 633c4226f9Spjha static char *pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t); 643c4226f9Spjha static int pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t, 653c4226f9Spjha char *, int, int); 663c4226f9Spjha static int pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t, 673c4226f9Spjha char *, int); 683c4226f9Spjha static minor_t pci_cfg_pcidev(di_node_t, di_prom_handle_t); 693c4226f9Spjha static int pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t, 703c4226f9Spjha char *, int, char **); 713c4226f9Spjha static char *pci_cfg_info_data(char *); 723c4226f9Spjha static int pci_cfg_is_ap_path(di_node_t, di_prom_handle_t); 733c4226f9Spjha static int pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t, 743c4226f9Spjha char *, int); 753c4226f9Spjha static void pci_cfg_rm_invalid_links(char *, char *); 763c4226f9Spjha static void pci_cfg_rm_link(char *); 773c4226f9Spjha static void pci_cfg_rm_all(char *); 783c4226f9Spjha static char *pci_cfg_devpath(di_node_t, di_minor_t); 793c4226f9Spjha static di_node_t pci_cfg_snapshot(di_node_t, di_minor_t, 803c4226f9Spjha di_node_t *, di_minor_t *); 813c4226f9Spjha 823c4226f9Spjha /* flag definitions for di_propall_*(); value "0" is always the default flag */ 833c4226f9Spjha #define DIPROP_PRI_NODE 0x0 843c4226f9Spjha #define DIPROP_PRI_PROM 0x1 853c4226f9Spjha static int di_propall_lookup_ints(di_prom_handle_t, int, 863c4226f9Spjha dev_t, di_node_t, const char *, int **); 873c4226f9Spjha static int di_propall_lookup_strings(di_prom_handle_t, int, 883c4226f9Spjha dev_t, di_node_t, const char *, char **); 89226236b5Spjha static int serid_printable(uint64_t *seridp); 903ebafc43Sjveta static int di_propall_lookup_slot_names(di_prom_handle_t, int, 913ebafc43Sjveta dev_t, di_node_t, di_slot_name_t **); 923c4226f9Spjha 933c4226f9Spjha 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * NOTE: The CREATE_DEFER flag is private to this module. 967c478bd9Sstevel@tonic-gate * NOT to be used by other modules 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate static devfsadm_create_t cfg_create_cbt[] = { 993c4226f9Spjha { "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL, 1007c478bd9Sstevel@tonic-gate TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 1017c478bd9Sstevel@tonic-gate }, 1023c4226f9Spjha { "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL, 1037c478bd9Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb 1047c478bd9Sstevel@tonic-gate }, 1053c4226f9Spjha { "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL, 1067c478bd9Sstevel@tonic-gate TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 1077c478bd9Sstevel@tonic-gate }, 1083c4226f9Spjha { "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL, 1097c478bd9Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb 1107c478bd9Sstevel@tonic-gate }, 1113c4226f9Spjha { "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL, 1127c478bd9Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb 1137c478bd9Sstevel@tonic-gate }, 1143c4226f9Spjha { "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL, 1157c478bd9Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb 11666f9d5cbSmlf }, 1173c4226f9Spjha { "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL, 11866f9d5cbSmlf TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb 1194bb7efa7SGarrett D'Amore }, 1204bb7efa7SGarrett D'Amore { "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL, 1214bb7efa7SGarrett D'Amore TYPE_EXACT, ILEVEL_0, sdcard_cfg_creat_cb 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate }; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(cfg_create_cbt); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate static devfsadm_remove_t cfg_remove_cbt[] = { 1287c478bd9Sstevel@tonic-gate { "attachment-point", SCSI_CFG_LINK_RE, RM_POST, 1297c478bd9Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 1307c478bd9Sstevel@tonic-gate }, 1317c478bd9Sstevel@tonic-gate { "attachment-point", SBD_CFG_LINK_RE, RM_POST, 1327c478bd9Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 1337c478bd9Sstevel@tonic-gate }, 1347c478bd9Sstevel@tonic-gate { "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST, 1357c478bd9Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 1367c478bd9Sstevel@tonic-gate }, 1377c478bd9Sstevel@tonic-gate { "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 1387c478bd9Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 1397c478bd9Sstevel@tonic-gate }, 1407c478bd9Sstevel@tonic-gate { "attachment-point", PCI_CFG_LINK_RE, RM_POST, 1417c478bd9Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 1427c478bd9Sstevel@tonic-gate }, 1433c4226f9Spjha { "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT, 1443c4226f9Spjha ILEVEL_0, pci_cfg_rm_all 1453c4226f9Spjha }, 1467c478bd9Sstevel@tonic-gate { "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 1477c478bd9Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 14866f9d5cbSmlf }, 14966f9d5cbSmlf { "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 15066f9d5cbSmlf ILEVEL_0, devfsadm_rm_all 1514bb7efa7SGarrett D'Amore }, 1524bb7efa7SGarrett D'Amore { "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 1534bb7efa7SGarrett D'Amore ILEVEL_0, devfsadm_rm_all 1544bb7efa7SGarrett D'Amore }, 1557c478bd9Sstevel@tonic-gate }; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static int 1607c478bd9Sstevel@tonic-gate scsi_cfg_creat_cb(di_minor_t minor, di_node_t node) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate char path[PATH_MAX + 1]; 1637c478bd9Sstevel@tonic-gate char *c_num = NULL, *devfs_path, *mn; 1647c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[3] = { 1657c478bd9Sstevel@tonic-gate {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 1667c478bd9Sstevel@tonic-gate {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 1677c478bd9Sstevel@tonic-gate {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 1687c478bd9Sstevel@tonic-gate }; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate mn = di_minor_name(minor); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate if ((devfs_path = di_devfs_path(node)) == NULL) { 1737c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate (void) strcpy(path, devfs_path); 1767c478bd9Sstevel@tonic-gate (void) strcat(path, ":"); 1777c478bd9Sstevel@tonic-gate (void) strcat(path, mn); 1787c478bd9Sstevel@tonic-gate di_devfs_path_free(devfs_path); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3) 1817c478bd9Sstevel@tonic-gate == DEVFSADM_FAILURE) { 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * Unlike the disks module we don't retry on failure. 1847c478bd9Sstevel@tonic-gate * If we have multiple "c" numbers for a single physical 1857c478bd9Sstevel@tonic-gate * controller due to bug 4045879, we will not assign a 1867c478bd9Sstevel@tonic-gate * c-number/symlink for the controller. 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate (void) strcpy(path, CFG_DIRNAME); 1927c478bd9Sstevel@tonic-gate (void) strcat(path, "/c"); 1937c478bd9Sstevel@tonic-gate (void) strcat(path, c_num); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate free(c_num); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate (void) devfsadm_mklink(path, node, minor, 0); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate static int 2037c478bd9Sstevel@tonic-gate sbd_cfg_creat_cb(di_minor_t minor, di_node_t node) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate char path[PATH_MAX + 1]; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate (void) strcpy(path, CFG_DIRNAME); 2087c478bd9Sstevel@tonic-gate (void) strcat(path, "/"); 2097c478bd9Sstevel@tonic-gate (void) strcat(path, di_minor_name(minor)); 2107c478bd9Sstevel@tonic-gate (void) devfsadm_mklink(path, node, minor, 0); 2117c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate static int 2167c478bd9Sstevel@tonic-gate usb_cfg_creat_cb(di_minor_t minor, di_node_t node) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate char *cp, path[PATH_MAX + 1]; 2197c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[1] = 2207c478bd9Sstevel@tonic-gate {"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub}; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if ((cp = di_devfs_path(node)) == NULL) { 2237c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 2277c478bd9Sstevel@tonic-gate di_devfs_path_free(cp); 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) { 2307c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* create usbN and the symlink */ 2347c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp, 2357c478bd9Sstevel@tonic-gate di_minor_name(minor)); 2367c478bd9Sstevel@tonic-gate free(cp); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate (void) devfsadm_mklink(path, node, minor, 0); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate 24466f9d5cbSmlf static int 24566f9d5cbSmlf sata_cfg_creat_cb(di_minor_t minor, di_node_t node) 24666f9d5cbSmlf { 24766f9d5cbSmlf char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath; 24866f9d5cbSmlf char *minor_nm; 24966f9d5cbSmlf devfsadm_enumerate_t rules[1] = 25066f9d5cbSmlf {"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR}; 25166f9d5cbSmlf 25266f9d5cbSmlf minor_nm = di_minor_name(minor); 25366f9d5cbSmlf if (minor_nm == NULL) 25466f9d5cbSmlf return (DEVFSADM_CONTINUE); 25566f9d5cbSmlf 25666f9d5cbSmlf devfspath = di_devfs_path(node); 25766f9d5cbSmlf if (devfspath == NULL) 25866f9d5cbSmlf return (DEVFSADM_CONTINUE); 25966f9d5cbSmlf 26066f9d5cbSmlf (void) strlcpy(path, devfspath, sizeof (path)); 26166f9d5cbSmlf (void) strlcat(path, ":", sizeof (path)); 26266f9d5cbSmlf (void) strlcat(path, minor_nm, sizeof (path)); 26366f9d5cbSmlf di_devfs_path_free(devfspath); 26466f9d5cbSmlf 26566f9d5cbSmlf /* build the physical path from the components */ 26666f9d5cbSmlf if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) == 26766f9d5cbSmlf DEVFSADM_FAILURE) { 26866f9d5cbSmlf return (DEVFSADM_CONTINUE); 26966f9d5cbSmlf } 27066f9d5cbSmlf 27166f9d5cbSmlf (void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME, 27266f9d5cbSmlf buf, minor_nm); 27366f9d5cbSmlf free(buf); 27466f9d5cbSmlf 27566f9d5cbSmlf (void) devfsadm_mklink(l_path, node, minor, 0); 27666f9d5cbSmlf 27766f9d5cbSmlf return (DEVFSADM_CONTINUE); 27866f9d5cbSmlf } 27966f9d5cbSmlf 2804bb7efa7SGarrett D'Amore static int 2814bb7efa7SGarrett D'Amore sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node) 2824bb7efa7SGarrett D'Amore { 2834bb7efa7SGarrett D'Amore char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath; 2844bb7efa7SGarrett D'Amore char *minor_nm; 2854bb7efa7SGarrett D'Amore devfsadm_enumerate_t rules[1] = 2864bb7efa7SGarrett D'Amore {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR}; 2874bb7efa7SGarrett D'Amore 2884bb7efa7SGarrett D'Amore minor_nm = di_minor_name(minor); 2894bb7efa7SGarrett D'Amore if (minor_nm == NULL) 2904bb7efa7SGarrett D'Amore return (DEVFSADM_CONTINUE); 2914bb7efa7SGarrett D'Amore 2924bb7efa7SGarrett D'Amore devfspath = di_devfs_path(node); 2934bb7efa7SGarrett D'Amore if (devfspath == NULL) 2944bb7efa7SGarrett D'Amore return (DEVFSADM_CONTINUE); 2954bb7efa7SGarrett D'Amore 2964bb7efa7SGarrett D'Amore (void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm); 2974bb7efa7SGarrett D'Amore di_devfs_path_free(devfspath); 2984bb7efa7SGarrett D'Amore 2994bb7efa7SGarrett D'Amore /* build the physical path from the components */ 3004bb7efa7SGarrett D'Amore if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) == 3014bb7efa7SGarrett D'Amore DEVFSADM_FAILURE) { 3024bb7efa7SGarrett D'Amore return (DEVFSADM_CONTINUE); 3034bb7efa7SGarrett D'Amore } 3044bb7efa7SGarrett D'Amore 3054bb7efa7SGarrett D'Amore (void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s", 3064bb7efa7SGarrett D'Amore CFG_DIRNAME, buf, minor_nm); 3074bb7efa7SGarrett D'Amore free(buf); 3084bb7efa7SGarrett D'Amore 3094bb7efa7SGarrett D'Amore (void) devfsadm_mklink(l_path, node, minor, 0); 3104bb7efa7SGarrett D'Amore 3114bb7efa7SGarrett D'Amore return (DEVFSADM_CONTINUE); 3124bb7efa7SGarrett D'Amore } 31366f9d5cbSmlf 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * get_roothub: 3167c478bd9Sstevel@tonic-gate * figure out the root hub path to calculate /dev/cfg/usbN 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3197c478bd9Sstevel@tonic-gate static char * 3207c478bd9Sstevel@tonic-gate get_roothub(const char *path, void *cb_arg) 3217c478bd9Sstevel@tonic-gate { 3227c478bd9Sstevel@tonic-gate int i, count = 0; 3237c478bd9Sstevel@tonic-gate char *physpath, *cp; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* make a copy */ 3267c478bd9Sstevel@tonic-gate if ((physpath = strdup(path)) == NULL) { 3277c478bd9Sstevel@tonic-gate return (NULL); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * physpath must always have a minor name component 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate if ((cp = strrchr(physpath, ':')) == NULL) { 3347c478bd9Sstevel@tonic-gate free(physpath); 3357c478bd9Sstevel@tonic-gate return (NULL); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate *cp++ = '\0'; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * No '.' in the minor name indicates a roothub port. 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate if (strchr(cp, '.') == NULL) { 3437c478bd9Sstevel@tonic-gate /* roothub device */ 3447c478bd9Sstevel@tonic-gate return (physpath); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate while (*cp) { 3487c478bd9Sstevel@tonic-gate if (*cp == '.') 3497c478bd9Sstevel@tonic-gate count++; 3507c478bd9Sstevel@tonic-gate cp++; 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* Remove as many trailing path components as there are '.'s */ 3547c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 3557c478bd9Sstevel@tonic-gate if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) { 3567c478bd9Sstevel@tonic-gate free(physpath); 3577c478bd9Sstevel@tonic-gate return (NULL); 3587c478bd9Sstevel@tonic-gate } 359*ff0e937bSRaymond Chen /* 360*ff0e937bSRaymond Chen * Check if there is any usb_mid node in the middle 361*ff0e937bSRaymond Chen * and remove the node as if there is an extra '.' 362*ff0e937bSRaymond Chen */ 363*ff0e937bSRaymond Chen if (strstr(cp, "miscellaneous") != NULL) { 364*ff0e937bSRaymond Chen count++; 365*ff0e937bSRaymond Chen } 3667c478bd9Sstevel@tonic-gate *cp = '\0'; 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 369*ff0e937bSRaymond Chen /* Remove the usb_mid node immediately before the trailing path */ 370*ff0e937bSRaymond Chen if ((cp = strrchr(physpath, '/')) != NULL && (cp != physpath)) { 371*ff0e937bSRaymond Chen if (strstr(cp, "miscellaneous") != NULL) { 372*ff0e937bSRaymond Chen *cp = '\0'; 373*ff0e937bSRaymond Chen } 374*ff0e937bSRaymond Chen } 375*ff0e937bSRaymond Chen 3767c478bd9Sstevel@tonic-gate return (physpath); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* 3813c4226f9Spjha * returns an allocted string containing the device path for <node> and 3823c4226f9Spjha * <minor> 3833c4226f9Spjha */ 3843c4226f9Spjha static char * 3853c4226f9Spjha pci_cfg_devpath(di_node_t node, di_minor_t minor) 3863c4226f9Spjha { 3873c4226f9Spjha char *path; 3883c4226f9Spjha char *bufp; 3893c4226f9Spjha char *minor_nm; 3903c4226f9Spjha int buflen; 3913c4226f9Spjha 3923c4226f9Spjha path = di_devfs_path(node); 3933c4226f9Spjha minor_nm = di_minor_name(minor); 394ad86e48dSpjha buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1; 3953c4226f9Spjha 3963c4226f9Spjha bufp = malloc(sizeof (char) * buflen); 397ad86e48dSpjha if (bufp != NULL) 3983c4226f9Spjha (void) snprintf(bufp, buflen, "%s:%s", path, minor_nm); 3993c4226f9Spjha 4003c4226f9Spjha di_devfs_path_free(path); 4013c4226f9Spjha return (bufp); 4023c4226f9Spjha } 4033c4226f9Spjha 4043c4226f9Spjha 4053c4226f9Spjha static int 4063c4226f9Spjha di_propall_lookup_ints(di_prom_handle_t ph, int flags, 4073c4226f9Spjha dev_t dev, di_node_t node, const char *prop_name, int **prop_data) 4083c4226f9Spjha { 4093c4226f9Spjha int rv; 4103c4226f9Spjha 4113c4226f9Spjha if (flags & DIPROP_PRI_PROM) { 4123c4226f9Spjha rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data); 4133c4226f9Spjha if (rv < 0) 4143c4226f9Spjha rv = di_prop_lookup_ints(dev, node, prop_name, 4153c4226f9Spjha prop_data); 4163c4226f9Spjha } else { 4173c4226f9Spjha rv = di_prop_lookup_ints(dev, node, prop_name, prop_data); 4183c4226f9Spjha if (rv < 0) 4193c4226f9Spjha rv = di_prom_prop_lookup_ints(ph, node, prop_name, 4203c4226f9Spjha prop_data); 4213c4226f9Spjha } 4223c4226f9Spjha return (rv); 4233c4226f9Spjha } 4243c4226f9Spjha 4253c4226f9Spjha 4263c4226f9Spjha static int 4273c4226f9Spjha di_propall_lookup_strings(di_prom_handle_t ph, int flags, 4283c4226f9Spjha dev_t dev, di_node_t node, const char *prop_name, char **prop_data) 4293c4226f9Spjha { 4303c4226f9Spjha int rv; 4313c4226f9Spjha 4323c4226f9Spjha if (flags & DIPROP_PRI_PROM) { 4333c4226f9Spjha rv = di_prom_prop_lookup_strings(ph, node, prop_name, 4343c4226f9Spjha prop_data); 4353c4226f9Spjha if (rv < 0) 4363c4226f9Spjha rv = di_prop_lookup_strings(dev, node, prop_name, 4373c4226f9Spjha prop_data); 4383c4226f9Spjha } else { 4393c4226f9Spjha rv = di_prop_lookup_strings(dev, node, prop_name, prop_data); 4403c4226f9Spjha if (rv < 0) 4413c4226f9Spjha rv = di_prom_prop_lookup_strings(ph, node, prop_name, 4423c4226f9Spjha prop_data); 4433c4226f9Spjha } 4443c4226f9Spjha return (rv); 4453c4226f9Spjha } 4463c4226f9Spjha 4473c4226f9Spjha 4483c4226f9Spjha static di_node_t 4493c4226f9Spjha pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph) 4503c4226f9Spjha { 4513c4226f9Spjha di_node_t curnode = node; 4523c4226f9Spjha int *firstchas; 4533c4226f9Spjha 4543c4226f9Spjha do { 4553c4226f9Spjha if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode, 4563ebafc43Sjveta DI_PROP_FIRST_CHAS, &firstchas) >= 0) 4573c4226f9Spjha return (curnode); 4583c4226f9Spjha } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 4593c4226f9Spjha 4603c4226f9Spjha return (DI_NODE_NIL); 4613c4226f9Spjha } 4623c4226f9Spjha 4633c4226f9Spjha 4643ebafc43Sjveta static int 4653ebafc43Sjveta di_propall_lookup_slot_names(di_prom_handle_t ph, int flags, 4663ebafc43Sjveta dev_t dev, di_node_t node, di_slot_name_t **prop_data) 4673ebafc43Sjveta { 4683ebafc43Sjveta int rv; 4693ebafc43Sjveta 4703ebafc43Sjveta if (flags & DIPROP_PRI_PROM) { 4713ebafc43Sjveta rv = di_prom_prop_lookup_slot_names(ph, node, prop_data); 4723ebafc43Sjveta if (rv < 0) 4733ebafc43Sjveta rv = di_prop_lookup_slot_names(dev, node, prop_data); 4743ebafc43Sjveta } else { 4753ebafc43Sjveta rv = di_prop_lookup_slot_names(dev, node, prop_data); 4763ebafc43Sjveta if (rv < 0) 4773ebafc43Sjveta rv = di_prom_prop_lookup_slot_names(ph, node, 4783ebafc43Sjveta prop_data); 4793ebafc43Sjveta } 4803ebafc43Sjveta return (rv); 4813ebafc43Sjveta } 4823ebafc43Sjveta 4833c4226f9Spjha /* 4843ebafc43Sjveta * returns an allocated string containing the slot name for the slot with 4853ebafc43Sjveta * device number <pci_dev> on bus <node> 4863c4226f9Spjha */ 4873c4226f9Spjha static char * 4883c4226f9Spjha pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev) 4893c4226f9Spjha { 4903c4226f9Spjha #ifdef DEBUG 4913c4226f9Spjha char *fnm = "pci_cfg_slotname"; 4923c4226f9Spjha #endif 4933ebafc43Sjveta int i, count; 4943ebafc43Sjveta char *name = NULL; 4953ebafc43Sjveta di_slot_name_t *slot_names = NULL; 4963c4226f9Spjha 4973ebafc43Sjveta count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node, 4983ebafc43Sjveta &slot_names); 4993ebafc43Sjveta if (count < 0) 5003c4226f9Spjha return (NULL); 5013c4226f9Spjha 5023ebafc43Sjveta for (i = 0; i < count; i++) { 5033ebafc43Sjveta if (slot_names[i].num == (int)pci_dev) { 5043ebafc43Sjveta name = strdup(slot_names[i].name); 5053c4226f9Spjha break; 5063c4226f9Spjha } 5073c4226f9Spjha } 5083ebafc43Sjveta #ifdef DEBUG 5093ebafc43Sjveta if (name == NULL) 5103ebafc43Sjveta dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n", 5113ebafc43Sjveta fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node))); 5123ebafc43Sjveta #endif 5133ebafc43Sjveta if (count > 0) 5143ebafc43Sjveta di_slot_names_free(count, slot_names); 5153ebafc43Sjveta return (name); 5163c4226f9Spjha } 5173c4226f9Spjha 5183c4226f9Spjha 5193c4226f9Spjha /* 5203c4226f9Spjha * returns non-zero if we can return a valid attachment point name for <node>, 5213c4226f9Spjha * for its slot identified by child pci device number <pci_dev>, through <buf> 5223c4226f9Spjha * 5233c4226f9Spjha * prioritized naming scheme: 5243ebafc43Sjveta * 1) <DI_PROP_SLOT_NAMES property> (see pci_cfg_slotname()) 5253ebafc43Sjveta * 2) <device-type><DI_PROP_PHYS_SLOT property> 5263c4226f9Spjha * 3) <drv name><drv inst>.<device-type><pci_dev> 5273c4226f9Spjha * 5283ebafc43Sjveta * where <device-type> is derived from the DI_PROP_DEV_TYPE property: 5293c4226f9Spjha * if its value is "pciex" then <device-type> is "pcie" 5303c4226f9Spjha * else the raw value is used 5313c4226f9Spjha * 5323c4226f9Spjha * if <flags> contains APNODE_DEFNAME, then scheme (3) is used 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate static int 5353c4226f9Spjha pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph, 5363c4226f9Spjha char *buf, int bufsz, int flags) 5377c478bd9Sstevel@tonic-gate { 5383c4226f9Spjha int *nump; 5393c4226f9Spjha int rv; 5403c4226f9Spjha char *str, *devtype; 5413c4226f9Spjha 5423c4226f9Spjha rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node, 5433ebafc43Sjveta DI_PROP_DEV_TYPE, &devtype); 5443c4226f9Spjha if (rv < 1) 5453c4226f9Spjha return (0); 5463c4226f9Spjha 5473c4226f9Spjha if (strcmp(devtype, PROPVAL_PCIEX) == 0) 5483c4226f9Spjha devtype = DEVTYPE_PCIE; 5493c4226f9Spjha 5503c4226f9Spjha if (flags & APNODE_DEFNAME) 5513c4226f9Spjha goto DEF; 5523c4226f9Spjha 5533c4226f9Spjha str = pci_cfg_slotname(node, ph, pci_dev); 5543c4226f9Spjha if (str != NULL) { 5553c4226f9Spjha (void) strlcpy(buf, str, bufsz); 5563ebafc43Sjveta free(str); 5573c4226f9Spjha return (1); 5583c4226f9Spjha } 5593c4226f9Spjha 5603ebafc43Sjveta if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, 5613ebafc43Sjveta DI_PROP_PHYS_SLOT, &nump) > 0) { 5623c4226f9Spjha if (*nump > 0) { 5633c4226f9Spjha (void) snprintf(buf, bufsz, "%s%d", devtype, *nump); 5643c4226f9Spjha return (1); 5653c4226f9Spjha } 5663c4226f9Spjha } 5673c4226f9Spjha DEF: 5683c4226f9Spjha (void) snprintf(buf, bufsz, "%s%d.%s%d", 5693c4226f9Spjha di_driver_name(node), di_instance(node), devtype, pci_dev); 5703c4226f9Spjha 5713c4226f9Spjha return (1); 5723c4226f9Spjha } 5733c4226f9Spjha 5743c4226f9Spjha 5753c4226f9Spjha /* 5763c4226f9Spjha * returns non-zero if we can return a valid expansion chassis name for <node> 5773c4226f9Spjha * through <buf> 5783c4226f9Spjha * 5793c4226f9Spjha * prioritized naming scheme: 5803ebafc43Sjveta * 1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion> 5813ebafc43Sjveta * 2) <IOB_PRE string><full DI_PROP_SERID property in hex> 5823c4226f9Spjha * 3) <IOB_PRE string> 5833c4226f9Spjha * 5843ebafc43Sjveta * DI_PROP_SERID encoding <64-bit int: msb ... lsb>: 585b6b3bf89Spjha * <24 bits: IEEE company id><40 bits: serial number> 5863c4226f9Spjha * 5873c4226f9Spjha * sun encoding of 40 bit serial number: 588226236b5Spjha * first byte = device type indicator 5893c4226f9Spjha * next 4 bytes = 4 ascii characters 590226236b5Spjha * 591226236b5Spjha * In the unlikely event that serial id contains non-printable characters 592226236b5Spjha * the full 64 bit raw hex string will be used for the attachment point. 5933c4226f9Spjha */ 5943c4226f9Spjha /*ARGSUSED*/ 5953c4226f9Spjha static int 5963c4226f9Spjha pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 5973c4226f9Spjha char *buf, int bufsz) 5983c4226f9Spjha { 5993c4226f9Spjha int64_t *seridp; 600b6b3bf89Spjha uint64_t serid; 601226236b5Spjha char *idstr; 6023c4226f9Spjha 6033ebafc43Sjveta if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID, 6043c4226f9Spjha &seridp) < 1) { 6053c4226f9Spjha (void) strlcpy(buf, IOB_PRE, bufsz); 6063c4226f9Spjha return (1); 6073c4226f9Spjha } 608226236b5Spjha 609b6b3bf89Spjha serid = (uint64_t)*seridp; 6103c4226f9Spjha 611226236b5Spjha if ((serid >> 40) != (uint64_t)IEEE_SUN_ID || 612226236b5Spjha !serid_printable(&serid)) { 6133c4226f9Spjha (void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid); 6143c4226f9Spjha return (1); 6153c4226f9Spjha } 6163c4226f9Spjha 617b6b3bf89Spjha /* 618226236b5Spjha * the serial id is constructed from lower 40 bits of the serialid 619226236b5Spjha * property and is represented by 5 ascii characters. The first 620226236b5Spjha * character indicates if the IO Box is PCIe or PCI-X. 621b6b3bf89Spjha */ 622b6b3bf89Spjha 623226236b5Spjha serid <<= 24; 624226236b5Spjha idstr = (char *)&serid; 625226236b5Spjha idstr[sizeof (serid) -1] = '\0'; 626226236b5Spjha 627226236b5Spjha (void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr); 628b6b3bf89Spjha 6293c4226f9Spjha return (1); 6303c4226f9Spjha } 6313c4226f9Spjha 6323c4226f9Spjha 633ad86e48dSpjha /* 634ad86e48dSpjha * returns the pci device number for <node> if found, else returns PCIDEV_NIL 635ad86e48dSpjha */ 6363c4226f9Spjha static minor_t 6373c4226f9Spjha pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph) 6383c4226f9Spjha { 6393c4226f9Spjha int rv; 6403c4226f9Spjha int *regp; 6413c4226f9Spjha 6423ebafc43Sjveta rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG, 6433c4226f9Spjha ®p); 6443c4226f9Spjha 6453c4226f9Spjha if (rv < 1) { 6463c4226f9Spjha dprint(("pci_cfg_pcidev: property %s not found " 6473ebafc43Sjveta "for %s%d\n", DI_PROP_REG, DRVINST(node))); 6484e0386dfSjveta return (PCIDEV_NIL); 6493c4226f9Spjha } 6503c4226f9Spjha 6513c4226f9Spjha return (REG_PCIDEV(regp)); 6523c4226f9Spjha } 6533c4226f9Spjha 6543c4226f9Spjha 6553c4226f9Spjha /* 6563c4226f9Spjha * returns non-zero when it can successfully return an attachment point 6573c4226f9Spjha * through <ap_path> whose length is less than <ap_pathsz>; returns the full 6583c4226f9Spjha * path of the AP through <pathret> which may be larger than <ap_pathsz>. 6593c4226f9Spjha * Callers need to free <pathret>. If it cannot return the full path through 6603c4226f9Spjha * <pathret> it will be set to NULL 6613c4226f9Spjha * 6623c4226f9Spjha * The ap path reflects a subset of the device path from an onboard host slot 6633c4226f9Spjha * up to <node>. We traverse up the device tree starting from <node>, naming 6643c4226f9Spjha * each component using pci_cfg_ap_node(). If we detect that a certain 6653c4226f9Spjha * segment is contained within an expansion chassis, then we skip any bus 6663c4226f9Spjha * nodes in between our current node and the topmost node of the chassis, 6673ebafc43Sjveta * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name 6683c4226f9Spjha * of the expansion chassis as given by pci_cfg_iob_name() 6693c4226f9Spjha * 6703c4226f9Spjha * This scheme is always used for <pathret>. If however, the size of 6713c4226f9Spjha * <pathret> is greater than <ap_pathsz> then only the default name as given 6723c4226f9Spjha * by pci_cfg_ap_node() for <node> will be used 6733c4226f9Spjha */ 6743c4226f9Spjha static int 6753c4226f9Spjha pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 6763c4226f9Spjha char *ap_path, int ap_pathsz, char **pathret) 6773c4226f9Spjha { 6783c4226f9Spjha #ifdef DEBUG 6793c4226f9Spjha char *fnm = "pci_cfg_ap_path"; 6803c4226f9Spjha #endif 6813c4226f9Spjha #define seplen (sizeof (AP_PATH_SEP) - 1) 6823c4226f9Spjha #define iob_pre_len (sizeof (IOB_PRE) - 1) 6833c4226f9Spjha #define ap_path_iob_sep_len (sizeof (AP_PATH_IOB_SEP) - 1) 6843c4226f9Spjha 6853c4226f9Spjha char *bufptr; 6863c4226f9Spjha char buf[MAXPATHLEN]; 6873c4226f9Spjha char pathbuf[MAXPATHLEN]; 6883c4226f9Spjha int bufsz; 6893c4226f9Spjha char *pathptr; 6903c4226f9Spjha char *pathend = NULL; 6913c4226f9Spjha int len; 6923c4226f9Spjha int rv = 0; 6933c4226f9Spjha int chasflag = 0; 6943c4226f9Spjha di_node_t curnode = node; 6953c4226f9Spjha di_node_t chasnode = DI_NODE_NIL; 6967c478bd9Sstevel@tonic-gate minor_t pci_dev; 6977c478bd9Sstevel@tonic-gate 6983c4226f9Spjha buf[0] = '\0'; 6993c4226f9Spjha pathbuf[0] = '\0'; 7003c4226f9Spjha pathptr = &pathbuf[sizeof (pathbuf) - 1]; 7013c4226f9Spjha *pathptr = '\0'; 7027c478bd9Sstevel@tonic-gate 7033c4226f9Spjha /* 7043c4226f9Spjha * as we traverse up the device tree, we prepend components of our 7053c4226f9Spjha * path inside pathbuf, using pathptr and decrementing 7063c4226f9Spjha */ 7073c4226f9Spjha pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 7083c4226f9Spjha do { 7093c4226f9Spjha bufptr = buf; 7103c4226f9Spjha bufsz = sizeof (buf); 7113c4226f9Spjha 7123c4226f9Spjha chasnode = pci_cfg_chassis_node(curnode, ph); 7133c4226f9Spjha if (chasnode != DI_NODE_NIL) { 7143c4226f9Spjha rv = pci_cfg_iob_name(minor, chasnode, ph, 7153c4226f9Spjha bufptr, bufsz); 7163c4226f9Spjha if (rv == 0) { 7173c4226f9Spjha dprint(("%s: cannot create iob name " 7183c4226f9Spjha "for %s%d\n", fnm, DRVINST(node))); 7193c4226f9Spjha *pathptr = '\0'; 7203c4226f9Spjha goto OUT; 7213c4226f9Spjha } 7223c4226f9Spjha 7233c4226f9Spjha (void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz); 7243c4226f9Spjha len = strlen(bufptr); 7253c4226f9Spjha bufptr += len; 7263c4226f9Spjha bufsz -= len - 1; 7273c4226f9Spjha 7283c4226f9Spjha /* set chasflag when the leaf node is within an iob */ 7293c4226f9Spjha if ((curnode == node) != NULL) 7303c4226f9Spjha chasflag = 1; 7313c4226f9Spjha } 7323c4226f9Spjha rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0); 7333c4226f9Spjha if (rv == 0) { 7343c4226f9Spjha dprint(("%s: cannot create ap node name " 7353c4226f9Spjha "for %s%d\n", fnm, DRVINST(node))); 7363c4226f9Spjha *pathptr = '\0'; 7373c4226f9Spjha goto OUT; 7383c4226f9Spjha } 7393c4226f9Spjha 7403c4226f9Spjha /* 7413c4226f9Spjha * if we can't fit the entire path in our pathbuf, then use 7423c4226f9Spjha * the default short name and nullify pathptr; also, since 7433c4226f9Spjha * we prepend in the buffer, we must avoid adding a null char 7443c4226f9Spjha */ 7453c4226f9Spjha if (curnode != node) { 7463c4226f9Spjha pathptr -= seplen; 7473c4226f9Spjha if (pathptr < pathbuf) { 7483c4226f9Spjha pathptr = pathbuf; 7493c4226f9Spjha *pathptr = '\0'; 7503c4226f9Spjha goto DEF; 7513c4226f9Spjha } 7523c4226f9Spjha (void) memcpy(pathptr, AP_PATH_SEP, seplen); 7533c4226f9Spjha } 7543c4226f9Spjha len = strlen(buf); 7553c4226f9Spjha pathptr -= len; 7563c4226f9Spjha if (pathptr < pathbuf) { 7573c4226f9Spjha pathptr = pathbuf; 7583c4226f9Spjha *pathptr = '\0'; 7593c4226f9Spjha goto DEF; 7603c4226f9Spjha } 7613c4226f9Spjha (void) memcpy(pathptr, buf, len); 7623c4226f9Spjha 7633c4226f9Spjha /* remember the leaf component */ 7643c4226f9Spjha if (curnode == node) 7653c4226f9Spjha pathend = pathptr; 7663c4226f9Spjha 7673c4226f9Spjha /* 7683c4226f9Spjha * go no further than the hosts' onboard slots 7693c4226f9Spjha */ 7703c4226f9Spjha if (chasnode == DI_NODE_NIL) 7713c4226f9Spjha break; 7723c4226f9Spjha curnode = chasnode; 7733c4226f9Spjha 7743c4226f9Spjha /* 7753c4226f9Spjha * the pci device number of the current node is used to 7763c4226f9Spjha * identify which slot of the parent's bus (next iteration) 7773c4226f9Spjha * the current node is on 7783c4226f9Spjha */ 7793c4226f9Spjha pci_dev = pci_cfg_pcidev(curnode, ph); 780ad86e48dSpjha if (pci_dev == PCIDEV_NIL) { 781ad86e48dSpjha dprint(("%s: cannot obtain pci device number " 782ad86e48dSpjha "for %s%d\n", fnm, DRVINST(node))); 783ad86e48dSpjha *pathptr = '\0'; 784ad86e48dSpjha goto OUT; 785ad86e48dSpjha } 7863c4226f9Spjha } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 7873c4226f9Spjha 7883c4226f9Spjha pathbuf[sizeof (pathbuf) - 1] = '\0'; 7893c4226f9Spjha if (strlen(pathptr) < ap_pathsz) { 7903c4226f9Spjha (void) strlcpy(ap_path, pathptr, ap_pathsz); 7913c4226f9Spjha rv = 1; 7923c4226f9Spjha goto OUT; 7933c4226f9Spjha } 7943c4226f9Spjha 7953c4226f9Spjha DEF: 7963c4226f9Spjha /* 7973c4226f9Spjha * when our name won't fit <ap_pathsz> we use the endpoint/leaf 7983c4226f9Spjha * <node>'s name ONLY IF it has a serialid# which will make the apid 7993c4226f9Spjha * globally unique 8003c4226f9Spjha */ 8013c4226f9Spjha if (chasflag && pathend != NULL) { 8023c4226f9Spjha if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP, 8033c4226f9Spjha ap_path_iob_sep_len) != 0) && 8043c4226f9Spjha (strlen(pathend) < ap_pathsz)) { 8053c4226f9Spjha (void) strlcpy(ap_path, pathend, ap_pathsz); 8063c4226f9Spjha rv = 1; 8073c4226f9Spjha goto OUT; 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8113c4226f9Spjha /* 8123c4226f9Spjha * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s 8133c4226f9Spjha * default name 8143c4226f9Spjha */ 8153e655c7dSjveta pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 8163c4226f9Spjha rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME); 8173c4226f9Spjha if (rv == 0) { 8183c4226f9Spjha dprint(("%s: cannot create default ap node name for %s%d\n", 8193c4226f9Spjha fnm, DRVINST(node))); 8203c4226f9Spjha *pathptr = '\0'; 8213c4226f9Spjha goto OUT; 8223c4226f9Spjha } 8233c4226f9Spjha if (strlen(buf) < ap_pathsz) { 8243c4226f9Spjha (void) strlcpy(ap_path, buf, ap_pathsz); 8253c4226f9Spjha rv = 1; 8263c4226f9Spjha goto OUT; 8273c4226f9Spjha } 8283c4226f9Spjha 8293c4226f9Spjha /* 8303c4226f9Spjha * in this case, cfgadm goes through an expensive process to generate 8313c4226f9Spjha * a purely dynamic logical apid: the framework will look through 8323c4226f9Spjha * the device tree for attachment point minor nodes and will invoke 8333c4226f9Spjha * each plugin responsible for that attachment point class, and if 8343c4226f9Spjha * the plugin returns a logical apid that matches the queried apid 8353c4226f9Spjha * or matches the default apid generated by the cfgadm framework for 8363c4226f9Spjha * that driver/class (occurs when plugin returns an empty logical apid) 8373c4226f9Spjha * then that is what it will use 8383c4226f9Spjha * 8393c4226f9Spjha * it is doubly expensive because the cfgadm pci plugin itself will 8403c4226f9Spjha * also search the entire device tree in the absence of a link 8413c4226f9Spjha */ 8423c4226f9Spjha rv = 0; 8433c4226f9Spjha dprint(("%s: cannot create apid for %s%d within length of %d\n", 8443c4226f9Spjha fnm, DRVINST(node), ap_pathsz)); 8453c4226f9Spjha 8463c4226f9Spjha OUT: 8473c4226f9Spjha ap_path[ap_pathsz - 1] = '\0'; 8483c4226f9Spjha *pathret = (*pathptr == '\0') ? NULL : strdup(pathptr); 8493c4226f9Spjha return (rv); 8503c4226f9Spjha 8513c4226f9Spjha #undef seplen 8523c4226f9Spjha #undef iob_pre_len 8533c4226f9Spjha #undef ap_path_iob_sep_len 8543c4226f9Spjha } 8553c4226f9Spjha 8563c4226f9Spjha 8573c4226f9Spjha /* 8583ebafc43Sjveta * the DI_PROP_AP_NAMES property contains the first integer section of the 8593c4226f9Spjha * ieee1275 "slot-names" property and functions as a bitmask; see comment for 8603c4226f9Spjha * pci_cfg_slotname() 8613c4226f9Spjha * 8623c4226f9Spjha * we use the name of the attachment point minor node if its pci device 8633ebafc43Sjveta * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES 8643c4226f9Spjha * 8653c4226f9Spjha * returns non-zero if we return a valid attachment point through <path> 8663c4226f9Spjha */ 8673c4226f9Spjha static int 8683c4226f9Spjha pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph, 8693c4226f9Spjha char *ap_path, int ap_pathsz) 8703c4226f9Spjha { 8713c4226f9Spjha minor_t pci_dev; 8723c4226f9Spjha int *anp; 8733c4226f9Spjha 8743ebafc43Sjveta if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES, 8753c4226f9Spjha &anp) < 1) 8763c4226f9Spjha return (0); 8773c4226f9Spjha 8783c4226f9Spjha pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor)); 8793c4226f9Spjha if ((*anp & (1 << pci_dev)) == 0) 8803c4226f9Spjha return (0); 8813c4226f9Spjha 8823c4226f9Spjha (void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz); 8833c4226f9Spjha return (1); 8843c4226f9Spjha } 8853c4226f9Spjha 8863c4226f9Spjha 8873c4226f9Spjha /* 8883c4226f9Spjha * determine if <node> qualifies for a path style apid 8893c4226f9Spjha */ 8903c4226f9Spjha static int 8913c4226f9Spjha pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph) 8923c4226f9Spjha { 8933c4226f9Spjha char *devtype; 8943c4226f9Spjha di_node_t curnode = node; 8953c4226f9Spjha 8963c4226f9Spjha do { 8973c4226f9Spjha if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode, 8983ebafc43Sjveta DI_PROP_DEV_TYPE, &devtype) > 0) 8993c4226f9Spjha if (strcmp(devtype, PROPVAL_PCIEX) == 0) 9003c4226f9Spjha return (1); 9013c4226f9Spjha } while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL); 9023c4226f9Spjha 9033c4226f9Spjha return (0); 9043c4226f9Spjha } 9053c4226f9Spjha 9063c4226f9Spjha 9073c4226f9Spjha /* 9083c4226f9Spjha * takes a full path as returned by <pathret> from pci_cfg_ap_path() and 9093c4226f9Spjha * returns an allocated string intendend to be stored in a devlink info (dli) 9103c4226f9Spjha * file 9113c4226f9Spjha * 9123c4226f9Spjha * data format: "Location: <transformed path>" 9133c4226f9Spjha * where <transformed path> is <path> with occurrances of AP_PATH_SEP 9143c4226f9Spjha * replaced by "/" 9153c4226f9Spjha */ 9163c4226f9Spjha static char * 9173c4226f9Spjha pci_cfg_info_data(char *path) 9183c4226f9Spjha { 9193c4226f9Spjha #define head "Location: " 9203c4226f9Spjha #define headlen (sizeof (head) - 1) 9213c4226f9Spjha #define seplen (sizeof (AP_PATH_SEP) - 1) 9223c4226f9Spjha 9233c4226f9Spjha char *sep, *prev, *np; 9243c4226f9Spjha char *newpath; 9253c4226f9Spjha int pathlen = strlen(path); 9263c4226f9Spjha int len; 9273c4226f9Spjha 9283c4226f9Spjha newpath = malloc(sizeof (char) * (headlen + pathlen + 1)); 9293c4226f9Spjha np = newpath; 9303c4226f9Spjha (void) strcpy(np, head); 9313c4226f9Spjha np += headlen; 9323c4226f9Spjha 9333c4226f9Spjha prev = path; 9343c4226f9Spjha while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) { 9353c4226f9Spjha len = sep - prev; 9363c4226f9Spjha (void) memcpy(np, prev, len); 9373c4226f9Spjha np += len; 9383c4226f9Spjha *np++ = '/'; 9393c4226f9Spjha prev = sep + seplen; 9403c4226f9Spjha } 9413c4226f9Spjha (void) strcpy(np, prev); 9423c4226f9Spjha return (newpath); 9433c4226f9Spjha 9443c4226f9Spjha #undef head 9453c4226f9Spjha #undef headlen 9463c4226f9Spjha #undef seplen 9473c4226f9Spjha } 9483c4226f9Spjha 9493c4226f9Spjha 9503c4226f9Spjha static void 9513c4226f9Spjha pci_cfg_rm_link(char *file) 9523c4226f9Spjha { 9533c4226f9Spjha char *dlipath; 9543c4226f9Spjha 9553c4226f9Spjha dlipath = di_dli_name(file); 9563c4226f9Spjha (void) unlink(dlipath); 9573c4226f9Spjha 9583c4226f9Spjha devfsadm_rm_all(file); 9593c4226f9Spjha free(dlipath); 9603c4226f9Spjha } 9613c4226f9Spjha 9623c4226f9Spjha /* 9633c4226f9Spjha * removes all registered devlinks to physical path <physpath> except for 9643c4226f9Spjha * the devlink <valid> if not NULL; 9653c4226f9Spjha * <physpath> must include the minor node 9663c4226f9Spjha */ 9673c4226f9Spjha static void 9683c4226f9Spjha pci_cfg_rm_invalid_links(char *physpath, char *valid) 9693c4226f9Spjha { 9703c4226f9Spjha char **dnp; 9713c4226f9Spjha char *cp, *vcp; 9723c4226f9Spjha int i, dnlen; 9733c4226f9Spjha 9743c4226f9Spjha dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen); 9753c4226f9Spjha if (dnp == NULL) 9763c4226f9Spjha return; 9773c4226f9Spjha 9783c4226f9Spjha if (valid != NULL) { 9793c4226f9Spjha if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0) 9803c4226f9Spjha vcp = valid + DEV_LEN + 1; 9813c4226f9Spjha else 9823c4226f9Spjha vcp = valid; 9833c4226f9Spjha } 9843c4226f9Spjha 9853c4226f9Spjha for (i = 0; i < dnlen; i++) { 9863c4226f9Spjha if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0) 9873c4226f9Spjha cp = dnp[i] + DEV_LEN + 1; 9883c4226f9Spjha else 9893c4226f9Spjha cp = dnp[i]; 9903c4226f9Spjha 9913c4226f9Spjha if (valid != NULL) { 9923c4226f9Spjha if (strcmp(vcp, cp) == 0) 9933c4226f9Spjha continue; 9943c4226f9Spjha } 9953c4226f9Spjha pci_cfg_rm_link(cp); 9963c4226f9Spjha } 9973c4226f9Spjha devfsadm_free_dev_names(dnp, dnlen); 9983c4226f9Spjha } 9993c4226f9Spjha 10003c4226f9Spjha 10013c4226f9Spjha /* 10023c4226f9Spjha * takes a complete devinfo snapshot and returns the root node; 10033c4226f9Spjha * callers must do a di_fini() on the returned node; 10043c4226f9Spjha * if the snapshot failed, DI_NODE_NIL is returned instead 10053c4226f9Spjha * 10063c4226f9Spjha * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node 10073c4226f9Spjha * in the new snapshot and return it through <ret_node> if it is found, 10083c4226f9Spjha * else DI_NODE_NIL is returned instead 10093c4226f9Spjha * 10103c4226f9Spjha * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return 10113c4226f9Spjha * the matching minor in the new snapshot through <ret_minor> if it is found, 10123c4226f9Spjha * else DI_MINOR_NIL is returned instead 10133c4226f9Spjha */ 10143c4226f9Spjha static di_node_t 10153c4226f9Spjha pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor, 10163c4226f9Spjha di_node_t *ret_node, di_minor_t *ret_minor) 10173c4226f9Spjha { 10183c4226f9Spjha di_node_t root_node; 10193c4226f9Spjha di_node_t node; 10203c4226f9Spjha di_minor_t minor; 10213c4226f9Spjha int pci_inst; 10223c4226f9Spjha dev_t pci_devt; 10233c4226f9Spjha 10243c4226f9Spjha *ret_node = DI_NODE_NIL; 10253c4226f9Spjha *ret_minor = DI_MINOR_NIL; 10263c4226f9Spjha 10273c4226f9Spjha root_node = di_init("/", DINFOCPYALL); 10283c4226f9Spjha if (root_node == DI_NODE_NIL) 10293c4226f9Spjha return (DI_NODE_NIL); 10303c4226f9Spjha 10313c4226f9Spjha /* 10323c4226f9Spjha * narrow down search by driver, then instance, then minor 10333c4226f9Spjha */ 10343c4226f9Spjha if (pci_node == DI_NODE_NIL) 10353c4226f9Spjha return (root_node); 10363c4226f9Spjha 10373c4226f9Spjha pci_inst = di_instance(pci_node); 10383c4226f9Spjha node = di_drv_first_node(di_driver_name(pci_node), root_node); 10393c4226f9Spjha do { 10403c4226f9Spjha if (pci_inst == di_instance(node)) { 10413c4226f9Spjha *ret_node = node; 10423c4226f9Spjha break; 10433c4226f9Spjha } 10443c4226f9Spjha } while ((node = di_drv_next_node(node)) != DI_NODE_NIL); 10453c4226f9Spjha 10463c4226f9Spjha if (node == DI_NODE_NIL) 10473c4226f9Spjha return (root_node); 10483c4226f9Spjha 10493c4226f9Spjha /* 10503c4226f9Spjha * found node, now search minors 10513c4226f9Spjha */ 10523c4226f9Spjha if (pci_minor == DI_MINOR_NIL) 10533c4226f9Spjha return (root_node); 10543c4226f9Spjha 10553c4226f9Spjha pci_devt = di_minor_devt(pci_minor); 10563c4226f9Spjha minor = DI_MINOR_NIL; 10573c4226f9Spjha while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 10583c4226f9Spjha if (pci_devt == di_minor_devt(minor)) { 10593c4226f9Spjha *ret_minor = minor; 10603c4226f9Spjha break; 10613c4226f9Spjha } 10623c4226f9Spjha } 10633c4226f9Spjha return (root_node); 10643c4226f9Spjha } 10653c4226f9Spjha 10663c4226f9Spjha 10673c4226f9Spjha static int 10683c4226f9Spjha pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node) 10693c4226f9Spjha { 10703c4226f9Spjha #ifdef DEBUG 10713c4226f9Spjha char *fnm = "pci_cfg_creat_cb"; 10723c4226f9Spjha #endif 10733c4226f9Spjha #define ap_pathsz (sizeof (ap_path)) 10743c4226f9Spjha 10753c4226f9Spjha char ap_path[CFGA_LOG_EXT_LEN]; 10763c4226f9Spjha char linkbuf[MAXPATHLEN]; 10773c4226f9Spjha char *fullpath = NULL; 10783c4226f9Spjha char *pathinfo = NULL; 10793c4226f9Spjha char *devpath = NULL; 1080ad86e48dSpjha int rv, fd = -1; 10813c4226f9Spjha size_t sz; 10823c4226f9Spjha di_prom_handle_t ph; 10833c4226f9Spjha di_node_t node; 10843c4226f9Spjha di_node_t root_node = DI_NODE_NIL; 10853c4226f9Spjha di_minor_t minor; 10863c4226f9Spjha 10873c4226f9Spjha ph = di_prom_init(); 10883c4226f9Spjha if (ph == DI_PROM_HANDLE_NIL) { 10893c4226f9Spjha dprint(("%s: di_prom_init() failed for %s%d\n", 10903c4226f9Spjha fnm, DRVINST(pci_node))); 10913c4226f9Spjha goto OUT; 10923c4226f9Spjha } 10933c4226f9Spjha 10943c4226f9Spjha /* 10953c4226f9Spjha * Since incoming nodes from hotplug events are from snapshots that 10963c4226f9Spjha * do NOT contain parent/ancestor data, we must retake our own 10973c4226f9Spjha * snapshot and search for the target node 10983c4226f9Spjha */ 10993c4226f9Spjha root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor); 11003c4226f9Spjha if (root_node == DI_NODE_NIL || node == DI_NODE_NIL || 11013c4226f9Spjha minor == DI_MINOR_NIL) { 11023c4226f9Spjha dprint(("%s: devinfo snapshot or search failed for %s%d\n", 11033c4226f9Spjha fnm, DRVINST(pci_node))); 11043c4226f9Spjha goto OUT; 11053c4226f9Spjha } 11063c4226f9Spjha 11073c4226f9Spjha if (pci_cfg_is_ap_path(node, ph)) { 11083c4226f9Spjha rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz, 11093c4226f9Spjha &fullpath); 11103c4226f9Spjha if (rv == 0) 11113c4226f9Spjha goto OUT; 11123c4226f9Spjha 11133c4226f9Spjha (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s", 11143c4226f9Spjha CFG_DIRNAME, ap_path); 11153c4226f9Spjha 11163c4226f9Spjha /* 11173c4226f9Spjha * We must remove existing links because we may have invalid 11183c4226f9Spjha * apids that are valid links. Since these are not dangling, 11193c4226f9Spjha * devfsadm will not invoke the remove callback on them. 11203c4226f9Spjha * 11213c4226f9Spjha * What are "invalid apids with valid links"? Consider swapping 11223c4226f9Spjha * an attachment point bus with another while the system is 11233c4226f9Spjha * down, on the same device path bound to the same drivers 11243c4226f9Spjha * but with the new AP bus having different properties 11253c4226f9Spjha * (e.g. serialid#). If the previous apid is not removed, 11263c4226f9Spjha * there will now be two different links pointing to the same 11273c4226f9Spjha * attachment point, but only one reflects the correct 11283c4226f9Spjha * logical apid 11293c4226f9Spjha */ 11303c4226f9Spjha devpath = pci_cfg_devpath(node, minor); 11313c4226f9Spjha if (devpath == NULL) 11323c4226f9Spjha goto OUT; 11333c4226f9Spjha pci_cfg_rm_invalid_links(devpath, linkbuf); 11343c4226f9Spjha free(devpath); 11353c4226f9Spjha 11363c4226f9Spjha (void) devfsadm_mklink(linkbuf, node, minor, 0); 11373c4226f9Spjha 11383c4226f9Spjha /* 11393c4226f9Spjha * we store the full logical path of the attachment point for 11403c4226f9Spjha * cfgadm to display in its info field which is useful when 11413c4226f9Spjha * the full logical path exceeds the size limit for logical 11423c4226f9Spjha * apids (CFGA_LOG_EXT_LEN) 11433c4226f9Spjha * 11443c4226f9Spjha * for the cfgadm pci plugin to do the same would be expensive 11453c4226f9Spjha * (i.e. devinfo snapshot + top down exhaustive minor search + 11463c4226f9Spjha * equivalent of pci_cfg_ap_path() on every invocation) 11473c4226f9Spjha * 11483c4226f9Spjha * note that if we do not create a link (pci_cfg_ap_path() is 11493c4226f9Spjha * not successful), that is what cfgadm will do anyways to 11503c4226f9Spjha * create a purely dynamic apid 11513c4226f9Spjha */ 11523c4226f9Spjha pathinfo = pci_cfg_info_data(fullpath); 11533c4226f9Spjha fd = di_dli_openw(linkbuf); 11543c4226f9Spjha if (fd < 0) 11553c4226f9Spjha goto OUT; 11563c4226f9Spjha 11573c4226f9Spjha sz = strlen(pathinfo) + 1; 11583c4226f9Spjha rv = write(fd, pathinfo, sz); 11593c4226f9Spjha if (rv < sz) { 11603c4226f9Spjha dprint(("%s: could not write full pathinfo to dli " 11613c4226f9Spjha "file for %s%d\n", fnm, DRVINST(node))); 11623c4226f9Spjha goto OUT; 11633c4226f9Spjha } 11643c4226f9Spjha di_dli_close(fd); 11653c4226f9Spjha } else { 11663c4226f9Spjha rv = pci_cfg_ap_legacy(minor, node, ph, ap_path, 11673c4226f9Spjha ap_pathsz); 11683c4226f9Spjha if (rv == 0) 11693c4226f9Spjha goto OUT; 11703c4226f9Spjha 11713c4226f9Spjha (void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s", 11723c4226f9Spjha CFG_DIRNAME, ap_path); 11733c4226f9Spjha (void) devfsadm_mklink(linkbuf, node, minor, 0); 11743c4226f9Spjha } 11753c4226f9Spjha 11763c4226f9Spjha OUT: 1177ad86e48dSpjha if (fd >= 0) 1178ad86e48dSpjha di_dli_close(fd); 11793c4226f9Spjha if (fullpath != NULL) 11803c4226f9Spjha free(fullpath); 11813c4226f9Spjha if (pathinfo != NULL) 11823c4226f9Spjha free(pathinfo); 11833c4226f9Spjha if (ph != DI_PROM_HANDLE_NIL) 11843c4226f9Spjha di_prom_fini(ph); 11853c4226f9Spjha if (root_node != DI_NODE_NIL) 11863c4226f9Spjha di_fini(root_node); 11877c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 11883c4226f9Spjha 11893c4226f9Spjha #undef ap_pathsz 11903c4226f9Spjha } 11913c4226f9Spjha 11923c4226f9Spjha 11933c4226f9Spjha static void 11943c4226f9Spjha pci_cfg_rm_all(char *file) 11953c4226f9Spjha { 11963c4226f9Spjha pci_cfg_rm_link(file); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * ib_cfg_creat_cb() creates two types of links 12027c478bd9Sstevel@tonic-gate * One for the fabric as /dev/cfg/ib 12037c478bd9Sstevel@tonic-gate * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID> 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate static int 12067c478bd9Sstevel@tonic-gate ib_cfg_creat_cb(di_minor_t minor, di_node_t node) 12077c478bd9Sstevel@tonic-gate { 12087c478bd9Sstevel@tonic-gate char *cp; 12097c478bd9Sstevel@tonic-gate char path[PATH_MAX + 1]; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if ((cp = di_devfs_path(node)) == NULL) { 12127c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 12167c478bd9Sstevel@tonic-gate di_devfs_path_free(cp); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate /* create fabric or hca:GUID and the symlink */ 12197c478bd9Sstevel@tonic-gate if (strstr(path, "ib:fabric") != NULL) { 12207c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME); 12217c478bd9Sstevel@tonic-gate } else { 12227c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME, 12237c478bd9Sstevel@tonic-gate di_minor_name(minor)); 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate (void) devfsadm_mklink(path, node, minor, 0); 12277c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 12287c478bd9Sstevel@tonic-gate } 1229226236b5Spjha 1230226236b5Spjha /* 1231226236b5Spjha * This function verifies if the serial id is printable. 1232226236b5Spjha */ 1233226236b5Spjha 1234226236b5Spjha static int 1235226236b5Spjha serid_printable(uint64_t *seridp) 1236226236b5Spjha { 1237226236b5Spjha 1238226236b5Spjha char *ptr; 1239226236b5Spjha int i = 0; 1240226236b5Spjha 1241226236b5Spjha for (ptr = (char *)seridp+3; i < 5; ptr++, i++) 1242226236b5Spjha if (*ptr < 0x21 || *ptr >= 0x7f) 1243226236b5Spjha return (0); 1244226236b5Spjha 1245226236b5Spjha return (1); 1246226236b5Spjha 1247226236b5Spjha } 1248