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 <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>
44
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 *);
69
70 /*
71 * Arrays of "property translation routines" to set the properties a
72 * given type of topology node should have.
73 *
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.
78 *
79 */
80
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 };
85
86 static const topo_pgroup_info_t protocol_pgroup = {
87 TOPO_PGROUP_PROTOCOL,
88 TOPO_STABILITY_PRIVATE,
89 TOPO_STABILITY_PRIVATE,
90 1
91 }; /* Request to create protocol will be ignored by libtopo */
92
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 }
150 };
151
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 }
156 };
157
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 }
165 };
166
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 },
175 /*
176 * These props need to be put at the end of table. x86pi has its
177 * own way to set them.
178 */
179 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
180 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
181 };
182
183 txprop_t ExHB_common_props[] = {
184 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
185 /*
186 * These props need to be put at the end of table. x86pi has its
187 * own way to set them.
188 */
189 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
190 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
191 };
192
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 }
197 };
198
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 },
204 /*
205 * These props need to be put at the end of table. x86pi has its
206 * own way to set them.
207 */
208 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
209 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
210 };
211
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);
219
220 /*
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.
228 */
229 static int
promprop2uint(topo_mod_t * mod,di_node_t n,const char * propnm,uint_t * val)230 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val)
231 {
232 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
233 di_prom_prop_t pp = DI_PROM_PROP_NIL;
234 uchar_t *buf;
235
236 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
237 return (-1);
238
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);
245 }
246 }
247 return (-1);
248 }
249
250 /*
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.
259 */
260 static int
hwprop2uint(di_node_t n,const char * propnm,uint_t * val)261 hwprop2uint(di_node_t n, const char *propnm, uint_t *val)
262 {
263 di_prop_t hp = DI_PROP_NIL;
264 uchar_t *buf;
265
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);
272 }
273 }
274 return (-1);
275 }
276
277 int
di_uintprop_get(topo_mod_t * mod,di_node_t n,const char * pnm,uint_t * pv)278 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv)
279 {
280 if (hwprop2uint(n, pnm, pv) < 0)
281 if (promprop2uint(mod, n, pnm, pv) < 0)
282 return (-1);
283 return (0);
284 }
285
286 int
di_bytes_get(topo_mod_t * mod,di_node_t n,const char * pnm,int * sz,uchar_t ** db)287 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz,
288 uchar_t **db)
289 {
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;
293
294 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
295 return (-1);
296
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;
303 }
304 }
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;
313 }
314 }
315 }
316
317 if (*sz < 0)
318 return (-1);
319 return (0);
320 }
321
322 /*
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.
332 */
333 static char *
dev_path_fix(topo_mod_t * mp,char * path,int devno,int fnno)334 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno)
335 {
336 char *lastslash;
337 char *newpath;
338 int need;
339
340 /*
341 * We only care about the last component of the dev path. If
342 * we don't find a slash, something is weird.
343 */
344 lastslash = strrchr(path, '/');
345 assert(lastslash != NULL);
346
347 /*
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.
351 */
352 if (strchr(lastslash, '@') != NULL)
353 return (path);
354
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++;
360
361 if ((newpath = topo_mod_alloc(mp, need)) == NULL) {
362 topo_mod_strfree(mp, path);
363 return (NULL);
364 }
365
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);
370
371 topo_mod_strfree(mp, path);
372 return (newpath);
373 }
374
375 /*
376 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path
377 * after the first element in the bus address.
378 */
379 static char *
dev_for_hostbridge(topo_mod_t * mp,char * path)380 dev_for_hostbridge(topo_mod_t *mp, char *path)
381 {
382 char *lastslash;
383 char *newpath;
384 char *comma;
385 int plen;
386
387 plen = strlen(path) + 1;
388
389 /*
390 * We only care about the last component of the dev path. If
391 * we don't find a slash, something is weird.
392 */
393 lastslash = strrchr(path, '/');
394 assert(lastslash != NULL);
395
396 /*
397 * Find the comma in the last component component@x,y, and
398 * truncate the comma and any following number.
399 */
400 comma = strchr(lastslash, ',');
401 assert(comma != NULL);
402
403 *comma = '\0';
404 if ((newpath = topo_mod_strdup(mp, path)) == NULL) {
405 topo_mod_free(mp, path, plen);
406 return (NULL);
407 }
408
409 *comma = ',';
410 topo_mod_free(mp, path, plen);
411 return (newpath);
412 }
413
414 /*ARGSUSED*/
415 static int
ASRU_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)416 ASRU_set(tnode_t *tn, did_t *pd,
417 const char *dpnm, const char *tpgrp, const char *tpnm)
418 {
419 topo_mod_t *mp;
420 nvlist_t *fmri;
421 char *dnpath, *path, *fpath, *nm;
422 int d, e, f;
423
424 /*
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.
430 */
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) {
438 /*
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()
442 */
443 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
444 di_devfs_path_free(dnpath);
445 return (topo_mod_seterrno(mp, EMOD_NOMEM));
446 }
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));
451
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);
459 }
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));
466 }
467 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
468 nvlist_free(fmri);
469 return (topo_mod_seterrno(mp, e));
470 }
471 nvlist_free(fmri);
472 return (0);
473 }
474 (void) topo_node_asru_set(tn, NULL, 0, &e);
475
476 return (0);
477 }
478
479 /*
480 * Set the FRU property to the hc fmri of this tnode
481 */
482 int
FRU_fmri_set(topo_mod_t * mp,tnode_t * tn)483 FRU_fmri_set(topo_mod_t *mp, tnode_t *tn)
484 {
485 nvlist_t *fmri;
486 int err, e;
487
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));
493 }
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);
499 }
500
501 tnode_t *
find_predecessor(tnode_t * tn,char * mod_name)502 find_predecessor(tnode_t *tn, char *mod_name)
503 {
504 tnode_t *pnode = topo_node_parent(tn);
505
506 while (pnode && (strcmp(topo_node_name(pnode), mod_name) != 0)) {
507 pnode = topo_node_parent(pnode);
508 }
509 return (pnode);
510 }
511
512 static int
use_predecessor_fru(tnode_t * tn,char * mod_name)513 use_predecessor_fru(tnode_t *tn, char *mod_name)
514 {
515 tnode_t *pnode = NULL;
516 nvlist_t *fru = NULL;
517 int err = 0;
518
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);
525
526 (void) topo_node_fru_set(tn, fru, 0, &err);
527 nvlist_free(fru);
528
529 return (0);
530 }
531
532 static int
use_predecessor_label(topo_mod_t * mod,tnode_t * tn,char * mod_name)533 use_predecessor_label(topo_mod_t *mod, tnode_t *tn, char *mod_name)
534 {
535 tnode_t *pnode = NULL;
536 int err = 0;
537 char *plabel = NULL;
538
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);
545
546 (void) topo_node_label_set(tn, plabel, &err);
547
548 topo_mod_strfree(mod, plabel);
549
550 return (0);
551 }
552
553
554 /*ARGSUSED*/
555 static int
FRU_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)556 FRU_set(tnode_t *tn, did_t *pd,
557 const char *dpnm, const char *tpgrp, const char *tpnm)
558 {
559 topo_mod_t *mp;
560 char *nm;
561 int e = 0, err = 0;
562
563 nm = topo_node_name(tn);
564 mp = did_mod(pd);
565
566 /*
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.
570 */
571 if ((strcmp(nm, PCIEX_BUS) == 0) &&
572 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {
573
574 if (use_predecessor_fru(tn, CPUBOARD) == 0)
575 return (0);
576 }
577 /*
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.
583 */
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);
588 }
589
590 /*
591 * If ioboard, set fru fmri to hc fmri
592 */
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;
599
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));
606 }
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));
612 }
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);
618
619 return (0);
620 }
621
622 /*ARGSUSED*/
623 static int
label_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)624 label_set(tnode_t *tn, did_t *pd,
625 const char *dpnm, const char *tpgrp, const char *tpnm)
626 {
627 topo_mod_t *mp;
628 nvlist_t *in, *out;
629 char *label;
630 int err;
631
632 mp = did_mod(pd);
633 /*
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.
637 */
638 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) &&
639 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {
640
641 if (use_predecessor_label(mp, tn, CPUBOARD) == 0)
642 return (0);
643 }
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));
650 }
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));
655 }
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));
663 }
664 nvlist_free(out);
665 }
666 return (0);
667 }
668
669 /*ARGSUSED*/
670 static int
EXCAP_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)671 EXCAP_set(tnode_t *tn, did_t *pd,
672 const char *dpnm, const char *tpgrp, const char *tpnm)
673 {
674 int excap = did_excap(pd);
675 int err;
676 int e = 0;
677
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;
703 }
704 if (e != 0)
705 return (topo_mod_seterrno(did_mod(pd), err));
706 return (0);
707 }
708
709 /*ARGSUSED*/
710 static int
DEVprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)711 DEVprop_set(tnode_t *tn, did_t *pd,
712 const char *dpnm, const char *tpgrp, const char *tpnm)
713 {
714 topo_mod_t *mp;
715 char *dnpath;
716 char *path, *fpath;
717 int d, f;
718 int err, e;
719
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));
724 }
725 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
726 di_devfs_path_free(dnpath);
727 return (-1);
728 }
729 di_devfs_path_free(dnpath);
730
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);
737 }
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);
746 }
747
748 /*ARGSUSED*/
749 static int
DRIVERprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)750 DRIVERprop_set(tnode_t *tn, did_t *pd,
751 const char *dpnm, const char *tpgrp, const char *tpnm)
752 {
753 char *dnm;
754 int err;
755
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));
761
762 return (0);
763 }
764
765 /*ARGSUSED*/
766 static int
MODULEprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)767 MODULEprop_set(tnode_t *tn, did_t *pd,
768 const char *dpnm, const char *tpgrp, const char *tpnm)
769 {
770 nvlist_t *mod;
771 topo_mod_t *mp;
772 char *dnm;
773 int err;
774
775 if ((dnm = di_driver_name(did_dinode(pd))) == NULL)
776 return (0);
777
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 */
781
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));
786 }
787 nvlist_free(mod);
788
789 return (0);
790 }
791
792 /*ARGSUSED*/
793 static int
maybe_di_chars_copy(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)794 maybe_di_chars_copy(tnode_t *tn, did_t *pd,
795 const char *dpnm, const char *tpgrp, const char *tpnm)
796 {
797 topo_mod_t *mp;
798 uchar_t *typbuf;
799 char *tmpbuf;
800 int sz = -1;
801 int err, e;
802
803 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
804 return (0);
805 mp = did_mod(pd);
806
807 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL)
808 return (topo_mod_seterrno(mp, EMOD_NOMEM));
809
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);
818 }
819
820 static int
uint_to_strprop(topo_mod_t * mp,uint_t v,tnode_t * tn,const char * tpgrp,const char * tpnm)821 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
822 const char *tpgrp, const char *tpnm)
823 {
824 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
825 int e;
826
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);
832 }
833
834 static int
maybe_di_uint_to_str(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)835 maybe_di_uint_to_str(tnode_t *tn, did_t *pd,
836 const char *dpnm, const char *tpgrp, const char *tpnm)
837 {
838 uint_t v;
839
840 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
841 return (0);
842
843 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
844 }
845
846 static int
uint_to_dec_strprop(topo_mod_t * mp,uint_t v,tnode_t * tn,const char * tpgrp,const char * tpnm)847 uint_to_dec_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
848 const char *tpgrp, const char *tpnm)
849 {
850 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
851 int e;
852
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);
858 }
859
860 static int
maybe_di_uint_to_dec_str(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)861 maybe_di_uint_to_dec_str(tnode_t *tn, did_t *pd,
862 const char *dpnm, const char *tpgrp, const char *tpnm)
863 {
864 uint_t v;
865
866 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
867 return (0);
868
869 return (uint_to_dec_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
870 }
871
872 static int
AADDR_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)873 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
874 const char *tpnm)
875 {
876 topo_mod_t *mp;
877 uchar_t *typbuf;
878 int sz = -1;
879 int err, e;
880
881 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
882 return (0);
883
884 mp = did_mod(pd);
885
886 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
887 /*LINTED*/
888 (uint32_t *)typbuf, sz/4, &err);
889
890 if (e != 0)
891 return (topo_mod_seterrno(mp, err));
892 return (0);
893 }
894
895 /*ARGSUSED*/
896 static int
BDF_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)897 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
898 const char *tpnm)
899 {
900 int bdf;
901 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */
902 int e;
903
904 if ((bdf = did_bdf(pd)) <= 0)
905 return (0);
906
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);
912 }
913
914 int
did_props_set(tnode_t * tn,did_t * pd,txprop_t txarray[],int txnum)915 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum)
916 {
917 topo_mod_t *mp;
918 int i, r, e;
919
920 mp = did_mod(pd);
921 for (i = 0; i < txnum; i++) {
922 /*
923 * Ensure the property group has been created.
924 */
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));
930 }
931 }
932
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);
944 }
945 topo_mod_dprintf(mp, "succeeded.\n");
946 }
947 return (0);
948 }
949