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
scsi_cfg_creat_cb(di_minor_t minor,di_node_t node)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
sbd_cfg_creat_cb(di_minor_t minor,di_node_t node)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
usb_cfg_creat_cb(di_minor_t minor,di_node_t node)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
sata_cfg_creat_cb(di_minor_t minor,di_node_t node)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
sdcard_cfg_creat_cb(di_minor_t minor,di_node_t node)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 *
get_roothub(const char * path,void * cb_arg)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 *
pci_cfg_devpath(di_node_t node,di_minor_t minor)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
di_propall_lookup_ints(di_prom_handle_t ph,int flags,dev_t dev,di_node_t node,const char * prop_name,int ** prop_data)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
di_propall_lookup_strings(di_prom_handle_t ph,int flags,dev_t dev,di_node_t node,const char * prop_name,char ** prop_data)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
pci_cfg_chassis_node(di_node_t node,di_prom_handle_t ph)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
di_propall_lookup_slot_names(di_prom_handle_t ph,int flags,dev_t dev,di_node_t node,di_slot_name_t ** prop_data)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 *
pci_cfg_slotname(di_node_t node,di_prom_handle_t ph,minor_t pci_dev)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
pci_cfg_ap_node(minor_t pci_dev,di_node_t node,di_prom_handle_t ph,char * buf,int bufsz,int flags)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
pci_cfg_iob_name(di_minor_t minor,di_node_t node,di_prom_handle_t ph,char * buf,int bufsz)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
pci_cfg_pcidev(di_node_t node,di_prom_handle_t ph)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
pci_cfg_ap_path(di_minor_t minor,di_node_t node,di_prom_handle_t ph,char * ap_path,int ap_pathsz,char ** pathret)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
pci_cfg_ap_legacy(di_minor_t minor,di_node_t node,di_prom_handle_t ph,char * ap_path,int ap_pathsz)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
pci_cfg_is_ap_path(di_node_t node,di_prom_handle_t ph)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 *
pci_cfg_info_data(char * path)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
pci_cfg_rm_link(char * file)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
pci_cfg_rm_invalid_links(char * physpath,char * valid)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
pci_cfg_snapshot(di_node_t pci_node,di_minor_t pci_minor,di_node_t * ret_node,di_minor_t * ret_minor)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
pci_cfg_creat_cb(di_minor_t pci_minor,di_node_t pci_node)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
pci_cfg_rm_all(char * file)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
ib_cfg_creat_cb(di_minor_t minor,di_node_t node)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
serid_printable(uint64_t * seridp)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