Home | History | Annotate | Download | only in devfsadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <devfsadm.h>
     28 #include <stdio.h>
     29 #include <strings.h>
     30 #include <stdlib.h>
     31 #include <stdarg.h>
     32 #include <limits.h>
     33 #include <unistd.h>
     34 #include <config_admin.h>
     35 #include <cfg_link.h>
     36 #include <sys/types.h>
     37 #include <sys/mkdev.h>
     38 #include <sys/hotplug/pci/pcihp.h>
     39 
     40 #ifdef	DEBUG
     41 #define	dprint(args)	devfsadm_errprint args
     42 /*
     43  * for use in print routine arg list as a shorthand way to locate node via
     44  * "prtconf -D" to avoid messy and cluttered debugging code
     45  * don't forget the corresponding "%s%d" format
     46  */
     47 #define	DRVINST(node)	di_driver_name(node), di_instance(node)
     48 #else
     49 #define	dprint(args)
     50 #endif
     51 
     52 
     53 static int	scsi_cfg_creat_cb(di_minor_t minor, di_node_t node);
     54 static int	sbd_cfg_creat_cb(di_minor_t minor, di_node_t node);
     55 static int	usb_cfg_creat_cb(di_minor_t minor, di_node_t node);
     56 static char	*get_roothub(const char *path, void *cb_arg);
     57 static int	pci_cfg_creat_cb(di_minor_t minor, di_node_t node);
     58 static int	ib_cfg_creat_cb(di_minor_t minor, di_node_t node);
     59 static int	sata_cfg_creat_cb(di_minor_t minor, di_node_t node);
     60 static int	sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node);
     61 
     62 static di_node_t	pci_cfg_chassis_node(di_node_t, di_prom_handle_t);
     63 static char 	*pci_cfg_slotname(di_node_t, di_prom_handle_t, minor_t);
     64 static int	pci_cfg_ap_node(minor_t, di_node_t, di_prom_handle_t,
     65 		    char *, int, int);
     66 static int	pci_cfg_iob_name(di_minor_t, di_node_t, di_prom_handle_t,
     67 		    char *, int);
     68 static minor_t	pci_cfg_pcidev(di_node_t, di_prom_handle_t);
     69 static int	pci_cfg_ap_path(di_minor_t, di_node_t, di_prom_handle_t,
     70 		    char *, int, char **);
     71 static char 	*pci_cfg_info_data(char *);
     72 static int	pci_cfg_is_ap_path(di_node_t, di_prom_handle_t);
     73 static int	pci_cfg_ap_legacy(di_minor_t, di_node_t, di_prom_handle_t,
     74 		    char *, int);
     75 static void	pci_cfg_rm_invalid_links(char *, char *);
     76 static void	pci_cfg_rm_link(char *);
     77 static void	pci_cfg_rm_all(char *);
     78 static char	*pci_cfg_devpath(di_node_t, di_minor_t);
     79 static di_node_t	pci_cfg_snapshot(di_node_t, di_minor_t,
     80 			    di_node_t *, di_minor_t *);
     81 
     82 /* flag definitions for di_propall_*(); value "0" is always the default flag */
     83 #define	DIPROP_PRI_NODE		0x0
     84 #define	DIPROP_PRI_PROM		0x1
     85 static int	di_propall_lookup_ints(di_prom_handle_t, int,
     86 		    dev_t, di_node_t, const char *, int **);
     87 static int	di_propall_lookup_strings(di_prom_handle_t, int,
     88 		    dev_t, di_node_t, const char *, char **);
     89 static int 	serid_printable(uint64_t *seridp);
     90 static int	di_propall_lookup_slot_names(di_prom_handle_t, int,
     91 		    dev_t, di_node_t, di_slot_name_t **);
     92 
     93 
     94 /*
     95  * NOTE: The CREATE_DEFER flag is private to this module.
     96  *	 NOT to be used by other modules
     97  */
     98 static devfsadm_create_t cfg_create_cbt[] = {
     99 	{ "attachment-point", DDI_NT_SCSI_ATTACHMENT_POINT, NULL,
    100 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
    101 	},
    102 	{ "attachment-point", DDI_NT_SBD_ATTACHMENT_POINT, NULL,
    103 	    TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb
    104 	},
    105 	{ "fc-attachment-point", DDI_NT_FC_ATTACHMENT_POINT, NULL,
    106 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb
    107 	},
    108 	{ "attachment-point", DDI_NT_USB_ATTACHMENT_POINT, NULL,
    109 	    TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb
    110 	},
    111 	{ "attachment-point", DDI_NT_PCI_ATTACHMENT_POINT, NULL,
    112 	    TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb
    113 	},
    114 	{ "attachment-point", DDI_NT_IB_ATTACHMENT_POINT, NULL,
    115 	    TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb
    116 	},
    117 	{ "attachment-point", DDI_NT_SATA_ATTACHMENT_POINT, NULL,
    118 	    TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb
    119 	},
    120 	{ "attachment-point", DDI_NT_SDCARD_ATTACHMENT_POINT, NULL,
    121 	    TYPE_EXACT, ILEVEL_0, sdcard_cfg_creat_cb
    122 	}
    123 };
    124 
    125 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt);
    126 
    127 static devfsadm_remove_t cfg_remove_cbt[] = {
    128 	{ "attachment-point", SCSI_CFG_LINK_RE, RM_POST,
    129 	    ILEVEL_0, devfsadm_rm_all
    130 	},
    131 	{ "attachment-point", SBD_CFG_LINK_RE, RM_POST,
    132 	    ILEVEL_0, devfsadm_rm_all
    133 	},
    134 	{ "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST,
    135 	    ILEVEL_0, devfsadm_rm_all
    136 	},
    137 	{ "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
    138 	    ILEVEL_0, devfsadm_rm_all
    139 	},
    140 	{ "attachment-point", PCI_CFG_LINK_RE, RM_POST,
    141 	    ILEVEL_0, devfsadm_rm_all
    142 	},
    143 	{ "attachment-point", PCI_CFG_PATH_LINK_RE, RM_POST|RM_HOT,
    144 	    ILEVEL_0, pci_cfg_rm_all
    145 	},
    146 	{ "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
    147 	    ILEVEL_0, devfsadm_rm_all
    148 	},
    149 	{ "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
    150 	    ILEVEL_0, devfsadm_rm_all
    151 	},
    152 	{ "attachment-point", SDCARD_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS,
    153 	    ILEVEL_0, devfsadm_rm_all
    154 	},
    155 };
    156 
    157 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt);
    158 
    159 static int
    160 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node)
    161 {
    162 	char path[PATH_MAX + 1];
    163 	char *c_num = NULL, *devfs_path, *mn;
    164 	devfsadm_enumerate_t rules[3] = {
    165 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
    166 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
    167 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
    168 	};
    169 
    170 	mn = di_minor_name(minor);
    171 
    172 	if ((devfs_path = di_devfs_path(node)) == NULL) {
    173 		return (DEVFSADM_CONTINUE);
    174 	}
    175 	(void) strcpy(path, devfs_path);
    176 	(void) strcat(path, ":");
    177 	(void) strcat(path, mn);
    178 	di_devfs_path_free(devfs_path);
    179 
    180 	if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3)
    181 	    == DEVFSADM_FAILURE) {
    182 		/*
    183 		 * Unlike the disks module we don't retry on failure.
    184 		 * If we have multiple "c" numbers for a single physical
    185 		 * controller due to bug 4045879, we will not assign a
    186 		 * c-number/symlink for the controller.
    187 		 */
    188 		return (DEVFSADM_CONTINUE);
    189 	}
    190 
    191 	(void) strcpy(path, CFG_DIRNAME);
    192 	(void) strcat(path, "/c");
    193 	(void) strcat(path, c_num);
    194 
    195 	free(c_num);
    196 
    197 	(void) devfsadm_mklink(path, node, minor, 0);
    198 
    199 	return (DEVFSADM_CONTINUE);
    200 }
    201 
    202 static int
    203 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node)
    204 {
    205 	char path[PATH_MAX + 1];
    206 
    207 	(void) strcpy(path, CFG_DIRNAME);
    208 	(void) strcat(path, "/");
    209 	(void) strcat(path, di_minor_name(minor));
    210 	(void) devfsadm_mklink(path, node, minor, 0);
    211 	return (DEVFSADM_CONTINUE);
    212 }
    213 
    214 
    215 static int
    216 usb_cfg_creat_cb(di_minor_t minor, di_node_t node)
    217 {
    218 	char *cp, path[PATH_MAX + 1];
    219 	devfsadm_enumerate_t rules[1] =
    220 		{"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub};
    221 
    222 	if ((cp = di_devfs_path(node)) == NULL) {
    223 		return (DEVFSADM_CONTINUE);
    224 	}
    225 
    226 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
    227 	di_devfs_path_free(cp);
    228 
    229 	if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) {
    230 		return (DEVFSADM_CONTINUE);
    231 	}
    232 
    233 	/* create usbN and the symlink */
    234 	(void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp,
    235 	    di_minor_name(minor));
    236 	free(cp);
    237 
    238 	(void) devfsadm_mklink(path, node, minor, 0);
    239 
    240 	return (DEVFSADM_CONTINUE);
    241 }
    242 
    243 
    244 static int
    245 sata_cfg_creat_cb(di_minor_t minor, di_node_t node)
    246 {
    247 	char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath;
    248 	char *minor_nm;
    249 	devfsadm_enumerate_t rules[1] =
    250 		{"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR};
    251 
    252 	minor_nm = di_minor_name(minor);
    253 	if (minor_nm == NULL)
    254 		return (DEVFSADM_CONTINUE);
    255 
    256 	devfspath = di_devfs_path(node);
    257 	if (devfspath == NULL)
    258 		return (DEVFSADM_CONTINUE);
    259 
    260 	(void) strlcpy(path, devfspath, sizeof (path));
    261 	(void) strlcat(path, ":", sizeof (path));
    262 	(void) strlcat(path, minor_nm, sizeof (path));
    263 	di_devfs_path_free(devfspath);
    264 
    265 	/* build the physical path from the components */
    266 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
    267 	    DEVFSADM_FAILURE) {
    268 		return (DEVFSADM_CONTINUE);
    269 	}
    270 
    271 	(void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME,
    272 	    buf, minor_nm);
    273 	free(buf);
    274 
    275 	(void) devfsadm_mklink(l_path, node, minor, 0);
    276 
    277 	return (DEVFSADM_CONTINUE);
    278 }
    279 
    280 static int
    281 sdcard_cfg_creat_cb(di_minor_t minor, di_node_t node)
    282 {
    283 	char path[PATH_MAX +1], l_path[PATH_MAX], *buf, *devfspath;
    284 	char *minor_nm;
    285 	devfsadm_enumerate_t rules[1] =
    286 	    {"^cfg$/^sdcard([0-9]+)$", 1, MATCH_ADDR};
    287 
    288 	minor_nm = di_minor_name(minor);
    289 	if (minor_nm == NULL)
    290 		return (DEVFSADM_CONTINUE);
    291 
    292 	devfspath = di_devfs_path(node);
    293 	if (devfspath == NULL)
    294 		return (DEVFSADM_CONTINUE);
    295 
    296 	(void) snprintf(path, sizeof (path), "%s:%s", devfspath, minor_nm);
    297 	di_devfs_path_free(devfspath);
    298 
    299 	/* build the physical path from the components */
    300 	if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) ==
    301 	    DEVFSADM_FAILURE) {
    302 		return (DEVFSADM_CONTINUE);
    303 	}
    304 
    305 	(void) snprintf(l_path, sizeof (l_path), "%s/sdcard%s/%s",
    306 	    CFG_DIRNAME, buf, minor_nm);
    307 	free(buf);
    308 
    309 	(void) devfsadm_mklink(l_path, node, minor, 0);
    310 
    311 	return (DEVFSADM_CONTINUE);
    312 }
    313 
    314 /*
    315  * get_roothub:
    316  *	figure out the root hub path to calculate /dev/cfg/usbN
    317  */
    318 /* ARGSUSED */
    319 static char *
    320 get_roothub(const char *path, void *cb_arg)
    321 {
    322 	int  i, count = 0;
    323 	char *physpath, *cp;
    324 
    325 	/* make a copy */
    326 	if ((physpath = strdup(path)) == NULL) {
    327 		return (NULL);
    328 	}
    329 
    330 	/*
    331 	 * physpath must always have a minor name component
    332 	 */
    333 	if ((cp = strrchr(physpath, ':')) == NULL) {
    334 		free(physpath);
    335 		return (NULL);
    336 	}
    337 	*cp++ = '\0';
    338 
    339 	/*
    340 	 * No '.' in the minor name indicates a roothub port.
    341 	 */
    342 	if (strchr(cp, '.') == NULL) {
    343 		/* roothub device */
    344 		return (physpath);
    345 	}
    346 
    347 	while (*cp) {
    348 		if (*cp == '.')
    349 			count++;
    350 		cp++;
    351 	}
    352 
    353 	/* Remove as many trailing path components as there are '.'s */
    354 	for (i = 0; i < count; i++) {
    355 		if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) {
    356 			free(physpath);
    357 			return (NULL);
    358 		}
    359 		*cp = '\0';
    360 	}
    361 
    362 	return (physpath);
    363 }
    364 
    365 
    366 /*
    367  * returns an allocted string containing the device path for <node> and
    368  * <minor>
    369  */
    370 static char *
    371 pci_cfg_devpath(di_node_t node, di_minor_t minor)
    372 {
    373 	char *path;
    374 	char *bufp;
    375 	char *minor_nm;
    376 	int buflen;
    377 
    378 	path = di_devfs_path(node);
    379 	minor_nm = di_minor_name(minor);
    380 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
    381 
    382 	bufp = malloc(sizeof (char) * buflen);
    383 	if (bufp != NULL)
    384 		(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
    385 
    386 	di_devfs_path_free(path);
    387 	return (bufp);
    388 }
    389 
    390 
    391 static int
    392 di_propall_lookup_ints(di_prom_handle_t ph, int flags,
    393     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
    394 {
    395 	int rv;
    396 
    397 	if (flags & DIPROP_PRI_PROM) {
    398 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
    399 		if (rv < 0)
    400 			rv = di_prop_lookup_ints(dev, node, prop_name,
    401 			    prop_data);
    402 	} else {
    403 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
    404 		if (rv < 0)
    405 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
    406 			    prop_data);
    407 	}
    408 	return (rv);
    409 }
    410 
    411 
    412 static int
    413 di_propall_lookup_strings(di_prom_handle_t ph, int flags,
    414     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
    415 {
    416 	int rv;
    417 
    418 	if (flags & DIPROP_PRI_PROM) {
    419 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
    420 		    prop_data);
    421 		if (rv < 0)
    422 			rv = di_prop_lookup_strings(dev, node, prop_name,
    423 			    prop_data);
    424 	} else {
    425 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
    426 		if (rv < 0)
    427 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
    428 			    prop_data);
    429 	}
    430 	return (rv);
    431 }
    432 
    433 
    434 static di_node_t
    435 pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
    436 {
    437 	di_node_t curnode = node;
    438 	int *firstchas;
    439 
    440 	do {
    441 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
    442 		    DI_PROP_FIRST_CHAS, &firstchas) >= 0)
    443 			return (curnode);
    444 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
    445 
    446 	return (DI_NODE_NIL);
    447 }
    448 
    449 
    450 static int
    451 di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
    452     dev_t dev, di_node_t node, di_slot_name_t **prop_data)
    453 {
    454 	int rv;
    455 
    456 	if (flags & DIPROP_PRI_PROM) {
    457 		rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
    458 		if (rv < 0)
    459 			rv = di_prop_lookup_slot_names(dev, node, prop_data);
    460 	} else {
    461 		rv = di_prop_lookup_slot_names(dev, node, prop_data);
    462 		if (rv < 0)
    463 			rv = di_prom_prop_lookup_slot_names(ph, node,
    464 			    prop_data);
    465 	}
    466 	return (rv);
    467 }
    468 
    469 /*
    470  * returns an allocated string containing the slot name for the slot with
    471  * device number <pci_dev> on bus <node>
    472  */
    473 static char *
    474 pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
    475 {
    476 #ifdef	DEBUG
    477 	char *fnm = "pci_cfg_slotname";
    478 #endif
    479 	int i, count;
    480 	char *name = NULL;
    481 	di_slot_name_t *slot_names = NULL;
    482 
    483 	count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
    484 	    &slot_names);
    485 	if (count < 0)
    486 		return (NULL);
    487 
    488 	for (i = 0; i < count; i++) {
    489 		if (slot_names[i].num == (int)pci_dev) {
    490 			name = strdup(slot_names[i].name);
    491 			break;
    492 		}
    493 	}
    494 #ifdef	DEBUG
    495 	if (name == NULL)
    496 		dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
    497 		    fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
    498 #endif
    499 	if (count > 0)
    500 		di_slot_names_free(count, slot_names);
    501 	return (name);
    502 }
    503 
    504 
    505 /*
    506  * returns non-zero if we can return a valid attachment point name for <node>,
    507  * for its slot identified by child pci device number <pci_dev>, through <buf>
    508  *
    509  * prioritized naming scheme:
    510  *	1) <DI_PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
    511  *	2) <device-type><DI_PROP_PHYS_SLOT property>
    512  *	3) <drv name><drv inst>.<device-type><pci_dev>
    513  *
    514  * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
    515  *	if its value is "pciex" then <device-type> is "pcie"
    516  *	else the raw value is used
    517  *
    518  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
    519  */
    520 static int
    521 pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
    522     char *buf, int bufsz, int flags)
    523 {
    524 	int *nump;
    525 	int rv;
    526 	char *str, *devtype;
    527 
    528 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
    529 	    DI_PROP_DEV_TYPE, &devtype);
    530 	if (rv < 1)
    531 		return (0);
    532 
    533 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
    534 		devtype = DEVTYPE_PCIE;
    535 
    536 	if (flags & APNODE_DEFNAME)
    537 		goto DEF;
    538 
    539 	str = pci_cfg_slotname(node, ph, pci_dev);
    540 	if (str != NULL) {
    541 		(void) strlcpy(buf, str, bufsz);
    542 		free(str);
    543 		return (1);
    544 	}
    545 
    546 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
    547 	    DI_PROP_PHYS_SLOT, &nump) > 0) {
    548 		if (*nump > 0) {
    549 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
    550 			return (1);
    551 		}
    552 	}
    553 DEF:
    554 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
    555 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
    556 
    557 	return (1);
    558 }
    559 
    560 
    561 /*
    562  * returns non-zero if we can return a valid expansion chassis name for <node>
    563  * through <buf>
    564  *
    565  * prioritized naming scheme:
    566  *	1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
    567  *	2) <IOB_PRE string><full DI_PROP_SERID property in hex>
    568  *	3) <IOB_PRE string>
    569  *
    570  * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
    571  * <24 bits: IEEE company id><40 bits: serial number>
    572  *
    573  * sun encoding of 40 bit serial number:
    574  * first byte = device type indicator
    575  * next 4 bytes = 4 ascii characters
    576  *
    577  * In the unlikely event that serial id contains non-printable characters
    578  * the full 64 bit raw hex string will be used for the attachment point.
    579  */
    580 /*ARGSUSED*/
    581 static int
    582 pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
    583     char *buf, int bufsz)
    584 {
    585 	int64_t *seridp;
    586 	uint64_t serid;
    587 	char *idstr;
    588 
    589 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
    590 	    &seridp) < 1) {
    591 		(void) strlcpy(buf, IOB_PRE, bufsz);
    592 		return (1);
    593 	}
    594 
    595 	serid = (uint64_t)*seridp;
    596 
    597 	if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
    598 	    !serid_printable(&serid)) {
    599 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
    600 		return (1);
    601 	}
    602 
    603 	/*
    604 	 * the serial id is constructed from lower 40 bits of the serialid
    605 	 * property and is represented by 5 ascii characters. The first
    606 	 * character indicates if the IO Box is PCIe or PCI-X.
    607 	 */
    608 
    609 	serid <<= 24;
    610 	idstr = (char *)&serid;
    611 	idstr[sizeof (serid) -1] = '\0';
    612 
    613 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
    614 
    615 	return (1);
    616 }
    617 
    618 
    619 /*
    620  * returns the pci device number for <node> if found, else returns PCIDEV_NIL
    621  */
    622 static minor_t
    623 pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
    624 {
    625 	int rv;
    626 	int *regp;
    627 
    628 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
    629 	    &regp);
    630 
    631 	if (rv < 1) {
    632 		dprint(("pci_cfg_pcidev: property %s not found "
    633 		    "for %s%d\n", DI_PROP_REG, DRVINST(node)));
    634 		return (PCIDEV_NIL);
    635 	}
    636 
    637 	return (REG_PCIDEV(regp));
    638 }
    639 
    640 
    641 /*
    642  * returns non-zero when it can successfully return an attachment point
    643  * through <ap_path> whose length is less than <ap_pathsz>; returns the full
    644  * path of the AP through <pathret> which may be larger than <ap_pathsz>.
    645  * Callers need to free <pathret>.  If it cannot return the full path through
    646  * <pathret> it will be set to NULL
    647  *
    648  * The ap path reflects a subset of the device path from an onboard host slot
    649  * up to <node>.  We traverse up the device tree starting from <node>, naming
    650  * each component using pci_cfg_ap_node().  If we detect that a certain
    651  * segment is contained within an expansion chassis, then we skip any bus
    652  * nodes in between our current node and the topmost node of the chassis,
    653  * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name
    654  * of the expansion chassis as given by pci_cfg_iob_name()
    655  *
    656  * This scheme is always used for <pathret>.  If however, the size of
    657  * <pathret> is greater than <ap_pathsz> then only the default name as given
    658  * by pci_cfg_ap_node() for <node> will be used
    659  */
    660 static int
    661 pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
    662     char *ap_path, int ap_pathsz, char **pathret)
    663 {
    664 #ifdef	DEBUG
    665 	char *fnm = "pci_cfg_ap_path";
    666 #endif
    667 #define	seplen		(sizeof (AP_PATH_SEP) - 1)
    668 #define	iob_pre_len	(sizeof (IOB_PRE) - 1)
    669 #define	ap_path_iob_sep_len	(sizeof (AP_PATH_IOB_SEP) - 1)
    670 
    671 	char *bufptr;
    672 	char buf[MAXPATHLEN];
    673 	char pathbuf[MAXPATHLEN];
    674 	int bufsz;
    675 	char *pathptr;
    676 	char *pathend = NULL;
    677 	int len;
    678 	int rv = 0;
    679 	int chasflag = 0;
    680 	di_node_t curnode = node;
    681 	di_node_t chasnode = DI_NODE_NIL;
    682 	minor_t pci_dev;
    683 
    684 	buf[0] = '\0';
    685 	pathbuf[0] = '\0';
    686 	pathptr = &pathbuf[sizeof (pathbuf) - 1];
    687 	*pathptr = '\0';
    688 
    689 	/*
    690 	 * as we traverse up the device tree, we prepend components of our
    691 	 * path inside pathbuf, using pathptr and decrementing
    692 	 */
    693 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
    694 	do {
    695 		bufptr = buf;
    696 		bufsz = sizeof (buf);
    697 
    698 		chasnode = pci_cfg_chassis_node(curnode, ph);
    699 		if (chasnode != DI_NODE_NIL) {
    700 			rv = pci_cfg_iob_name(minor, chasnode, ph,
    701 			    bufptr, bufsz);
    702 			if (rv == 0) {
    703 				dprint(("%s: cannot create iob name "
    704 				    "for %s%d\n", fnm, DRVINST(node)));
    705 				*pathptr = '\0';
    706 				goto OUT;
    707 			}
    708 
    709 			(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
    710 			len = strlen(bufptr);
    711 			bufptr += len;
    712 			bufsz -= len - 1;
    713 
    714 			/* set chasflag when the leaf node is within an iob */
    715 			if ((curnode == node) != NULL)
    716 				chasflag = 1;
    717 		}
    718 		rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
    719 		if (rv == 0) {
    720 			dprint(("%s: cannot create ap node name "
    721 			    "for %s%d\n", fnm, DRVINST(node)));
    722 			*pathptr = '\0';
    723 			goto OUT;
    724 		}
    725 
    726 		/*
    727 		 * if we can't fit the entire path in our pathbuf, then use
    728 		 * the default short name and nullify pathptr; also, since
    729 		 * we prepend in the buffer, we must avoid adding a null char
    730 		 */
    731 		if (curnode != node) {
    732 			pathptr -= seplen;
    733 			if (pathptr < pathbuf) {
    734 				pathptr = pathbuf;
    735 				*pathptr = '\0';
    736 				goto DEF;
    737 			}
    738 			(void) memcpy(pathptr, AP_PATH_SEP, seplen);
    739 		}
    740 		len = strlen(buf);
    741 		pathptr -= len;
    742 		if (pathptr < pathbuf) {
    743 			pathptr = pathbuf;
    744 			*pathptr = '\0';
    745 			goto DEF;
    746 		}
    747 		(void) memcpy(pathptr, buf, len);
    748 
    749 		/* remember the leaf component */
    750 		if (curnode == node)
    751 			pathend = pathptr;
    752 
    753 		/*
    754 		 * go no further than the hosts' onboard slots
    755 		 */
    756 		if (chasnode == DI_NODE_NIL)
    757 			break;
    758 		curnode = chasnode;
    759 
    760 		/*
    761 		 * the pci device number of the current node is used to
    762 		 * identify which slot of the parent's bus (next iteration)
    763 		 * the current node is on
    764 		 */
    765 		pci_dev = pci_cfg_pcidev(curnode, ph);
    766 		if (pci_dev == PCIDEV_NIL) {
    767 			dprint(("%s: cannot obtain pci device number "
    768 			    "for %s%d\n", fnm, DRVINST(node)));
    769 			*pathptr = '\0';
    770 			goto OUT;
    771 		}
    772 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
    773 
    774 	pathbuf[sizeof (pathbuf) - 1] = '\0';
    775 	if (strlen(pathptr) < ap_pathsz) {
    776 		(void) strlcpy(ap_path, pathptr, ap_pathsz);
    777 		rv = 1;
    778 		goto OUT;
    779 	}
    780 
    781 DEF:
    782 	/*
    783 	 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
    784 	 * <node>'s name ONLY IF it has a serialid# which will make the apid
    785 	 * globally unique
    786 	 */
    787 	if (chasflag && pathend != NULL) {
    788 		if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
    789 		    ap_path_iob_sep_len) != 0) &&
    790 		    (strlen(pathend) < ap_pathsz)) {
    791 			(void) strlcpy(ap_path, pathend, ap_pathsz);
    792 			rv = 1;
    793 			goto OUT;
    794 		}
    795 	}
    796 
    797 	/*
    798 	 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
    799 	 * default name
    800 	 */
    801 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
    802 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
    803 	if (rv == 0) {
    804 		dprint(("%s: cannot create default ap node name for %s%d\n",
    805 		    fnm, DRVINST(node)));
    806 		*pathptr = '\0';
    807 		goto OUT;
    808 	}
    809 	if (strlen(buf) < ap_pathsz) {
    810 		(void) strlcpy(ap_path, buf, ap_pathsz);
    811 		rv = 1;
    812 		goto OUT;
    813 	}
    814 
    815 	/*
    816 	 * in this case, cfgadm goes through an expensive process to generate
    817 	 * a purely dynamic logical apid: the framework will look through
    818 	 * the device tree for attachment point minor nodes and will invoke
    819 	 * each plugin responsible for that attachment point class, and if
    820 	 * the plugin returns a logical apid that matches the queried apid
    821 	 * or matches the default apid generated by the cfgadm framework for
    822 	 * that driver/class (occurs when plugin returns an empty logical apid)
    823 	 * then that is what it will use
    824 	 *
    825 	 * it is doubly expensive because the cfgadm pci plugin itself will
    826 	 * also search the entire device tree in the absence of a link
    827 	 */
    828 	rv = 0;
    829 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
    830 	    fnm, DRVINST(node), ap_pathsz));
    831 
    832 OUT:
    833 	ap_path[ap_pathsz - 1] = '\0';
    834 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
    835 	return (rv);
    836 
    837 #undef	seplen
    838 #undef	iob_pre_len
    839 #undef	ap_path_iob_sep_len
    840 }
    841 
    842 
    843 /*
    844  * the DI_PROP_AP_NAMES property contains the first integer section of the
    845  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
    846  * pci_cfg_slotname()
    847  *
    848  * we use the name of the attachment point minor node if its pci device
    849  * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
    850  *
    851  * returns non-zero if we return a valid attachment point through <path>
    852  */
    853 static int
    854 pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
    855     char *ap_path, int ap_pathsz)
    856 {
    857 	minor_t pci_dev;
    858 	int *anp;
    859 
    860 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
    861 	    &anp) < 1)
    862 		return (0);
    863 
    864 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
    865 	if ((*anp & (1 << pci_dev)) == 0)
    866 		return (0);
    867 
    868 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
    869 	return (1);
    870 }
    871 
    872 
    873 /*
    874  * determine if <node> qualifies for a path style apid
    875  */
    876 static int
    877 pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
    878 {
    879 	char *devtype;
    880 	di_node_t curnode = node;
    881 
    882 	do {
    883 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
    884 		    DI_PROP_DEV_TYPE, &devtype) > 0)
    885 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
    886 				return (1);
    887 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
    888 
    889 	return (0);
    890 }
    891 
    892 
    893 /*
    894  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
    895  * returns an allocated string intendend to be stored in a devlink info (dli)
    896  * file
    897  *
    898  * data format: "Location: <transformed path>"
    899  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
    900  * replaced by "/"
    901  */
    902 static char *
    903 pci_cfg_info_data(char *path)
    904 {
    905 #define	head	"Location: "
    906 #define	headlen	(sizeof (head) - 1)
    907 #define	seplen	(sizeof (AP_PATH_SEP) - 1)
    908 
    909 	char *sep, *prev, *np;
    910 	char *newpath;
    911 	int pathlen = strlen(path);
    912 	int len;
    913 
    914 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
    915 	np = newpath;
    916 	(void) strcpy(np, head);
    917 	np += headlen;
    918 
    919 	prev = path;
    920 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
    921 		len = sep - prev;
    922 		(void) memcpy(np, prev, len);
    923 		np += len;
    924 		*np++ = '/';
    925 		prev = sep + seplen;
    926 	}
    927 	(void) strcpy(np, prev);
    928 	return (newpath);
    929 
    930 #undef	head
    931 #undef	headlen
    932 #undef	seplen
    933 }
    934 
    935 
    936 static void
    937 pci_cfg_rm_link(char *file)
    938 {
    939 	char *dlipath;
    940 
    941 	dlipath = di_dli_name(file);
    942 	(void) unlink(dlipath);
    943 
    944 	devfsadm_rm_all(file);
    945 	free(dlipath);
    946 }
    947 
    948 /*
    949  * removes all registered devlinks to physical path <physpath> except for
    950  * the devlink <valid> if not NULL;
    951  * <physpath> must include the minor node
    952  */
    953 static void
    954 pci_cfg_rm_invalid_links(char *physpath, char *valid)
    955 {
    956 	char **dnp;
    957 	char *cp, *vcp;
    958 	int i, dnlen;
    959 
    960 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
    961 	if (dnp == NULL)
    962 		return;
    963 
    964 	if (valid != NULL) {
    965 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
    966 			vcp = valid + DEV_LEN + 1;
    967 		else
    968 			vcp = valid;
    969 	}
    970 
    971 	for (i = 0; i < dnlen; i++) {
    972 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
    973 			cp = dnp[i] + DEV_LEN + 1;
    974 		else
    975 			cp = dnp[i];
    976 
    977 		if (valid != NULL) {
    978 			if (strcmp(vcp, cp) == 0)
    979 				continue;
    980 		}
    981 		pci_cfg_rm_link(cp);
    982 	}
    983 	devfsadm_free_dev_names(dnp, dnlen);
    984 }
    985 
    986 
    987 /*
    988  * takes a complete devinfo snapshot and returns the root node;
    989  * callers must do a di_fini() on the returned node;
    990  * if the snapshot failed, DI_NODE_NIL is returned instead
    991  *
    992  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
    993  * in the new snapshot and return it through <ret_node> if it is found,
    994  * else DI_NODE_NIL is returned instead
    995  *
    996  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
    997  * the matching minor in the new snapshot through <ret_minor> if it is found,
    998  * else DI_MINOR_NIL is returned instead
    999  */
   1000 static di_node_t
   1001 pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
   1002     di_node_t *ret_node, di_minor_t *ret_minor)
   1003 {
   1004 	di_node_t root_node;
   1005 	di_node_t node;
   1006 	di_minor_t minor;
   1007 	int pci_inst;
   1008 	dev_t pci_devt;
   1009 
   1010 	*ret_node = DI_NODE_NIL;
   1011 	*ret_minor = DI_MINOR_NIL;
   1012 
   1013 	root_node = di_init("/", DINFOCPYALL);
   1014 	if (root_node == DI_NODE_NIL)
   1015 		return (DI_NODE_NIL);
   1016 
   1017 	/*
   1018 	 * narrow down search by driver, then instance, then minor
   1019 	 */
   1020 	if (pci_node == DI_NODE_NIL)
   1021 		return (root_node);
   1022 
   1023 	pci_inst = di_instance(pci_node);
   1024 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
   1025 	do {
   1026 		if (pci_inst == di_instance(node)) {
   1027 			*ret_node = node;
   1028 			break;
   1029 		}
   1030 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
   1031 
   1032 	if (node == DI_NODE_NIL)
   1033 		return (root_node);
   1034 
   1035 	/*
   1036 	 * found node, now search minors
   1037 	 */
   1038 	if (pci_minor == DI_MINOR_NIL)
   1039 		return (root_node);
   1040 
   1041 	pci_devt = di_minor_devt(pci_minor);
   1042 	minor = DI_MINOR_NIL;
   1043 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
   1044 		if (pci_devt == di_minor_devt(minor)) {
   1045 			*ret_minor = minor;
   1046 			break;
   1047 		}
   1048 	}
   1049 	return (root_node);
   1050 }
   1051 
   1052 
   1053 static int
   1054 pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
   1055 {
   1056 #ifdef	DEBUG
   1057 	char *fnm = "pci_cfg_creat_cb";
   1058 #endif
   1059 #define	ap_pathsz	(sizeof (ap_path))
   1060 
   1061 	char ap_path[CFGA_LOG_EXT_LEN];
   1062 	char linkbuf[MAXPATHLEN];
   1063 	char *fullpath = NULL;
   1064 	char *pathinfo = NULL;
   1065 	char *devpath = NULL;
   1066 	int rv, fd = -1;
   1067 	size_t sz;
   1068 	di_prom_handle_t