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 2009 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 		/*
    360 		 * Check if there is any usb_mid node in the middle
    361 		 * and remove the node as if there is an extra '.'
    362 		 */
    363 		if (strstr(cp, "miscellaneous") != NULL) {
    364 			count++;
    365 		}
    366 		*cp = '\0';
    367 	}
    368 
    369 	/* Remove the usb_mid node immediately before the trailing path */
    370 	if ((cp = strrchr(physpath, '/')) != NULL && (cp != physpath)) {
    371 		if (strstr(cp, "miscellaneous") != NULL) {
    372 			*cp = '\0';
    373 		}
    374 	}
    375 
    376 	return (physpath);
    377 }
    378 
    379 
    380 /*
    381  * returns an allocted string containing the device path for <node> and
    382  * <minor>
    383  */
    384 static char *
    385 pci_cfg_devpath(di_node_t node, di_minor_t minor)
    386 {
    387 	char *path;
    388 	char *bufp;
    389 	char *minor_nm;
    390 	int buflen;
    391 
    392 	path = di_devfs_path(node);
    393 	minor_nm = di_minor_name(minor);
    394 	buflen = snprintf(NULL, 0, "%s:%s", path, minor_nm) + 1;
    395 
    396 	bufp = malloc(sizeof (char) * buflen);
    397 	if (bufp != NULL)
    398 		(void) snprintf(bufp, buflen, "%s:%s", path, minor_nm);
    399 
    400 	di_devfs_path_free(path);
    401 	return (bufp);
    402 }
    403 
    404 
    405 static int
    406 di_propall_lookup_ints(di_prom_handle_t ph, int flags,
    407     dev_t dev, di_node_t node, const char *prop_name, int **prop_data)
    408 {
    409 	int rv;
    410 
    411 	if (flags & DIPROP_PRI_PROM) {
    412 		rv = di_prom_prop_lookup_ints(ph, node, prop_name, prop_data);
    413 		if (rv < 0)
    414 			rv = di_prop_lookup_ints(dev, node, prop_name,
    415 			    prop_data);
    416 	} else {
    417 		rv = di_prop_lookup_ints(dev, node, prop_name, prop_data);
    418 		if (rv < 0)
    419 			rv = di_prom_prop_lookup_ints(ph, node, prop_name,
    420 			    prop_data);
    421 	}
    422 	return (rv);
    423 }
    424 
    425 
    426 static int
    427 di_propall_lookup_strings(di_prom_handle_t ph, int flags,
    428     dev_t dev, di_node_t node, const char *prop_name, char **prop_data)
    429 {
    430 	int rv;
    431 
    432 	if (flags & DIPROP_PRI_PROM) {
    433 		rv = di_prom_prop_lookup_strings(ph, node, prop_name,
    434 		    prop_data);
    435 		if (rv < 0)
    436 			rv = di_prop_lookup_strings(dev, node, prop_name,
    437 			    prop_data);
    438 	} else {
    439 		rv = di_prop_lookup_strings(dev, node, prop_name, prop_data);
    440 		if (rv < 0)
    441 			rv = di_prom_prop_lookup_strings(ph, node, prop_name,
    442 			    prop_data);
    443 	}
    444 	return (rv);
    445 }
    446 
    447 
    448 static di_node_t
    449 pci_cfg_chassis_node(di_node_t node, di_prom_handle_t ph)
    450 {
    451 	di_node_t curnode = node;
    452 	int *firstchas;
    453 
    454 	do {
    455 		if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, curnode,
    456 		    DI_PROP_FIRST_CHAS, &firstchas) >= 0)
    457 			return (curnode);
    458 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
    459 
    460 	return (DI_NODE_NIL);
    461 }
    462 
    463 
    464 static int
    465 di_propall_lookup_slot_names(di_prom_handle_t ph, int flags,
    466     dev_t dev, di_node_t node, di_slot_name_t **prop_data)
    467 {
    468 	int rv;
    469 
    470 	if (flags & DIPROP_PRI_PROM) {
    471 		rv = di_prom_prop_lookup_slot_names(ph, node, prop_data);
    472 		if (rv < 0)
    473 			rv = di_prop_lookup_slot_names(dev, node, prop_data);
    474 	} else {
    475 		rv = di_prop_lookup_slot_names(dev, node, prop_data);
    476 		if (rv < 0)
    477 			rv = di_prom_prop_lookup_slot_names(ph, node,
    478 			    prop_data);
    479 	}
    480 	return (rv);
    481 }
    482 
    483 /*
    484  * returns an allocated string containing the slot name for the slot with
    485  * device number <pci_dev> on bus <node>
    486  */
    487 static char *
    488 pci_cfg_slotname(di_node_t node, di_prom_handle_t ph, minor_t pci_dev)
    489 {
    490 #ifdef	DEBUG
    491 	char *fnm = "pci_cfg_slotname";
    492 #endif
    493 	int i, count;
    494 	char *name = NULL;
    495 	di_slot_name_t *slot_names = NULL;
    496 
    497 	count = di_propall_lookup_slot_names(ph, 0, DDI_DEV_T_ANY, node,
    498 	    &slot_names);
    499 	if (count < 0)
    500 		return (NULL);
    501 
    502 	for (i = 0; i < count; i++) {
    503 		if (slot_names[i].num == (int)pci_dev) {
    504 			name = strdup(slot_names[i].name);
    505 			break;
    506 		}
    507 	}
    508 #ifdef	DEBUG
    509 	if (name == NULL)
    510 		dprint(("%s: slot w/ pci_dev %d not found in %s for %s%d\n",
    511 		    fnm, (int)pci_dev, DI_PROP_SLOT_NAMES, DRVINST(node)));
    512 #endif
    513 	if (count > 0)
    514 		di_slot_names_free(count, slot_names);
    515 	return (name);
    516 }
    517 
    518 
    519 /*
    520  * returns non-zero if we can return a valid attachment point name for <node>,
    521  * for its slot identified by child pci device number <pci_dev>, through <buf>
    522  *
    523  * prioritized naming scheme:
    524  *	1) <DI_PROP_SLOT_NAMES property>    (see pci_cfg_slotname())
    525  *	2) <device-type><DI_PROP_PHYS_SLOT property>
    526  *	3) <drv name><drv inst>.<device-type><pci_dev>
    527  *
    528  * where <device-type> is derived from the DI_PROP_DEV_TYPE property:
    529  *	if its value is "pciex" then <device-type> is "pcie"
    530  *	else the raw value is used
    531  *
    532  * if <flags> contains APNODE_DEFNAME, then scheme (3) is used
    533  */
    534 static int
    535 pci_cfg_ap_node(minor_t pci_dev, di_node_t node, di_prom_handle_t ph,
    536     char *buf, int bufsz, int flags)
    537 {
    538 	int *nump;
    539 	int rv;
    540 	char *str, *devtype;
    541 
    542 	rv = di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, node,
    543 	    DI_PROP_DEV_TYPE, &devtype);
    544 	if (rv < 1)
    545 		return (0);
    546 
    547 	if (strcmp(devtype, PROPVAL_PCIEX) == 0)
    548 		devtype = DEVTYPE_PCIE;
    549 
    550 	if (flags & APNODE_DEFNAME)
    551 		goto DEF;
    552 
    553 	str = pci_cfg_slotname(node, ph, pci_dev);
    554 	if (str != NULL) {
    555 		(void) strlcpy(buf, str, bufsz);
    556 		free(str);
    557 		return (1);
    558 	}
    559 
    560 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node,
    561 	    DI_PROP_PHYS_SLOT, &nump) > 0) {
    562 		if (*nump > 0) {
    563 			(void) snprintf(buf, bufsz, "%s%d", devtype, *nump);
    564 			return (1);
    565 		}
    566 	}
    567 DEF:
    568 	(void) snprintf(buf, bufsz, "%s%d.%s%d",
    569 	    di_driver_name(node), di_instance(node), devtype, pci_dev);
    570 
    571 	return (1);
    572 }
    573 
    574 
    575 /*
    576  * returns non-zero if we can return a valid expansion chassis name for <node>
    577  * through <buf>
    578  *
    579  * prioritized naming scheme:
    580  *	1) <IOB_PRE string><DI_PROP_SERID property: sun specific portion>
    581  *	2) <IOB_PRE string><full DI_PROP_SERID property in hex>
    582  *	3) <IOB_PRE string>
    583  *
    584  * DI_PROP_SERID encoding <64-bit int: msb ... lsb>:
    585  * <24 bits: IEEE company id><40 bits: serial number>
    586  *
    587  * sun encoding of 40 bit serial number:
    588  * first byte = device type indicator
    589  * next 4 bytes = 4 ascii characters
    590  *
    591  * In the unlikely event that serial id contains non-printable characters
    592  * the full 64 bit raw hex string will be used for the attachment point.
    593  */
    594 /*ARGSUSED*/
    595 static int
    596 pci_cfg_iob_name(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
    597     char *buf, int bufsz)
    598 {
    599 	int64_t *seridp;
    600 	uint64_t serid;
    601 	char *idstr;
    602 
    603 	if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, DI_PROP_SERID,
    604 	    &seridp) < 1) {
    605 		(void) strlcpy(buf, IOB_PRE, bufsz);
    606 		return (1);
    607 	}
    608 
    609 	serid = (uint64_t)*seridp;
    610 
    611 	if ((serid >> 40) != (uint64_t)IEEE_SUN_ID ||
    612 	    !serid_printable(&serid)) {
    613 		(void) snprintf(buf, bufsz, "%s%llx", IOB_PRE, serid);
    614 		return (1);
    615 	}
    616 
    617 	/*
    618 	 * the serial id is constructed from lower 40 bits of the serialid
    619 	 * property and is represented by 5 ascii characters. The first
    620 	 * character indicates if the IO Box is PCIe or PCI-X.
    621 	 */
    622 
    623 	serid <<= 24;
    624 	idstr = (char *)&serid;
    625 	idstr[sizeof (serid) -1] = '\0';
    626 
    627 	(void) snprintf(buf, bufsz, "%s%s", IOB_PRE, idstr);
    628 
    629 	return (1);
    630 }
    631 
    632 
    633 /*
    634  * returns the pci device number for <node> if found, else returns PCIDEV_NIL
    635  */
    636 static minor_t
    637 pci_cfg_pcidev(di_node_t node, di_prom_handle_t ph)
    638 {
    639 	int rv;
    640 	int *regp;
    641 
    642 	rv = di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_REG,
    643 	    &regp);
    644 
    645 	if (rv < 1) {
    646 		dprint(("pci_cfg_pcidev: property %s not found "
    647 		    "for %s%d\n", DI_PROP_REG, DRVINST(node)));
    648 		return (PCIDEV_NIL);
    649 	}
    650 
    651 	return (REG_PCIDEV(regp));
    652 }
    653 
    654 
    655 /*
    656  * returns non-zero when it can successfully return an attachment point
    657  * through <ap_path> whose length is less than <ap_pathsz>; returns the full
    658  * path of the AP through <pathret> which may be larger than <ap_pathsz>.
    659  * Callers need to free <pathret>.  If it cannot return the full path through
    660  * <pathret> it will be set to NULL
    661  *
    662  * The ap path reflects a subset of the device path from an onboard host slot
    663  * up to <node>.  We traverse up the device tree starting from <node>, naming
    664  * each component using pci_cfg_ap_node().  If we detect that a certain
    665  * segment is contained within an expansion chassis, then we skip any bus
    666  * nodes in between our current node and the topmost node of the chassis,
    667  * which is identified by the DI_PROP_FIRST_CHAS property, and prepend the name
    668  * of the expansion chassis as given by pci_cfg_iob_name()
    669  *
    670  * This scheme is always used for <pathret>.  If however, the size of
    671  * <pathret> is greater than <ap_pathsz> then only the default name as given
    672  * by pci_cfg_ap_node() for <node> will be used
    673  */
    674 static int
    675 pci_cfg_ap_path(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
    676     char *ap_path, int ap_pathsz, char **pathret)
    677 {
    678 #ifdef	DEBUG
    679 	char *fnm = "pci_cfg_ap_path";
    680 #endif
    681 #define	seplen		(sizeof (AP_PATH_SEP) - 1)
    682 #define	iob_pre_len	(sizeof (IOB_PRE) - 1)
    683 #define	ap_path_iob_sep_len	(sizeof (AP_PATH_IOB_SEP) - 1)
    684 
    685 	char *bufptr;
    686 	char buf[MAXPATHLEN];
    687 	char pathbuf[MAXPATHLEN];
    688 	int bufsz;
    689 	char *pathptr;
    690 	char *pathend = NULL;
    691 	int len;
    692 	int rv = 0;
    693 	int chasflag = 0;
    694 	di_node_t curnode = node;
    695 	di_node_t chasnode = DI_NODE_NIL;
    696 	minor_t pci_dev;
    697 
    698 	buf[0] = '\0';
    699 	pathbuf[0] = '\0';
    700 	pathptr = &pathbuf[sizeof (pathbuf) - 1];
    701 	*pathptr = '\0';
    702 
    703 	/*
    704 	 * as we traverse up the device tree, we prepend components of our
    705 	 * path inside pathbuf, using pathptr and decrementing
    706 	 */
    707 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
    708 	do {
    709 		bufptr = buf;
    710 		bufsz = sizeof (buf);
    711 
    712 		chasnode = pci_cfg_chassis_node(curnode, ph);
    713 		if (chasnode != DI_NODE_NIL) {
    714 			rv = pci_cfg_iob_name(minor, chasnode, ph,
    715 			    bufptr, bufsz);
    716 			if (rv == 0) {
    717 				dprint(("%s: cannot create iob name "
    718 				    "for %s%d\n", fnm, DRVINST(node)));
    719 				*pathptr = '\0';
    720 				goto OUT;
    721 			}
    722 
    723 			(void) strncat(bufptr, AP_PATH_IOB_SEP, bufsz);
    724 			len = strlen(bufptr);
    725 			bufptr += len;
    726 			bufsz -= len - 1;
    727 
    728 			/* set chasflag when the leaf node is within an iob */
    729 			if ((curnode == node) != NULL)
    730 				chasflag = 1;
    731 		}
    732 		rv = pci_cfg_ap_node(pci_dev, curnode, ph, bufptr, bufsz, 0);
    733 		if (rv == 0) {
    734 			dprint(("%s: cannot create ap node name "
    735 			    "for %s%d\n", fnm, DRVINST(node)));
    736 			*pathptr = '\0';
    737 			goto OUT;
    738 		}
    739 
    740 		/*
    741 		 * if we can't fit the entire path in our pathbuf, then use
    742 		 * the default short name and nullify pathptr; also, since
    743 		 * we prepend in the buffer, we must avoid adding a null char
    744 		 */
    745 		if (curnode != node) {
    746 			pathptr -= seplen;
    747 			if (pathptr < pathbuf) {
    748 				pathptr = pathbuf;
    749 				*pathptr = '\0';
    750 				goto DEF;
    751 			}
    752 			(void) memcpy(pathptr, AP_PATH_SEP, seplen);
    753 		}
    754 		len = strlen(buf);
    755 		pathptr -= len;
    756 		if (pathptr < pathbuf) {
    757 			pathptr = pathbuf;
    758 			*pathptr = '\0';
    759 			goto DEF;
    760 		}
    761 		(void) memcpy(pathptr, buf, len);
    762 
    763 		/* remember the leaf component */
    764 		if (curnode == node)
    765 			pathend = pathptr;
    766 
    767 		/*
    768 		 * go no further than the hosts' onboard slots
    769 		 */
    770 		if (chasnode == DI_NODE_NIL)
    771 			break;
    772 		curnode = chasnode;
    773 
    774 		/*
    775 		 * the pci device number of the current node is used to
    776 		 * identify which slot of the parent's bus (next iteration)
    777 		 * the current node is on
    778 		 */
    779 		pci_dev = pci_cfg_pcidev(curnode, ph);
    780 		if (pci_dev == PCIDEV_NIL) {
    781 			dprint(("%s: cannot obtain pci device number "
    782 			    "for %s%d\n", fnm, DRVINST(node)));
    783 			*pathptr = '\0';
    784 			goto OUT;
    785 		}
    786 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
    787 
    788 	pathbuf[sizeof (pathbuf) - 1] = '\0';
    789 	if (strlen(pathptr) < ap_pathsz) {
    790 		(void) strlcpy(ap_path, pathptr, ap_pathsz);
    791 		rv = 1;
    792 		goto OUT;
    793 	}
    794 
    795 DEF:
    796 	/*
    797 	 * when our name won't fit <ap_pathsz> we use the endpoint/leaf
    798 	 * <node>'s name ONLY IF it has a serialid# which will make the apid
    799 	 * globally unique
    800 	 */
    801 	if (chasflag && pathend != NULL) {
    802 		if ((strncmp(pathend + iob_pre_len, AP_PATH_IOB_SEP,
    803 		    ap_path_iob_sep_len) != 0) &&
    804 		    (strlen(pathend) < ap_pathsz)) {
    805 			(void) strlcpy(ap_path, pathend, ap_pathsz);
    806 			rv = 1;
    807 			goto OUT;
    808 		}
    809 	}
    810 
    811 	/*
    812 	 * if our name still won't fit <ap_pathsz>, then use the leaf <node>'s
    813 	 * default name
    814 	 */
    815 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
    816 	rv = pci_cfg_ap_node(pci_dev, node, ph, buf, bufsz, APNODE_DEFNAME);
    817 	if (rv == 0) {
    818 		dprint(("%s: cannot create default ap node name for %s%d\n",
    819 		    fnm, DRVINST(node)));
    820 		*pathptr = '\0';
    821 		goto OUT;
    822 	}
    823 	if (strlen(buf) < ap_pathsz) {
    824 		(void) strlcpy(ap_path, buf, ap_pathsz);
    825 		rv = 1;
    826 		goto OUT;
    827 	}
    828 
    829 	/*
    830 	 * in this case, cfgadm goes through an expensive process to generate
    831 	 * a purely dynamic logical apid: the framework will look through
    832 	 * the device tree for attachment point minor nodes and will invoke
    833 	 * each plugin responsible for that attachment point class, and if
    834 	 * the plugin returns a logical apid that matches the queried apid
    835 	 * or matches the default apid generated by the cfgadm framework for
    836 	 * that driver/class (occurs when plugin returns an empty logical apid)
    837 	 * then that is what it will use
    838 	 *
    839 	 * it is doubly expensive because the cfgadm pci plugin itself will
    840 	 * also search the entire device tree in the absence of a link
    841 	 */
    842 	rv = 0;
    843 	dprint(("%s: cannot create apid for %s%d within length of %d\n",
    844 	    fnm, DRVINST(node), ap_pathsz));
    845 
    846 OUT:
    847 	ap_path[ap_pathsz - 1] = '\0';
    848 	*pathret = (*pathptr == '\0') ? NULL : strdup(pathptr);
    849 	return (rv);
    850 
    851 #undef	seplen
    852 #undef	iob_pre_len
    853 #undef	ap_path_iob_sep_len
    854 }
    855 
    856 
    857 /*
    858  * the DI_PROP_AP_NAMES property contains the first integer section of the
    859  * ieee1275 "slot-names" property and functions as a bitmask; see comment for
    860  * pci_cfg_slotname()
    861  *
    862  * we use the name of the attachment point minor node if its pci device
    863  * number (encoded in the minor number) is allowed by DI_PROP_AP_NAMES
    864  *
    865  * returns non-zero if we return a valid attachment point through <path>
    866  */
    867 static int
    868 pci_cfg_ap_legacy(di_minor_t minor, di_node_t node, di_prom_handle_t ph,
    869     char *ap_path, int ap_pathsz)
    870 {
    871 	minor_t pci_dev;
    872 	int *anp;
    873 
    874 	if (di_propall_lookup_ints(ph, 0, DDI_DEV_T_ANY, node, DI_PROP_AP_NAMES,
    875 	    &anp) < 1)
    876 		return (0);
    877 
    878 	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(di_minor_devt(minor));
    879 	if ((*anp & (1 << pci_dev)) == 0)
    880 		return (0);
    881 
    882 	(void) strlcpy(ap_path, di_minor_name(minor), ap_pathsz);
    883 	return (1);
    884 }
    885 
    886 
    887 /*
    888  * determine if <node> qualifies for a path style apid
    889  */
    890 static int
    891 pci_cfg_is_ap_path(di_node_t node, di_prom_handle_t ph)
    892 {
    893 	char *devtype;
    894 	di_node_t curnode = node;
    895 
    896 	do {
    897 		if (di_propall_lookup_strings(ph, 0, DDI_DEV_T_ANY, curnode,
    898 		    DI_PROP_DEV_TYPE, &devtype) > 0)
    899 			if (strcmp(devtype, PROPVAL_PCIEX) == 0)
    900 				return (1);
    901 	} while ((curnode = di_parent_node(curnode)) != DI_NODE_NIL);
    902 
    903 	return (0);
    904 }
    905 
    906 
    907 /*
    908  * takes a full path as returned by <pathret> from pci_cfg_ap_path() and
    909  * returns an allocated string intendend to be stored in a devlink info (dli)
    910  * file
    911  *
    912  * data format: "Location: <transformed path>"
    913  * where <transformed path> is <path> with occurrances of AP_PATH_SEP
    914  * replaced by "/"
    915  */
    916 static char *
    917 pci_cfg_info_data(char *path)
    918 {
    919 #define	head	"Location: "
    920 #define	headlen	(sizeof (head) - 1)
    921 #define	seplen	(sizeof (AP_PATH_SEP) - 1)
    922 
    923 	char *sep, *prev, *np;
    924 	char *newpath;
    925 	int pathlen = strlen(path);
    926 	int len;
    927 
    928 	newpath = malloc(sizeof (char) * (headlen + pathlen + 1));
    929 	np = newpath;
    930 	(void) strcpy(np, head);
    931 	np += headlen;
    932 
    933 	prev = path;
    934 	while ((sep = strstr(prev, AP_PATH_SEP)) != NULL) {
    935 		len = sep - prev;
    936 		(void) memcpy(np, prev, len);
    937 		np += len;
    938 		*np++ = '/';
    939 		prev = sep + seplen;
    940 	}
    941 	(void) strcpy(np, prev);
    942 	return (newpath);
    943 
    944 #undef	head
    945 #undef	headlen
    946 #undef	seplen
    947 }
    948 
    949 
    950 static void
    951 pci_cfg_rm_link(char *file)
    952 {
    953 	char *dlipath;
    954 
    955 	dlipath = di_dli_name(file);
    956 	(void) unlink(dlipath);
    957 
    958 	devfsadm_rm_all(file);
    959 	free(dlipath);
    960 }
    961 
    962 /*
    963  * removes all registered devlinks to physical path <physpath> except for
    964  * the devlink <valid> if not NULL;
    965  * <physpath> must include the minor node
    966  */
    967 static void
    968 pci_cfg_rm_invalid_links(char *physpath, char *valid)
    969 {
    970 	char **dnp;
    971 	char *cp, *vcp;
    972 	int i, dnlen;
    973 
    974 	dnp = devfsadm_lookup_dev_names(physpath, NULL, &dnlen);
    975 	if (dnp == NULL)
    976 		return;
    977 
    978 	if (valid != NULL) {
    979 		if (strncmp(valid, DEV "/", DEV_LEN + 1) == 0)
    980 			vcp = valid + DEV_LEN + 1;
    981 		else
    982 			vcp = valid;
    983 	}
    984 
    985 	for (i = 0; i < dnlen; i++) {
    986 		if (strncmp(dnp[i], DEV "/", DEV_LEN + 1) == 0)
    987 			cp = dnp[i] + DEV_LEN + 1;
    988 		else
    989 			cp = dnp[i];
    990 
    991 		if (valid != NULL) {
    992 			if (strcmp(vcp, cp) == 0)
    993 				continue;
    994 		}
    995 		pci_cfg_rm_link(cp);
    996 	}
    997 	devfsadm_free_dev_names(dnp, dnlen);
    998 }
    999 
   1000 
   1001 /*
   1002  * takes a complete devinfo snapshot and returns the root node;
   1003  * callers must do a di_fini() on the returned node;
   1004  * if the snapshot failed, DI_NODE_NIL is returned instead
   1005  *
   1006  * if <pci_node> is not DI_NODE_NIL, it will search for the same devinfo node
   1007  * in the new snapshot and return it through <ret_node> if it is found,
   1008  * else DI_NODE_NIL is returned instead
   1009  *
   1010  * in addition, if <pci_minor> is not DI_MINOR_NIL, it will also return
   1011  * the matching minor in the new snapshot through <ret_minor> if it is found,
   1012  * else DI_MINOR_NIL is returned instead
   1013  */
   1014 static di_node_t
   1015 pci_cfg_snapshot(di_node_t pci_node, di_minor_t pci_minor,
   1016     di_node_t *ret_node, di_minor_t *ret_minor)
   1017 {
   1018 	di_node_t root_node;
   1019 	di_node_t node;
   1020 	di_minor_t minor;
   1021 	int pci_inst;
   1022 	dev_t pci_devt;
   1023 
   1024 	*ret_node = DI_NODE_NIL;
   1025 	*ret_minor = DI_MINOR_NIL;
   1026 
   1027 	root_node = di_init("/", DINFOCPYALL);
   1028 	if (root_node == DI_NODE_NIL)
   1029 		return (DI_NODE_NIL);
   1030 
   1031 	/*
   1032 	 * narrow down search by driver, then instance, then minor
   1033 	 */
   1034 	if (pci_node == DI_NODE_NIL)
   1035 		return (root_node);
   1036 
   1037 	pci_inst = di_instance(pci_node);
   1038 	node = di_drv_first_node(di_driver_name(pci_node), root_node);
   1039 	do {
   1040 		if (pci_inst == di_instance(node)) {
   1041 			*ret_node = node;
   1042 			break;
   1043 		}
   1044 	} while ((node = di_drv_next_node(node)) != DI_NODE_NIL);
   1045 
   1046 	if (node == DI_NODE_NIL)
   1047 		return (root_node);
   1048 
   1049 	/*
   1050 	 * found node, now search minors
   1051 	 */
   1052 	if (pci_minor == DI_MINOR_NIL)
   1053 		return (root_node);
   1054 
   1055 	pci_devt = di_minor_devt(pci_minor);
   1056 	minor = DI_MINOR_NIL;
   1057 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
   1058 		if (pci_devt == di_minor_devt(minor)) {
   1059 			*ret_minor = minor;
   1060 			break;
   1061 		}
   1062 	}
   1063 	return (root_node);
   1064 }
   1065 
   1066 
   1067 static int
   1068 pci_cfg_creat_cb(di_minor_t pci_minor, di_node_t pci_node)
   1069 {
   1070 #ifdef	DEBUG
   1071 	char *fnm = "pci_cfg_creat_cb";
   1072 #endif
   1073 #define	ap_pathsz	(sizeof (ap_path))
   1074 
   1075 	char ap_path[CFGA_LOG_EXT_LEN];
   1076 	char linkbuf[MAXPATHLEN];
   1077 	char *fullpath = NULL;
   1078 	char *pathinfo = NULL;
   1079 	char *devpath = NULL;
   1080 	int rv, fd = -1;
   1081 	size_t sz;
   1082 	di_prom_handle_t ph;
   1083 	di_node_t node;
   1084 	di_node_t root_node = DI_NODE_NIL;
   1085 	di_minor_t minor;
   1086 
   1087 	ph = di_prom_init();
   1088 	if (ph == DI_PROM_HANDLE_NIL) {
   1089 		dprint(("%s: di_prom_init() failed for %s%d\n",
   1090 		    fnm, DRVINST(pci_node)));
   1091 		goto OUT;
   1092 	}
   1093 
   1094 	/*
   1095 	 * Since incoming nodes from hotplug events are from snapshots that
   1096 	 * do NOT contain parent/ancestor data, we must retake our own
   1097 	 * snapshot and search for the target node
   1098 	 */
   1099 	root_node = pci_cfg_snapshot(pci_node, pci_minor, &node, &minor);
   1100 	if (root_node == DI_NODE_NIL || node == DI_NODE_NIL ||
   1101 	    minor == DI_MINOR_NIL) {
   1102 		dprint(("%s: devinfo snapshot or search failed for %s%d\n",
   1103 		    fnm, DRVINST(pci_node)));
   1104 		goto OUT;
   1105 	}
   1106 
   1107 	if (pci_cfg_is_ap_path(node, ph)) {
   1108 		rv = pci_cfg_ap_path(minor, node, ph, ap_path, ap_pathsz,
   1109 		    &fullpath);
   1110 		if (rv == 0)
   1111 			goto OUT;
   1112 
   1113 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
   1114 		    CFG_DIRNAME, ap_path);
   1115 
   1116 		/*
   1117 		 * We must remove existing links because we may have invalid
   1118 		 * apids that are valid links.  Since these are not dangling,
   1119 		 * devfsadm will not invoke the remove callback on them.
   1120 		 *
   1121 		 * What are "invalid apids with valid links"?  Consider swapping
   1122 		 * an attachment point bus with another while the system is
   1123 		 * down, on the same device path bound to the same drivers
   1124 		 * but with the new AP bus having different properties
   1125 		 * (e.g. serialid#).  If the previous apid is not removed,
   1126 		 * there will now be two different links pointing to the same
   1127 		 * attachment point, but only one reflects the correct
   1128 		 * logical apid
   1129 		 */
   1130 		devpath = pci_cfg_devpath(node, minor);
   1131 		if (devpath == NULL)
   1132 			goto OUT;
   1133 		pci_cfg_rm_invalid_links(devpath, linkbuf);
   1134 		free(devpath);
   1135 
   1136 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
   1137 
   1138 		/*
   1139 		 * we store the full logical path of the attachment point for
   1140 		 * cfgadm to display in its info field which is useful when
   1141 		 * the full logical path exceeds the size limit for logical
   1142 		 * apids (CFGA_LOG_EXT_LEN)
   1143 		 *
   1144 		 * for the cfgadm pci plugin to do the same would be expensive
   1145 		 * (i.e. devinfo snapshot + top down exhaustive minor search +
   1146 		 * equivalent of pci_cfg_ap_path() on every invocation)
   1147 		 *
   1148 		 * note that if we do not create a link (pci_cfg_ap_path() is
   1149 		 * not successful), that is what cfgadm will do anyways to
   1150 		 * create a purely dynamic apid
   1151 		 */
   1152 		pathinfo = pci_cfg_info_data(fullpath);
   1153 		fd = di_dli_openw(linkbuf);
   1154 		if (fd < 0)
   1155 			goto OUT;
   1156 
   1157 		sz = strlen(pathinfo) + 1;
   1158 		rv = write(fd, pathinfo, sz);
   1159 		if (rv < sz) {
   1160 			dprint(("%s: could not write full pathinfo to dli "
   1161 			    "file for %s%d\n", fnm, DRVINST(node)));
   1162 			goto OUT;
   1163 		}
   1164 		di_dli_close(fd);
   1165 	} else {
   1166 		rv = pci_cfg_ap_legacy(minor, node, ph, ap_path,
   1167 		    ap_pathsz);
   1168 		if (rv == 0)
   1169 			goto OUT;
   1170 
   1171 		(void) snprintf(linkbuf, sizeof (linkbuf), "%s/%s",
   1172 		    CFG_DIRNAME, ap_path);
   1173 		(void) devfsadm_mklink(linkbuf, node, minor, 0);
   1174 	}
   1175 
   1176 OUT:
   1177 	if (fd >= 0)
   1178 		di_dli_close(fd);
   1179 	if (fullpath != NULL)
   1180 		free(fullpath);
   1181 	if (pathinfo != NULL)
   1182 		free(pathinfo);
   1183 	if (ph != DI_PROM_HANDLE_NIL)
   1184 		di_prom_fini(ph);
   1185 	if (root_node != DI_NODE_NIL)
   1186 		di_fini(root_node);
   1187 	return (DEVFSADM_CONTINUE);
   1188 
   1189 #undef	ap_pathsz
   1190 }
   1191 
   1192 
   1193 static void
   1194 pci_cfg_rm_all(char *file)
   1195 {
   1196 	pci_cfg_rm_link(file);
   1197 }
   1198 
   1199 
   1200 /*
   1201  * ib_cfg_creat_cb() creates two types of links
   1202  * One for the fabric as /dev/cfg/ib
   1203  * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID>
   1204  */
   1205 static int
   1206 ib_cfg_creat_cb(di_minor_t minor, di_node_t node)
   1207 {
   1208 	char	*cp;
   1209 	char	path[PATH_MAX + 1];
   1210 
   1211 	if ((cp = di_devfs_path(node)) == NULL) {
   1212 		return (DEVFSADM_CONTINUE);
   1213 	}
   1214 
   1215 	(void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor));
   1216 	di_devfs_path_free(cp);
   1217 
   1218 	/* create fabric or hca:GUID and the symlink */
   1219 	if (strstr(path, "ib:fabric") != NULL) {
   1220 		(void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME);
   1221 	} else {
   1222 		(void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME,
   1223 		    di_minor_name(minor));
   1224 	}
   1225 
   1226 	(void) devfsadm_mklink(path, node, minor, 0);
   1227 	return (DEVFSADM_CONTINUE);
   1228 }
   1229 
   1230 /*
   1231  * This function verifies if the serial id is printable.
   1232  */
   1233 
   1234 static int
   1235 serid_printable(uint64_t *seridp)
   1236 {
   1237 
   1238 	char *ptr;
   1239 	int i = 0;
   1240 
   1241 	for (ptr = (char *)seridp+3; i < 5; ptr++, i++)
   1242 		if (*ptr < 0x21 || *ptr >= 0x7f)
   1243 			return (0);
   1244 
   1245 	return (1);
   1246 
   1247 }
   1248