xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pcibus/did_props.c (revision 0a44ef6d9afbfe052a7e975f55ea0d2954b62a82)
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 2006 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 <assert.h>
30 #include <alloca.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <limits.h>
34 #include <sys/types.h>
35 #include <sys/pci.h>
36 #include <sys/pcie.h>
37 #include <sys/fm/protocol.h>
38 #include <fm/topo_mod.h>
39 #include <fm/topo_hc.h>
40 #include <libdevinfo.h>
41 
42 #include <hostbridge.h>
43 #include <pcibus.h>
44 #include <did.h>
45 #include <did_props.h>
46 
47 static int ASRU_set(tnode_t *, did_t *,
48     const char *, const char *, const char *);
49 static int FRU_set(tnode_t *, did_t *,
50     const char *, const char *, const char *);
51 static int DEVprop_set(tnode_t *, did_t *,
52     const char *, const char *, const char *);
53 static int DRIVERprop_set(tnode_t *, did_t *,
54     const char *, const char *, const char *);
55 static int EXCAP_set(tnode_t *, did_t *,
56     const char *, const char *, const char *);
57 static int BDF_set(tnode_t *, did_t *,
58     const char *, const char *, const char *);
59 static int label_set(tnode_t *, did_t *,
60     const char *, const char *, const char *);
61 static int maybe_di_chars_copy(tnode_t *, did_t *,
62     const char *, const char *, const char *);
63 static int maybe_di_uint_to_str(tnode_t *, did_t *,
64     const char *, const char *, const char *);
65 
66 /*
67  * Arrays of "property translation routines" to set the properties a
68  * given type of topology node should have.
69  *
70  * Note that the label_set translation *MUST COME BEFORE* the FRU
71  * translation.  For the near term we're setting the FRU fmri to
72  * be a legacy-hc style FMRI based on the label, so the label needs
73  * to have been set before we do the FRU translation.
74  *
75  */
76 
77 static const topo_pgroup_info_t io_pgroup =
78 	{ TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
79 static const topo_pgroup_info_t pci_pgroup =
80 	{ TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
81 
82 static const topo_pgroup_info_t protocol_pgroup = {
83 	TOPO_PGROUP_PROTOCOL,
84 	TOPO_STABILITY_PRIVATE,
85 	TOPO_STABILITY_PRIVATE,
86 	1
87 }; /* Request to create protocol will be ignored by libtopo */
88 
89 txprop_t Fn_common_props[] = {
90 	{ NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
91 	{ DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
92 	{ DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str },
93 	{ NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
94 	{ NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
95 	{ DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str },
96 	{ DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str },
97 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
98 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
99 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
100 };
101 
102 txprop_t Dev_common_props[] = {
103 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
104 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
105 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
106 };
107 
108 txprop_t Bus_common_props[] = {
109 	{ DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
110 	{ NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
111 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
112 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
113 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
114 };
115 
116 txprop_t RC_common_props[] = {
117 	{ NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
118 	{ DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
119 	{ NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
120 	{ NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
121 	{ NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_set },
122 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
123 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
124 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
125 };
126 
127 txprop_t ExHB_common_props[] = {
128 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
129 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
130 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
131 };
132 
133 txprop_t IOB_common_props[] = {
134 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
135 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
136 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
137 };
138 
139 txprop_t HB_common_props[] = {
140 	{ NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
141 	{ NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
142 	{ NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
143 	{ NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
144 	{ NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
145 };
146 
147 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t);
148 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t);
149 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t);
150 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t);
151 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t);
152 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t);
153 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t);
154 
155 /*
156  * If this devinfo node came originally from OBP data, we'll have prom
157  * properties associated with the node where we can find properties of
158  * interest.  We ignore anything after the the first four bytes of the
159  * property, and interpet those first four bytes as our unsigned
160  * integer.  If we don't find the property or it's not large enough,
161  * 'val' will remained unchanged and we'll return -1.  Otherwise 'val'
162  * gets updated with the property value and we return 0.
163  */
164 static int
165 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val)
166 {
167 	di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
168 	di_prom_prop_t pp = DI_PROM_PROP_NIL;
169 	uchar_t *buf;
170 
171 	if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
172 		return (-1);
173 
174 	while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) {
175 		if (strcmp(di_prom_prop_name(pp), propnm) == 0) {
176 			if (di_prom_prop_data(pp, &buf) < sizeof (uint_t))
177 				continue;
178 			bcopy(buf, val, sizeof (uint_t));
179 			return (0);
180 		}
181 	}
182 	return (-1);
183 }
184 
185 /*
186  * If this devinfo node was added by the PCI hotplug framework it
187  * doesn't have the PROM properties, but hopefully has the properties
188  * we're looking for attached directly to the devinfo node.  We only
189  * care about the first four bytes of the property, which we read as
190  * our unsigned integer.  The remaining bytes are ignored.  If we
191  * don't find the property we're looking for, or can't get its value,
192  * 'val' remains unchanged and we return -1.  Otherwise 'val' gets the
193  * property value and we return 0.
194  */
195 static int
196 hwprop2uint(di_node_t n, const char *propnm, uint_t *val)
197 {
198 	di_prop_t hp = DI_PROP_NIL;
199 	uchar_t *buf;
200 
201 	while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) {
202 		if (strcmp(di_prop_name(hp), propnm) == 0) {
203 			if (di_prop_bytes(hp, &buf) < sizeof (uint_t))
204 				continue;
205 			bcopy(buf, val, sizeof (uint_t));
206 			return (0);
207 		}
208 	}
209 	return (-1);
210 }
211 
212 int
213 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv)
214 {
215 	if (hwprop2uint(n, pnm, pv) < 0)
216 		if (promprop2uint(mod, n, pnm, pv) < 0)
217 			return (-1);
218 	return (0);
219 }
220 
221 int
222 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz,
223     uchar_t **db)
224 {
225 	di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
226 	di_prom_prop_t pp = DI_PROM_PROP_NIL;
227 	di_prop_t hp = DI_PROP_NIL;
228 
229 	if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
230 		return (-1);
231 
232 	*sz = -1;
233 	while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) {
234 		if (strcmp(di_prop_name(hp), pnm) == 0) {
235 			if ((*sz = di_prop_bytes(hp, db)) < 0)
236 				continue;
237 			break;
238 		}
239 	}
240 	if (*sz < 0) {
241 		while ((pp = di_prom_prop_next(ptp, n, pp)) !=
242 		    DI_PROM_PROP_NIL) {
243 			if (strcmp(di_prom_prop_name(pp), pnm) == 0) {
244 				*sz = di_prom_prop_data(pp, db);
245 				if (*sz < 0)
246 					continue;
247 				break;
248 			}
249 		}
250 	}
251 
252 	if (*sz < 0)
253 		return (-1);
254 	return (0);
255 }
256 
257 /*
258  * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole
259  * story, leaving off the device and function number.  Chances are if
260  * devfs doesn't put these on then we'll never see this device as an
261  * error detector called out in an ereport.  Unfortunately, there are
262  * races and we sometimes do get ereports from devices that devfs
263  * decides aren't there.  For example, the error injector card seems
264  * to bounce in and out of existence according to devfs.  We tack on
265  * the missing dev and fn here so that the DEV property used to look
266  * up the topology node is correct.
267  */
268 static char *
269 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno)
270 {
271 	char *lastslash;
272 	char *newpath;
273 	int need;
274 
275 	/*
276 	 * We only care about the last component of the dev path. If
277 	 * we don't find a slash, something is weird.
278 	 */
279 	lastslash = strrchr(path, '/');
280 	assert(lastslash != NULL);
281 
282 	/*
283 	 * If an @ sign is present in the last component, the
284 	 * di_devfs_path() result had the device,fn unit-address.
285 	 * In that case there's nothing we need do.
286 	 */
287 	if (strchr(lastslash, '@') != NULL)
288 		return (path);
289 
290 	if (fnno == 0)
291 		need = snprintf(NULL, 0, "%s@%x", path, devno);
292 	else
293 		need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno);
294 	need++;
295 
296 	if ((newpath = topo_mod_alloc(mp, need)) == NULL) {
297 		topo_mod_strfree(mp, path);
298 		return (NULL);
299 	}
300 
301 	if (fnno == 0)
302 		(void) snprintf(newpath, need, "%s@%x", path, devno);
303 	else
304 		(void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno);
305 
306 	topo_mod_strfree(mp, path);
307 	return (newpath);
308 }
309 
310 /*
311  * dev_for_hostbridge() -- For hostbridges we truncate the devfs path
312  * after the first element in the bus address.
313  */
314 static char *
315 dev_for_hostbridge(topo_mod_t *mp, char *path)
316 {
317 	char *lastslash;
318 	char *newpath;
319 	char *comma;
320 
321 	/*
322 	 * We only care about the last component of the dev path. If
323 	 * we don't find a slash, something is weird.
324 	 */
325 	lastslash = strrchr(path, '/');
326 	assert(lastslash != NULL);
327 
328 	/*
329 	 * Find the comma in the last component component@x,y, and
330 	 * truncate the comma and any following number.
331 	 */
332 	comma = strchr(lastslash, ',');
333 	assert(comma != NULL);
334 
335 	*comma = '\0';
336 	if ((newpath = topo_mod_strdup(mp, path)) == NULL)
337 		return (path);
338 	*comma = ',';
339 	topo_mod_strfree(mp, path);
340 	return (newpath);
341 }
342 
343 /*ARGSUSED*/
344 static int
345 ASRU_set(tnode_t *tn, did_t *pd,
346     const char *dpnm, const char *tpgrp, const char *tpnm)
347 {
348 	topo_mod_t *mp;
349 	nvlist_t *fmri;
350 	char *dnpath, *path, *fpath, *nm;
351 	int d, e, f;
352 
353 	/*
354 	 * If this topology node represents a function of device,
355 	 * set the ASRU to a dev scheme FMRI based on the value of
356 	 * di_devfs_path().  If that path is NULL, set the ASRU to
357 	 * be the resource describing this topology node.  If this
358 	 * isn't a function, inherit any ASRU from the parent.
359 	 */
360 	mp = did_mod(pd);
361 	nm = topo_node_name(tn);
362 	if (strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 ||
363 	    strcmp(nm, PCIEX_ROOT) == 0) {
364 		if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) {
365 			/*
366 			 * Dup the path, dev_path_fix() may replace it and
367 			 * dev_path_fix() wouldn't know to use
368 			 * di_devfs_path_free()
369 			 */
370 			if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
371 				di_devfs_path_free(dnpath);
372 				return (topo_mod_seterrno(mp, EMOD_NOMEM));
373 			}
374 			di_devfs_path_free(dnpath);
375 			did_BDF(pd, NULL, &d, &f);
376 			if ((fpath = dev_path_fix(mp, path, d, f)) == NULL)
377 				return (topo_mod_seterrno(mp, EMOD_NOMEM));
378 
379 			fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
380 			    fpath, NULL);
381 			if (fmri == NULL) {
382 				topo_mod_dprintf(mp,
383 				    "dev:///%s fmri creation failed.\n", fpath);
384 				topo_mod_strfree(mp, fpath);
385 				return (-1);
386 			}
387 			topo_mod_strfree(mp, fpath);
388 		} else {
389 			topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
390 			if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
391 			    TOPO_PROP_RESOURCE, &fmri, &e) < 0)
392 				return (topo_mod_seterrno(mp, e));
393 		}
394 		if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
395 			nvlist_free(fmri);
396 			return (topo_mod_seterrno(mp, e));
397 		}
398 		nvlist_free(fmri);
399 		return (0);
400 	}
401 	(void) topo_node_asru_set(tn, NULL, 0, &e);
402 
403 	return (0);
404 }
405 
406 /*
407  * Hopefully this hack routine goes away when fmdump can print the labels.
408  */
409 static int
410 FRU_fmri_hack(topo_mod_t *mp, tnode_t *tn, const char *label)
411 {
412 	char buf[PATH_MAX];
413 	nvlist_t *fmri;
414 	int err, e;
415 
416 
417 	(void) snprintf(buf, PATH_MAX, "hc:///component=%s", label);
418 	if (topo_mod_str2nvl(mp, buf, &fmri) < 0)
419 		return (-1);
420 
421 	e = topo_node_fru_set(tn, fmri, 0, &err);
422 	nvlist_free(fmri);
423 	if (e < 0)
424 		return (topo_mod_seterrno(mp, err));
425 	return (0);
426 }
427 
428 /*ARGSUSED*/
429 static int
430 FRU_set(tnode_t *tn, did_t *pd,
431     const char *dpnm, const char *tpgrp, const char *tpnm)
432 {
433 	topo_mod_t *mp;
434 	char *label, *nm;
435 	int e;
436 
437 	nm = topo_node_name(tn);
438 	mp = did_mod(pd);
439 
440 	/*
441 	 * If this topology node represents something other than an
442 	 * ioboard or a device that implements a slot, inherit the
443 	 * parent's FRU value.  If there is no label, inherit our
444 	 * parent's FRU value.  Otherwise, munge up an fmri based on
445 	 * the label.
446 	 */
447 	if (strcmp(nm, "ioboard") != 0 && strcmp(nm, PCI_DEVICE) != 0 &&
448 	    strcmp(nm, PCIEX_DEVICE) != 0) {
449 		(void) topo_node_fru_set(tn, NULL, 0, &e);
450 		return (0);
451 	}
452 
453 	if (topo_prop_get_string(tn,
454 	    TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, &label, &e) < 0) {
455 		if (e != ETOPO_PROP_NOENT)
456 			return (topo_mod_seterrno(mp, e));
457 		(void) topo_node_fru_set(tn, NULL, 0, &e);
458 		return (0);
459 	}
460 	e = FRU_fmri_hack(mp, tn, label);
461 	topo_mod_strfree(mp, label);
462 	return (e);
463 }
464 
465 /*ARGSUSED*/
466 static int
467 label_set(tnode_t *tn, did_t *pd,
468     const char *dpnm, const char *tpgrp, const char *tpnm)
469 {
470 	topo_mod_t *mp;
471 	nvlist_t *in, *out;
472 	char *label;
473 	int err;
474 
475 	mp = did_mod(pd);
476 	if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0)
477 		return (topo_mod_seterrno(mp, EMOD_FMRI_NVL));
478 	if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) !=
479 	    0) {
480 		nvlist_free(in);
481 		return (topo_mod_seterrno(mp, EMOD_NOMEM));
482 	}
483 	if (topo_method_invoke(tn,
484 	    TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) {
485 		nvlist_free(in);
486 		return (topo_mod_seterrno(mp, err));
487 	}
488 	nvlist_free(in);
489 	if (out != NULL &&
490 	    nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) {
491 		if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL,
492 		    TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) {
493 			nvlist_free(out);
494 			return (topo_mod_seterrno(mp, err));
495 		}
496 		nvlist_free(out);
497 	}
498 	return (0);
499 }
500 
501 /*ARGSUSED*/
502 static int
503 EXCAP_set(tnode_t *tn, did_t *pd,
504     const char *dpnm, const char *tpgrp, const char *tpnm)
505 {
506 	int excap;
507 	int err;
508 	int e = 0;
509 
510 	if ((excap = did_excap(pd)) <= 0)
511 		return (0);
512 
513 	switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) {
514 	case PCIE_PCIECAP_DEV_TYPE_ROOT:
515 		e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
516 		    TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err);
517 		break;
518 	case PCIE_PCIECAP_DEV_TYPE_UP:
519 		e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
520 		    TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err);
521 		break;
522 	case PCIE_PCIECAP_DEV_TYPE_DOWN:
523 		e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
524 		    TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err);
525 		break;
526 	case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
527 		e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
528 		    TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err);
529 		break;
530 	case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
531 		e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
532 		    TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err);
533 		break;
534 	case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
535 		e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
536 		    TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err);
537 		break;
538 	}
539 	if (e != 0)
540 		return (topo_mod_seterrno(did_mod(pd), err));
541 	return (0);
542 }
543 
544 /*ARGSUSED*/
545 static int
546 DEVprop_set(tnode_t *tn, did_t *pd,
547     const char *dpnm, const char *tpgrp, const char *tpnm)
548 {
549 	topo_mod_t *mp;
550 	char *dnpath;
551 	char *path, *fpath;
552 	int d, f;
553 	int err, e;
554 
555 	mp = did_mod(pd);
556 	if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) {
557 		topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
558 		return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT));
559 	}
560 	if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
561 		di_devfs_path_free(dnpath);
562 		return (-1);
563 	}
564 	di_devfs_path_free(dnpath);
565 
566 	/* The DEV path is modified for hostbridges */
567 	if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) {
568 		fpath = dev_for_hostbridge(did_mod(pd), path);
569 	} else {
570 		did_BDF(pd, NULL, &d, &f);
571 		fpath = dev_path_fix(mp, path, d, f);
572 	}
573 	if (fpath == NULL)
574 		return (-1);
575 	e = topo_prop_set_string(tn,
576 	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err);
577 	topo_mod_strfree(mp, fpath);
578 	if (e != 0)
579 		return (topo_mod_seterrno(mp, err));
580 	return (0);
581 }
582 
583 /*ARGSUSED*/
584 static int
585 DRIVERprop_set(tnode_t *tn, did_t *pd,
586     const char *dpnm, const char *tpgrp, const char *tpnm)
587 {
588 	char *dnm;
589 	int err;
590 
591 	if ((dnm = di_driver_name(did_dinode(pd))) == NULL)
592 		return (0);
593 	if (topo_prop_set_string(tn,
594 	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0)
595 		return (topo_mod_seterrno(did_mod(pd), err));
596 
597 	return (0);
598 }
599 
600 /*ARGSUSED*/
601 static int
602 maybe_di_chars_copy(tnode_t *tn, did_t *pd,
603     const char *dpnm, const char *tpgrp, const char *tpnm)
604 {
605 	topo_mod_t *mp;
606 	uchar_t *typbuf;
607 	char *tmpbuf;
608 	int sz = -1;
609 	int err, e;
610 
611 	if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
612 		return (0);
613 	mp = did_mod(pd);
614 	tmpbuf = topo_mod_alloc(mp, sz + 1);
615 	bcopy(typbuf, tmpbuf, sz);
616 	tmpbuf[sz] = 0;
617 	e = topo_prop_set_string(tn,
618 	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err);
619 	topo_mod_free(mp, tmpbuf, sz + 1);
620 	if (e != 0)
621 		return (topo_mod_seterrno(mp, err));
622 	return (0);
623 }
624 
625 static int
626 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
627     const char *tpgrp, const char *tpnm)
628 {
629 	char str[21]; /* sizeof (UINT64_MAX) + '\0' */
630 	int e;
631 
632 	(void) snprintf(str, 21, "%x", v);
633 	if (topo_prop_set_string(tn,
634 	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
635 		return (topo_mod_seterrno(mp, e));
636 	return (0);
637 }
638 
639 static int
640 maybe_di_uint_to_str(tnode_t *tn, did_t *pd,
641     const char *dpnm, const char *tpgrp, const char *tpnm)
642 {
643 	uint_t v;
644 
645 	if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
646 		return (0);
647 
648 	return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
649 }
650 
651 /*ARGSUSED*/
652 static int
653 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
654     const char *tpnm)
655 {
656 	int bdf;
657 	char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */
658 	int e;
659 
660 	if ((bdf = did_bdf(pd)) <= 0)
661 		return (0);
662 
663 	(void) snprintf(str, 23, "0x%x", bdf);
664 	if (topo_prop_set_string(tn,
665 	    tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
666 		return (topo_mod_seterrno(did_mod(pd), e));
667 	return (0);
668 }
669 
670 int
671 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum)
672 {
673 	topo_mod_t *mp;
674 	int i, r, e;
675 
676 	mp = did_mod(pd);
677 	for (i = 0; i < txnum; i++) {
678 		/*
679 		 * Ensure the property group has been created.
680 		 */
681 		if (txarray[i].tx_tpgroup != NULL) {
682 			if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e)
683 			    < 0) {
684 				if (e != ETOPO_PROP_DEFD)
685 					return (topo_mod_seterrno(mp, e));
686 			}
687 		}
688 
689 		topo_mod_dprintf(mp,
690 		    "Setting property %s in group %s.\n",
691 		    txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name);
692 		r = txarray[i].tx_xlate(tn, pd,
693 		    txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name,
694 		    txarray[i].tx_tprop);
695 		if (r != 0) {
696 			topo_mod_dprintf(mp, "failed.\n");
697 			topo_mod_dprintf(mp, "Error was %s.\n",
698 			    topo_strerror(topo_mod_errno(mp)));
699 			return (-1);
700 		}
701 		topo_mod_dprintf(mp, "succeeded.\n");
702 	}
703 	return (0);
704 }
705