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