6659 nvlist_free(NULL) is a no-op
[illumos-gate.git] / usr / src / lib / fm / topo / modules / common / pcibus / did_props.c
blob2fcc36e9244ed38a581634f4881c637803fc0b4a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <assert.h>
28 #include <alloca.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <limits.h>
32 #include <sys/types.h>
33 #include <sys/pci.h>
34 #include <sys/pcie.h>
35 #include <sys/fm/protocol.h>
36 #include <fm/topo_mod.h>
37 #include <fm/topo_hc.h>
38 #include <libdevinfo.h>
39 #include <hostbridge.h>
40 #include <pcibus.h>
41 #include <did.h>
42 #include <did_props.h>
43 #include <fm/libtopo.h>
45 static int ASRU_set(tnode_t *, did_t *,
46 const char *, const char *, const char *);
47 static int FRU_set(tnode_t *, did_t *,
48 const char *, const char *, const char *);
49 static int DEVprop_set(tnode_t *, did_t *,
50 const char *, const char *, const char *);
51 static int DRIVERprop_set(tnode_t *, did_t *,
52 const char *, const char *, const char *);
53 static int MODULEprop_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 static int maybe_di_uint_to_dec_str(tnode_t *, did_t *,
66 const char *, const char *, const char *);
67 static int AADDR_set(tnode_t *, did_t *,
68 const char *, const char *, const char *);
71 * Arrays of "property translation routines" to set the properties a
72 * given type of topology node should have.
74 * Note that the label_set translation *MUST COME BEFORE* the FRU
75 * translation. For the near term we're setting the FRU fmri to
76 * be a legacy-hc style FMRI based on the label, so the label needs
77 * to have been set before we do the FRU translation.
81 static const topo_pgroup_info_t io_pgroup =
82 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
83 static const topo_pgroup_info_t pci_pgroup =
84 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
86 static const topo_pgroup_info_t protocol_pgroup = {
87 TOPO_PGROUP_PROTOCOL,
88 TOPO_STABILITY_PRIVATE,
89 TOPO_STABILITY_PRIVATE,
91 }; /* Request to create protocol will be ignored by libtopo */
93 txprop_t Fn_common_props[] = {
94 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
95 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
96 { DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str },
97 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
98 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
99 { "serd_io_device_nonfatal_n", &io_pgroup, "serd_io_device_nonfatal_n",
100 maybe_di_uint_to_dec_str },
101 { "serd_io_device_nonfatal_t", &io_pgroup, "serd_io_device_nonfatal_t",
102 maybe_di_chars_copy },
103 { "serd_io_device_nonfatal_btlp_n", &io_pgroup,
104 "serd_io_device_nonfatal_btlp_n", maybe_di_uint_to_dec_str },
105 { "serd_io_device_nonfatal_btlp_t", &io_pgroup,
106 "serd_io_device_nonfatal_btlp_t", maybe_di_chars_copy },
107 { "serd_io_device_nonfatal_bdllp_n", &io_pgroup,
108 "serd_io_device_nonfatal_bdllp_n", maybe_di_uint_to_dec_str },
109 { "serd_io_device_nonfatal_bdllp_t", &io_pgroup,
110 "serd_io_device_nonfatal_bdllp_t", maybe_di_chars_copy },
111 { "serd_io_device_nonfatal_re_n", &io_pgroup,
112 "serd_io_device_nonfatal_re_n", maybe_di_uint_to_dec_str },
113 { "serd_io_device_nonfatal_re_t", &io_pgroup,
114 "serd_io_device_nonfatal_re_t", maybe_di_chars_copy },
115 { "serd_io_device_nonfatal_rto_n", &io_pgroup,
116 "serd_io_device_nonfatal_rto_n", maybe_di_uint_to_dec_str },
117 { "serd_io_device_nonfatal_rto_t", &io_pgroup,
118 "serd_io_device_nonfatal_rto_t", maybe_di_chars_copy },
119 { "serd_io_device_nonfatal_rnr_n", &io_pgroup,
120 "serd_io_device_nonfatal_rnr_n", maybe_di_uint_to_dec_str },
121 { "serd_io_device_nonfatal_rnr_t", &io_pgroup,
122 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy },
123 { "serd_io_pciex_corrlink-bus_btlp_n", &io_pgroup,
124 "serd_io_pciex_corrlink-bus_btlp_n", maybe_di_uint_to_dec_str },
125 { "serd_io_pciex_corrlink-bus_btlp_t", &io_pgroup,
126 "serd_io_pciex_corrlink-bus_btlp_t", maybe_di_chars_copy },
127 { "serd_io_pciex_corrlink-bus_bdllp_n", &io_pgroup,
128 "serd_io_pciex_corrlink-bus_bdllp_n", maybe_di_uint_to_dec_str },
129 { "serd_io_pciex_corrlink-bus_bdllp_t", &io_pgroup,
130 "serd_io_pciex_corrlink-bus_bdllp_t", maybe_di_chars_copy },
131 { "serd_io_pciex_corrlink-bus_re_n", &io_pgroup,
132 "serd_io_pciex_corrlink-bus_re_n", maybe_di_uint_to_dec_str },
133 { "serd_io_pciex_corrlink-bus_re_t", &io_pgroup,
134 "serd_io_pciex_corrlink-bus_re_t", maybe_di_chars_copy },
135 { "serd_io_pciex_corrlink-bus_rto_n", &io_pgroup,
136 "serd_io_pciex_corrlink-bus_rto_n", maybe_di_uint_to_dec_str },
137 { "serd_io_pciex_corrlink-bus_rto_t", &io_pgroup,
138 "serd_io_pciex_corrlink-bus_rto_t", maybe_di_chars_copy },
139 { "serd_io_pciex_corrlink-bus_rnr_n", &io_pgroup,
140 "serd_io_pciex_corrlink-bus_rnr_n", maybe_di_uint_to_dec_str },
141 { "serd_io_pciex_corrlink-bus_rnr_t", &io_pgroup,
142 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy },
143 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
144 { DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str },
145 { DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str },
146 { DI_AADDRPROP, &pci_pgroup, TOPO_PCI_AADDR, AADDR_set },
147 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
148 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
149 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
152 txprop_t Dev_common_props[] = {
153 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
154 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
155 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
158 txprop_t Bus_common_props[] = {
159 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
160 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
161 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
162 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
163 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
164 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
167 txprop_t RC_common_props[] = {
168 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
169 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
170 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
171 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
172 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
173 { NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_set },
174 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
176 * These props need to be put at the end of table. x86pi has its
177 * own way to set them.
179 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
180 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
183 txprop_t ExHB_common_props[] = {
184 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
186 * These props need to be put at the end of table. x86pi has its
187 * own way to set them.
189 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
190 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
193 txprop_t IOB_common_props[] = {
194 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
195 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
196 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
199 txprop_t HB_common_props[] = {
200 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
201 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
202 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
203 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
205 * These props need to be put at the end of table. x86pi has its
206 * own way to set them.
208 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
209 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
212 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t);
213 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t);
214 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t);
215 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t);
216 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t);
217 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t);
218 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t);
221 * If this devinfo node came originally from OBP data, we'll have prom
222 * properties associated with the node where we can find properties of
223 * interest. We ignore anything after the the first four bytes of the
224 * property, and interpet those first four bytes as our unsigned
225 * integer. If we don't find the property or it's not large enough,
226 * 'val' will remained unchanged and we'll return -1. Otherwise 'val'
227 * gets updated with the property value and we return 0.
229 static int
230 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val)
232 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
233 di_prom_prop_t pp = DI_PROM_PROP_NIL;
234 uchar_t *buf;
236 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
237 return (-1);
239 while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) {
240 if (strcmp(di_prom_prop_name(pp), propnm) == 0) {
241 if (di_prom_prop_data(pp, &buf) < sizeof (uint_t))
242 continue;
243 bcopy(buf, val, sizeof (uint_t));
244 return (0);
247 return (-1);
251 * If this devinfo node was added by the PCI hotplug framework it
252 * doesn't have the PROM properties, but hopefully has the properties
253 * we're looking for attached directly to the devinfo node. We only
254 * care about the first four bytes of the property, which we read as
255 * our unsigned integer. The remaining bytes are ignored. If we
256 * don't find the property we're looking for, or can't get its value,
257 * 'val' remains unchanged and we return -1. Otherwise 'val' gets the
258 * property value and we return 0.
260 static int
261 hwprop2uint(di_node_t n, const char *propnm, uint_t *val)
263 di_prop_t hp = DI_PROP_NIL;
264 uchar_t *buf;
266 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) {
267 if (strcmp(di_prop_name(hp), propnm) == 0) {
268 if (di_prop_bytes(hp, &buf) < sizeof (uint_t))
269 continue;
270 bcopy(buf, val, sizeof (uint_t));
271 return (0);
274 return (-1);
278 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv)
280 if (hwprop2uint(n, pnm, pv) < 0)
281 if (promprop2uint(mod, n, pnm, pv) < 0)
282 return (-1);
283 return (0);
287 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz,
288 uchar_t **db)
290 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
291 di_prom_prop_t pp = DI_PROM_PROP_NIL;
292 di_prop_t hp = DI_PROP_NIL;
294 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
295 return (-1);
297 *sz = -1;
298 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) {
299 if (strcmp(di_prop_name(hp), pnm) == 0) {
300 if ((*sz = di_prop_bytes(hp, db)) < 0)
301 continue;
302 break;
305 if (*sz < 0) {
306 while ((pp = di_prom_prop_next(ptp, n, pp)) !=
307 DI_PROM_PROP_NIL) {
308 if (strcmp(di_prom_prop_name(pp), pnm) == 0) {
309 *sz = di_prom_prop_data(pp, db);
310 if (*sz < 0)
311 continue;
312 break;
317 if (*sz < 0)
318 return (-1);
319 return (0);
323 * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole
324 * story, leaving off the device and function number. Chances are if
325 * devfs doesn't put these on then we'll never see this device as an
326 * error detector called out in an ereport. Unfortunately, there are
327 * races and we sometimes do get ereports from devices that devfs
328 * decides aren't there. For example, the error injector card seems
329 * to bounce in and out of existence according to devfs. We tack on
330 * the missing dev and fn here so that the DEV property used to look
331 * up the topology node is correct.
333 static char *
334 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno)
336 char *lastslash;
337 char *newpath;
338 int need;
341 * We only care about the last component of the dev path. If
342 * we don't find a slash, something is weird.
344 lastslash = strrchr(path, '/');
345 assert(lastslash != NULL);
348 * If an @ sign is present in the last component, the
349 * di_devfs_path() result had the device,fn unit-address.
350 * In that case there's nothing we need do.
352 if (strchr(lastslash, '@') != NULL)
353 return (path);
355 if (fnno == 0)
356 need = snprintf(NULL, 0, "%s@%x", path, devno);
357 else
358 need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno);
359 need++;
361 if ((newpath = topo_mod_alloc(mp, need)) == NULL) {
362 topo_mod_strfree(mp, path);
363 return (NULL);
366 if (fnno == 0)
367 (void) snprintf(newpath, need, "%s@%x", path, devno);
368 else
369 (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno);
371 topo_mod_strfree(mp, path);
372 return (newpath);
376 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path
377 * after the first element in the bus address.
379 static char *
380 dev_for_hostbridge(topo_mod_t *mp, char *path)
382 char *lastslash;
383 char *newpath;
384 char *comma;
385 int plen;
387 plen = strlen(path) + 1;
390 * We only care about the last component of the dev path. If
391 * we don't find a slash, something is weird.
393 lastslash = strrchr(path, '/');
394 assert(lastslash != NULL);
397 * Find the comma in the last component component@x,y, and
398 * truncate the comma and any following number.
400 comma = strchr(lastslash, ',');
401 assert(comma != NULL);
403 *comma = '\0';
404 if ((newpath = topo_mod_strdup(mp, path)) == NULL) {
405 topo_mod_free(mp, path, plen);
406 return (NULL);
409 *comma = ',';
410 topo_mod_free(mp, path, plen);
411 return (newpath);
414 /*ARGSUSED*/
415 static int
416 ASRU_set(tnode_t *tn, did_t *pd,
417 const char *dpnm, const char *tpgrp, const char *tpnm)
419 topo_mod_t *mp;
420 nvlist_t *fmri;
421 char *dnpath, *path, *fpath, *nm;
422 int d, e, f;
425 * If this topology node represents a function of device,
426 * set the ASRU to a dev scheme FMRI based on the value of
427 * di_devfs_path(). If that path is NULL, set the ASRU to
428 * be the resource describing this topology node. If this
429 * isn't a function, inherit any ASRU from the parent.
431 mp = did_mod(pd);
432 nm = topo_node_name(tn);
433 if ((strcmp(nm, PCI_BUS) == 0 && did_gettnode(pd) &&
434 strcmp(topo_node_name(did_gettnode(pd)), HOSTBRIDGE) == 0) ||
435 strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 ||
436 strcmp(nm, PCIEX_ROOT) == 0) {
437 if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) {
439 * Dup the path, dev_path_fix() may replace it and
440 * dev_path_fix() wouldn't know to use
441 * di_devfs_path_free()
443 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
444 di_devfs_path_free(dnpath);
445 return (topo_mod_seterrno(mp, EMOD_NOMEM));
447 di_devfs_path_free(dnpath);
448 did_BDF(pd, NULL, &d, &f);
449 if ((fpath = dev_path_fix(mp, path, d, f)) == NULL)
450 return (topo_mod_seterrno(mp, EMOD_NOMEM));
452 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
453 fpath, NULL);
454 if (fmri == NULL) {
455 topo_mod_dprintf(mp,
456 "dev:///%s fmri creation failed.\n", fpath);
457 topo_mod_strfree(mp, fpath);
458 return (-1);
460 topo_mod_strfree(mp, fpath);
461 } else {
462 topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
463 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
464 TOPO_PROP_RESOURCE, &fmri, &e) < 0)
465 return (topo_mod_seterrno(mp, e));
467 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
468 nvlist_free(fmri);
469 return (topo_mod_seterrno(mp, e));
471 nvlist_free(fmri);
472 return (0);
474 (void) topo_node_asru_set(tn, NULL, 0, &e);
476 return (0);
480 * Set the FRU property to the hc fmri of this tnode
483 FRU_fmri_set(topo_mod_t *mp, tnode_t *tn)
485 nvlist_t *fmri;
486 int err, e;
488 if (topo_node_resource(tn, &fmri, &err) < 0 ||
489 fmri == NULL) {
490 topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n",
491 topo_strerror(topo_mod_errno(mp)));
492 return (topo_mod_seterrno(mp, err));
494 e = topo_node_fru_set(tn, fmri, 0, &err);
495 nvlist_free(fmri);
496 if (e < 0)
497 return (topo_mod_seterrno(mp, err));
498 return (0);
501 tnode_t *
502 find_predecessor(tnode_t *tn, char *mod_name)
504 tnode_t *pnode = topo_node_parent(tn);
506 while (pnode && (strcmp(topo_node_name(pnode), mod_name) != 0)) {
507 pnode = topo_node_parent(pnode);
509 return (pnode);
512 static int
513 use_predecessor_fru(tnode_t *tn, char *mod_name)
515 tnode_t *pnode = NULL;
516 nvlist_t *fru = NULL;
517 int err = 0;
519 if ((pnode = find_predecessor(tn, mod_name)) == NULL)
520 return (-1);
521 if ((pnode = topo_node_parent(pnode)) == NULL)
522 return (-1);
523 if (topo_node_fru(pnode, &fru, NULL, &err) != 0)
524 return (-1);
526 (void) topo_node_fru_set(tn, fru, 0, &err);
527 nvlist_free(fru);
529 return (0);
532 static int
533 use_predecessor_label(topo_mod_t *mod, tnode_t *tn, char *mod_name)
535 tnode_t *pnode = NULL;
536 int err = 0;
537 char *plabel = NULL;
539 if ((pnode = find_predecessor(tn, mod_name)) == NULL)
540 return (-1);
541 if ((pnode = topo_node_parent(pnode)) == NULL)
542 return (-1);
543 if (topo_node_label(pnode, &plabel, &err) != 0 || plabel == NULL)
544 return (-1);
546 (void) topo_node_label_set(tn, plabel, &err);
548 topo_mod_strfree(mod, plabel);
550 return (0);
554 /*ARGSUSED*/
555 static int
556 FRU_set(tnode_t *tn, did_t *pd,
557 const char *dpnm, const char *tpgrp, const char *tpnm)
559 topo_mod_t *mp;
560 char *nm;
561 int e = 0, err = 0;
563 nm = topo_node_name(tn);
564 mp = did_mod(pd);
567 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT,
568 * check for a CPUBOARD predecessor. If found, inherit its
569 * parent's FRU. Otherwise, continue with FRU set.
571 if ((strcmp(nm, PCIEX_BUS) == 0) &&
572 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {
574 if (use_predecessor_fru(tn, CPUBOARD) == 0)
575 return (0);
578 * If this topology node represents something other than an
579 * ioboard or a device that implements a slot, inherit the
580 * parent's FRU value. If there is no label, inherit our
581 * parent's FRU value. Otherwise, munge up an fmri based on
582 * the label.
584 if (strcmp(nm, IOBOARD) != 0 && strcmp(nm, PCI_DEVICE) != 0 &&
585 strcmp(nm, PCIEX_DEVICE) != 0 && strcmp(nm, PCIEX_BUS) != 0) {
586 (void) topo_node_fru_set(tn, NULL, 0, &e);
587 return (0);
591 * If ioboard, set fru fmri to hc fmri
593 if (strcmp(nm, IOBOARD) == 0) {
594 e = FRU_fmri_set(mp, tn);
595 return (e);
596 } else if (strcmp(nm, PCI_DEVICE) == 0 ||
597 strcmp(nm, PCIEX_DEVICE) == 0 || strcmp(nm, PCIEX_BUS) == 0) {
598 nvlist_t *in, *out;
600 mp = did_mod(pd);
601 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0)
602 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL));
603 if (nvlist_add_uint64(in, "nv1", (uintptr_t)pd) != 0) {
604 nvlist_free(in);
605 return (topo_mod_seterrno(mp, EMOD_NOMEM));
607 if (topo_method_invoke(tn,
608 TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_VERSION,
609 in, &out, &err) != 0) {
610 nvlist_free(in);
611 return (topo_mod_seterrno(mp, err));
613 nvlist_free(in);
614 (void) topo_node_fru_set(tn, out, 0, &err);
615 nvlist_free(out);
616 } else
617 (void) topo_node_fru_set(tn, NULL, 0, &err);
619 return (0);
622 /*ARGSUSED*/
623 static int
624 label_set(tnode_t *tn, did_t *pd,
625 const char *dpnm, const char *tpgrp, const char *tpnm)
627 topo_mod_t *mp;
628 nvlist_t *in, *out;
629 char *label;
630 int err;
632 mp = did_mod(pd);
634 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT,
635 * check for a CPUBOARD predecessor. If found, inherit its
636 * parent's Label. Otherwise, continue with label set.
638 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) &&
639 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {
641 if (use_predecessor_label(mp, tn, CPUBOARD) == 0)
642 return (0);
644 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0)
645 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL));
646 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) !=
647 0) {
648 nvlist_free(in);
649 return (topo_mod_seterrno(mp, EMOD_NOMEM));
651 if (topo_method_invoke(tn,
652 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) {
653 nvlist_free(in);
654 return (topo_mod_seterrno(mp, err));
656 nvlist_free(in);
657 if (out != NULL &&
658 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) {
659 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL,
660 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) {
661 nvlist_free(out);
662 return (topo_mod_seterrno(mp, err));
664 nvlist_free(out);
666 return (0);
669 /*ARGSUSED*/
670 static int
671 EXCAP_set(tnode_t *tn, did_t *pd,
672 const char *dpnm, const char *tpgrp, const char *tpnm)
674 int excap = did_excap(pd);
675 int err;
676 int e = 0;
678 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) {
679 case PCIE_PCIECAP_DEV_TYPE_ROOT:
680 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
681 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err);
682 break;
683 case PCIE_PCIECAP_DEV_TYPE_UP:
684 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
685 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err);
686 break;
687 case PCIE_PCIECAP_DEV_TYPE_DOWN:
688 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
689 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err);
690 break;
691 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
692 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
693 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err);
694 break;
695 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
696 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
697 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err);
698 break;
699 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
700 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
701 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err);
702 break;
704 if (e != 0)
705 return (topo_mod_seterrno(did_mod(pd), err));
706 return (0);
709 /*ARGSUSED*/
710 static int
711 DEVprop_set(tnode_t *tn, did_t *pd,
712 const char *dpnm, const char *tpgrp, const char *tpnm)
714 topo_mod_t *mp;
715 char *dnpath;
716 char *path, *fpath;
717 int d, f;
718 int err, e;
720 mp = did_mod(pd);
721 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) {
722 topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
723 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT));
725 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
726 di_devfs_path_free(dnpath);
727 return (-1);
729 di_devfs_path_free(dnpath);
731 /* The DEV path is modified for hostbridges */
732 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) {
733 fpath = dev_for_hostbridge(did_mod(pd), path);
734 } else {
735 did_BDF(pd, NULL, &d, &f);
736 fpath = dev_path_fix(mp, path, d, f);
738 if (fpath == NULL)
739 return (-1);
740 e = topo_prop_set_string(tn,
741 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err);
742 topo_mod_strfree(mp, fpath);
743 if (e != 0)
744 return (topo_mod_seterrno(mp, err));
745 return (0);
748 /*ARGSUSED*/
749 static int
750 DRIVERprop_set(tnode_t *tn, did_t *pd,
751 const char *dpnm, const char *tpgrp, const char *tpnm)
753 char *dnm;
754 int err;
756 if ((dnm = di_driver_name(did_dinode(pd))) == NULL)
757 return (0);
758 if (topo_prop_set_string(tn,
759 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0)
760 return (topo_mod_seterrno(did_mod(pd), err));
762 return (0);
765 /*ARGSUSED*/
766 static int
767 MODULEprop_set(tnode_t *tn, did_t *pd,
768 const char *dpnm, const char *tpgrp, const char *tpnm)
770 nvlist_t *mod;
771 topo_mod_t *mp;
772 char *dnm;
773 int err;
775 if ((dnm = di_driver_name(did_dinode(pd))) == NULL)
776 return (0);
778 mp = did_mod(pd);
779 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, dnm)) == NULL)
780 return (0); /* driver maybe detached, return success */
782 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, mod,
783 &err) < 0) {
784 nvlist_free(mod);
785 return (topo_mod_seterrno(mp, err));
787 nvlist_free(mod);
789 return (0);
792 /*ARGSUSED*/
793 static int
794 maybe_di_chars_copy(tnode_t *tn, did_t *pd,
795 const char *dpnm, const char *tpgrp, const char *tpnm)
797 topo_mod_t *mp;
798 uchar_t *typbuf;
799 char *tmpbuf;
800 int sz = -1;
801 int err, e;
803 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
804 return (0);
805 mp = did_mod(pd);
807 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL)
808 return (topo_mod_seterrno(mp, EMOD_NOMEM));
810 bcopy(typbuf, tmpbuf, sz);
811 tmpbuf[sz] = 0;
812 e = topo_prop_set_string(tn,
813 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err);
814 topo_mod_free(mp, tmpbuf, sz + 1);
815 if (e != 0)
816 return (topo_mod_seterrno(mp, err));
817 return (0);
820 static int
821 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
822 const char *tpgrp, const char *tpnm)
824 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
825 int e;
827 (void) snprintf(str, 21, "%x", v);
828 if (topo_prop_set_string(tn,
829 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
830 return (topo_mod_seterrno(mp, e));
831 return (0);
834 static int
835 maybe_di_uint_to_str(tnode_t *tn, did_t *pd,
836 const char *dpnm, const char *tpgrp, const char *tpnm)
838 uint_t v;
840 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
841 return (0);
843 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
846 static int
847 uint_to_dec_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
848 const char *tpgrp, const char *tpnm)
850 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
851 int e;
853 (void) snprintf(str, 21, "%d", v);
854 if (topo_prop_set_string(tn,
855 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
856 return (topo_mod_seterrno(mp, e));
857 return (0);
860 static int
861 maybe_di_uint_to_dec_str(tnode_t *tn, did_t *pd,
862 const char *dpnm, const char *tpgrp, const char *tpnm)
864 uint_t v;
866 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
867 return (0);
869 return (uint_to_dec_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
872 static int
873 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
874 const char *tpnm)
876 topo_mod_t *mp;
877 uchar_t *typbuf;
878 int sz = -1;
879 int err, e;
881 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
882 return (0);
884 mp = did_mod(pd);
886 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
887 /*LINTED*/
888 (uint32_t *)typbuf, sz/4, &err);
890 if (e != 0)
891 return (topo_mod_seterrno(mp, err));
892 return (0);
895 /*ARGSUSED*/
896 static int
897 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
898 const char *tpnm)
900 int bdf;
901 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */
902 int e;
904 if ((bdf = did_bdf(pd)) <= 0)
905 return (0);
907 (void) snprintf(str, 23, "0x%x", bdf);
908 if (topo_prop_set_string(tn,
909 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
910 return (topo_mod_seterrno(did_mod(pd), e));
911 return (0);
915 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum)
917 topo_mod_t *mp;
918 int i, r, e;
920 mp = did_mod(pd);
921 for (i = 0; i < txnum; i++) {
923 * Ensure the property group has been created.
925 if (txarray[i].tx_tpgroup != NULL) {
926 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e)
927 < 0) {
928 if (e != ETOPO_PROP_DEFD)
929 return (topo_mod_seterrno(mp, e));
933 topo_mod_dprintf(mp,
934 "Setting property %s in group %s.\n",
935 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name);
936 r = txarray[i].tx_xlate(tn, pd,
937 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name,
938 txarray[i].tx_tprop);
939 if (r != 0) {
940 topo_mod_dprintf(mp, "failed.\n");
941 topo_mod_dprintf(mp, "Error was %s.\n",
942 topo_strerror(topo_mod_errno(mp)));
943 return (-1);
945 topo_mod_dprintf(mp, "succeeded.\n");
947 return (0);