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 * Copyright 2019 Joyent, Inc.
28 */
29
30 #include <assert.h>
31 #include <alloca.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <limits.h>
35 #include <sys/types.h>
36 #include <sys/pci.h>
37 #include <sys/pcie.h>
38 #include <sys/fm/protocol.h>
39 #include <fm/topo_mod.h>
40 #include <fm/topo_hc.h>
41 #include <libdevinfo.h>
42 #include <hostbridge.h>
43 #include <pcibus.h>
44 #include <did.h>
45 #include <did_props.h>
46 #include <fm/libtopo.h>
47 #include <pcidb.h>
48
49 static int ASRU_set(tnode_t *, did_t *,
50 const char *, const char *, const char *);
51 static int FRU_set(tnode_t *, did_t *,
52 const char *, const char *, const char *);
53 static int DEVprop_set(tnode_t *, did_t *,
54 const char *, const char *, const char *);
55 static int DRIVERprop_set(tnode_t *, did_t *,
56 const char *, const char *, const char *);
57 static int INSTprop_set(tnode_t *, did_t *,
58 const char *, const char *, const char *);
59 static int MODULEprop_set(tnode_t *, did_t *,
60 const char *, const char *, const char *);
61 static int EXCAP_set(tnode_t *, did_t *,
62 const char *, const char *, const char *);
63 static int BDF_set(tnode_t *, did_t *,
64 const char *, const char *, const char *);
65 static int label_set(tnode_t *, did_t *,
66 const char *, const char *, const char *);
67 static int maybe_di_chars_copy(tnode_t *, did_t *,
68 const char *, const char *, const char *);
69 static int maybe_di_uint_to_str(tnode_t *, did_t *,
70 const char *, const char *, const char *);
71 static int maybe_di_uint_to_dec_str(tnode_t *, did_t *,
72 const char *, const char *, const char *);
73 static int AADDR_set(tnode_t *, did_t *,
74 const char *, const char *, const char *);
75 static int maybe_pcidb_set(tnode_t *, did_t *,
76 const char *, const char *, const char *);
77 static int maybe_di_int_to_uint32(tnode_t *, did_t *,
78 const char *, const char *, const char *);
79 static int maybe_pcie_speed(tnode_t *, did_t *,
80 const char *, const char *, const char *);
81 static int maybe_pcie_supported_speed(tnode_t *, did_t *,
82 const char *, const char *, const char *);
83 static int maybe_pcie_target_speed(tnode_t *, did_t *,
84 const char *, const char *, const char *);
85
86 /*
87 * Arrays of "property translation routines" to set the properties a
88 * given type of topology node should have.
89 *
90 * Note that the label_set translation *MUST COME BEFORE* the FRU
91 * translation. For the near term we're setting the FRU fmri to
92 * be a legacy-hc style FMRI based on the label, so the label needs
93 * to have been set before we do the FRU translation.
94 *
95 */
96
97 static const topo_pgroup_info_t io_pgroup =
98 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
99 static const topo_pgroup_info_t pci_pgroup =
100 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
101
102 static const topo_pgroup_info_t protocol_pgroup = {
103 TOPO_PGROUP_PROTOCOL,
104 TOPO_STABILITY_PRIVATE,
105 TOPO_STABILITY_PRIVATE,
106 1
107 }; /* Request to create protocol will be ignored by libtopo */
108
109 txprop_t Fn_common_props[] = {
110 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
111 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
112 { DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str },
113 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
114 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set },
115 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
116 { "serd_io_device_nonfatal_n", &io_pgroup, "serd_io_device_nonfatal_n",
117 maybe_di_uint_to_dec_str },
118 { "serd_io_device_nonfatal_t", &io_pgroup, "serd_io_device_nonfatal_t",
119 maybe_di_chars_copy },
120 { "serd_io_device_nonfatal_btlp_n", &io_pgroup,
121 "serd_io_device_nonfatal_btlp_n", maybe_di_uint_to_dec_str },
122 { "serd_io_device_nonfatal_btlp_t", &io_pgroup,
123 "serd_io_device_nonfatal_btlp_t", maybe_di_chars_copy },
124 { "serd_io_device_nonfatal_bdllp_n", &io_pgroup,
125 "serd_io_device_nonfatal_bdllp_n", maybe_di_uint_to_dec_str },
126 { "serd_io_device_nonfatal_bdllp_t", &io_pgroup,
127 "serd_io_device_nonfatal_bdllp_t", maybe_di_chars_copy },
128 { "serd_io_device_nonfatal_re_n", &io_pgroup,
129 "serd_io_device_nonfatal_re_n", maybe_di_uint_to_dec_str },
130 { "serd_io_device_nonfatal_re_t", &io_pgroup,
131 "serd_io_device_nonfatal_re_t", maybe_di_chars_copy },
132 { "serd_io_device_nonfatal_rto_n", &io_pgroup,
133 "serd_io_device_nonfatal_rto_n", maybe_di_uint_to_dec_str },
134 { "serd_io_device_nonfatal_rto_t", &io_pgroup,
135 "serd_io_device_nonfatal_rto_t", maybe_di_chars_copy },
136 { "serd_io_device_nonfatal_rnr_n", &io_pgroup,
137 "serd_io_device_nonfatal_rnr_n", maybe_di_uint_to_dec_str },
138 { "serd_io_device_nonfatal_rnr_t", &io_pgroup,
139 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy },
140 { "serd_io_pciex_corrlink-bus_btlp_n", &io_pgroup,
141 "serd_io_pciex_corrlink-bus_btlp_n", maybe_di_uint_to_dec_str },
142 { "serd_io_pciex_corrlink-bus_btlp_t", &io_pgroup,
143 "serd_io_pciex_corrlink-bus_btlp_t", maybe_di_chars_copy },
144 { "serd_io_pciex_corrlink-bus_bdllp_n", &io_pgroup,
145 "serd_io_pciex_corrlink-bus_bdllp_n", maybe_di_uint_to_dec_str },
146 { "serd_io_pciex_corrlink-bus_bdllp_t", &io_pgroup,
147 "serd_io_pciex_corrlink-bus_bdllp_t", maybe_di_chars_copy },
148 { "serd_io_pciex_corrlink-bus_re_n", &io_pgroup,
149 "serd_io_pciex_corrlink-bus_re_n", maybe_di_uint_to_dec_str },
150 { "serd_io_pciex_corrlink-bus_re_t", &io_pgroup,
151 "serd_io_pciex_corrlink-bus_re_t", maybe_di_chars_copy },
152 { "serd_io_pciex_corrlink-bus_rto_n", &io_pgroup,
153 "serd_io_pciex_corrlink-bus_rto_n", maybe_di_uint_to_dec_str },
154 { "serd_io_pciex_corrlink-bus_rto_t", &io_pgroup,
155 "serd_io_pciex_corrlink-bus_rto_t", maybe_di_chars_copy },
156 { "serd_io_pciex_corrlink-bus_rnr_n", &io_pgroup,
157 "serd_io_pciex_corrlink-bus_rnr_n", maybe_di_uint_to_dec_str },
158 { "serd_io_pciex_corrlink-bus_rnr_t", &io_pgroup,
159 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy },
160 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
161 { DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str },
162 { DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str },
163 { DI_AADDRPROP, &pci_pgroup, TOPO_PCI_AADDR, AADDR_set },
164 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
165 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
166 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
167 /*
168 * This entry will attempt to set the following three properties via
169 * lookups in the PCI database:
170 * - vendor-name
171 * - device-name
172 * - subsystem-name
173 */
174 { NULL, &pci_pgroup, NULL, maybe_pcidb_set }
175 };
176
177 txprop_t Dev_common_props[] = {
178 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
179 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
180 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
181 { DI_PCIE_MAX_WIDTH, &pci_pgroup, TOPO_PCI_MAX_WIDTH,
182 maybe_di_int_to_uint32 },
183 { DI_PCIE_CUR_WIDTH, &pci_pgroup, TOPO_PCI_CUR_WIDTH,
184 maybe_di_int_to_uint32 },
185 { DI_PCIE_MAX_SPEED, &pci_pgroup, TOPO_PCI_MAX_SPEED,
186 maybe_pcie_speed },
187 { DI_PCIE_CUR_SPEED, &pci_pgroup, TOPO_PCI_CUR_SPEED,
188 maybe_pcie_speed },
189 { DI_PCIE_SUP_SPEEDS, &pci_pgroup, TOPO_PCI_SUP_SPEED,
190 maybe_pcie_supported_speed },
191 { NULL, &pci_pgroup, TOPO_PCI_ADMIN_SPEED, maybe_pcie_target_speed }
192 };
193
194 txprop_t Bus_common_props[] = {
195 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
196 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
197 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set },
198 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
199 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
200 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
201 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
202 };
203
204 txprop_t RC_common_props[] = {
205 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
206 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy },
207 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
208 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set },
209 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
210 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set },
211 { NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_set },
212 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
213 /*
214 * These props need to be put at the end of table. x86pi has its
215 * own way to set them.
216 */
217 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
218 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
219 };
220
221 txprop_t ExHB_common_props[] = {
222 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
223 /*
224 * These props need to be put at the end of table. x86pi has its
225 * own way to set them.
226 */
227 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
228 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
229 };
230
231 txprop_t IOB_common_props[] = {
232 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
233 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set },
234 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }
235 };
236
237 txprop_t HB_common_props[] = {
238 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set },
239 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set },
240 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set },
241 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set },
242 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set },
243 /*
244 * These props need to be put at the end of table. x86pi has its
245 * own way to set them.
246 */
247 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set },
248 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }
249 };
250
251 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t);
252 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t);
253 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t);
254 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t);
255 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t);
256 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t);
257 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t);
258
259 /*
260 * If this devinfo node came originally from OBP data, we'll have prom
261 * properties associated with the node where we can find properties of
262 * interest. We ignore anything after the the first four bytes of the
263 * property, and interpet those first four bytes as our unsigned
264 * integer. If we don't find the property or it's not large enough,
265 * 'val' will remained unchanged and we'll return -1. Otherwise 'val'
266 * gets updated with the property value and we return 0.
267 */
268 static int
promprop2uint(topo_mod_t * mod,di_node_t n,const char * propnm,uint_t * val)269 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val)
270 {
271 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
272 di_prom_prop_t pp = DI_PROM_PROP_NIL;
273 uchar_t *buf;
274
275 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
276 return (-1);
277
278 while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) {
279 if (strcmp(di_prom_prop_name(pp), propnm) == 0) {
280 if (di_prom_prop_data(pp, &buf) < sizeof (uint_t))
281 continue;
282 bcopy(buf, val, sizeof (uint_t));
283 return (0);
284 }
285 }
286 return (-1);
287 }
288
289 /*
290 * If this devinfo node was added by the PCI hotplug framework it
291 * doesn't have the PROM properties, but hopefully has the properties
292 * we're looking for attached directly to the devinfo node. We only
293 * care about the first four bytes of the property, which we read as
294 * our unsigned integer. The remaining bytes are ignored. If we
295 * don't find the property we're looking for, or can't get its value,
296 * 'val' remains unchanged and we return -1. Otherwise 'val' gets the
297 * property value and we return 0.
298 */
299 static int
hwprop2uint(di_node_t n,const char * propnm,uint_t * val)300 hwprop2uint(di_node_t n, const char *propnm, uint_t *val)
301 {
302 di_prop_t hp = DI_PROP_NIL;
303 uchar_t *buf;
304
305 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) {
306 if (strcmp(di_prop_name(hp), propnm) == 0) {
307 if (di_prop_bytes(hp, &buf) < sizeof (uint_t))
308 continue;
309 bcopy(buf, val, sizeof (uint_t));
310 return (0);
311 }
312 }
313 return (-1);
314 }
315
316 int
di_uintprop_get(topo_mod_t * mod,di_node_t n,const char * pnm,uint_t * pv)317 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv)
318 {
319 if (hwprop2uint(n, pnm, pv) < 0)
320 if (promprop2uint(mod, n, pnm, pv) < 0)
321 return (-1);
322 return (0);
323 }
324
325 int
di_bytes_get(topo_mod_t * mod,di_node_t n,const char * pnm,int * sz,uchar_t ** db)326 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz,
327 uchar_t **db)
328 {
329 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL;
330 di_prom_prop_t pp = DI_PROM_PROP_NIL;
331 di_prop_t hp = DI_PROP_NIL;
332
333 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL)
334 return (-1);
335
336 *sz = -1;
337 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) {
338 if (strcmp(di_prop_name(hp), pnm) == 0) {
339 if ((*sz = di_prop_bytes(hp, db)) < 0)
340 continue;
341 break;
342 }
343 }
344 if (*sz < 0) {
345 while ((pp = di_prom_prop_next(ptp, n, pp)) !=
346 DI_PROM_PROP_NIL) {
347 if (strcmp(di_prom_prop_name(pp), pnm) == 0) {
348 *sz = di_prom_prop_data(pp, db);
349 if (*sz < 0)
350 continue;
351 break;
352 }
353 }
354 }
355
356 if (*sz < 0)
357 return (-1);
358 return (0);
359 }
360
361 /*
362 * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole
363 * story, leaving off the device and function number. Chances are if
364 * devfs doesn't put these on then we'll never see this device as an
365 * error detector called out in an ereport. Unfortunately, there are
366 * races and we sometimes do get ereports from devices that devfs
367 * decides aren't there. For example, the error injector card seems
368 * to bounce in and out of existence according to devfs. We tack on
369 * the missing dev and fn here so that the DEV property used to look
370 * up the topology node is correct.
371 */
372 static char *
dev_path_fix(topo_mod_t * mp,char * path,int devno,int fnno)373 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno)
374 {
375 char *lastslash;
376 char *newpath;
377 int need;
378
379 /*
380 * We only care about the last component of the dev path. If
381 * we don't find a slash, something is weird.
382 */
383 lastslash = strrchr(path, '/');
384 assert(lastslash != NULL);
385
386 /*
387 * If an @ sign is present in the last component, the
388 * di_devfs_path() result had the device,fn unit-address.
389 * In that case there's nothing we need do.
390 */
391 if (strchr(lastslash, '@') != NULL)
392 return (path);
393
394 if (fnno == 0)
395 need = snprintf(NULL, 0, "%s@%x", path, devno);
396 else
397 need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno);
398 need++;
399
400 if ((newpath = topo_mod_alloc(mp, need)) == NULL) {
401 topo_mod_strfree(mp, path);
402 return (NULL);
403 }
404
405 if (fnno == 0)
406 (void) snprintf(newpath, need, "%s@%x", path, devno);
407 else
408 (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno);
409
410 topo_mod_strfree(mp, path);
411 return (newpath);
412 }
413
414 /*
415 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path
416 * after the first element in the bus address.
417 */
418 static char *
dev_for_hostbridge(topo_mod_t * mp,char * path)419 dev_for_hostbridge(topo_mod_t *mp, char *path)
420 {
421 char *lastslash;
422 char *newpath;
423 char *comma;
424 int plen;
425
426 plen = strlen(path) + 1;
427
428 /*
429 * We only care about the last component of the dev path. If
430 * we don't find a slash, something is weird.
431 */
432 lastslash = strrchr(path, '/');
433 assert(lastslash != NULL);
434
435 /*
436 * Find the comma in the last component component@x,y, and
437 * truncate the comma and any following number.
438 */
439 comma = strchr(lastslash, ',');
440 assert(comma != NULL);
441
442 *comma = '\0';
443 if ((newpath = topo_mod_strdup(mp, path)) == NULL) {
444 topo_mod_free(mp, path, plen);
445 return (NULL);
446 }
447
448 *comma = ',';
449 topo_mod_free(mp, path, plen);
450 return (newpath);
451 }
452
453 /*ARGSUSED*/
454 static int
ASRU_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)455 ASRU_set(tnode_t *tn, did_t *pd,
456 const char *dpnm, const char *tpgrp, const char *tpnm)
457 {
458 topo_mod_t *mp;
459 nvlist_t *fmri;
460 char *dnpath, *path, *fpath, *nm;
461 int d, e, f;
462
463 /*
464 * If this topology node represents a function of device,
465 * set the ASRU to a dev scheme FMRI based on the value of
466 * di_devfs_path(). If that path is NULL, set the ASRU to
467 * be the resource describing this topology node. If this
468 * isn't a function, inherit any ASRU from the parent.
469 */
470 mp = did_mod(pd);
471 nm = topo_node_name(tn);
472 if ((strcmp(nm, PCI_BUS) == 0 && did_gettnode(pd) &&
473 strcmp(topo_node_name(did_gettnode(pd)), HOSTBRIDGE) == 0) ||
474 strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 ||
475 strcmp(nm, PCIEX_ROOT) == 0) {
476 if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) {
477 /*
478 * Dup the path, dev_path_fix() may replace it and
479 * dev_path_fix() wouldn't know to use
480 * di_devfs_path_free()
481 */
482 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
483 di_devfs_path_free(dnpath);
484 return (topo_mod_seterrno(mp, EMOD_NOMEM));
485 }
486 di_devfs_path_free(dnpath);
487 did_BDF(pd, NULL, &d, &f);
488 if ((fpath = dev_path_fix(mp, path, d, f)) == NULL)
489 return (topo_mod_seterrno(mp, EMOD_NOMEM));
490
491 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
492 fpath, NULL);
493 if (fmri == NULL) {
494 topo_mod_dprintf(mp,
495 "dev:///%s fmri creation failed.\n", fpath);
496 topo_mod_strfree(mp, fpath);
497 return (-1);
498 }
499 topo_mod_strfree(mp, fpath);
500 } else {
501 topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
502 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
503 TOPO_PROP_RESOURCE, &fmri, &e) < 0)
504 return (topo_mod_seterrno(mp, e));
505 }
506 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
507 nvlist_free(fmri);
508 return (topo_mod_seterrno(mp, e));
509 }
510 nvlist_free(fmri);
511 return (0);
512 }
513 (void) topo_node_asru_set(tn, NULL, 0, &e);
514
515 return (0);
516 }
517
518 /*
519 * Set the FRU property to the hc fmri of this tnode
520 */
521 int
FRU_fmri_set(topo_mod_t * mp,tnode_t * tn)522 FRU_fmri_set(topo_mod_t *mp, tnode_t *tn)
523 {
524 nvlist_t *fmri;
525 int err, e;
526
527 if (topo_node_resource(tn, &fmri, &err) < 0 ||
528 fmri == NULL) {
529 topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n",
530 topo_strerror(topo_mod_errno(mp)));
531 return (topo_mod_seterrno(mp, err));
532 }
533 e = topo_node_fru_set(tn, fmri, 0, &err);
534 nvlist_free(fmri);
535 if (e < 0)
536 return (topo_mod_seterrno(mp, err));
537 return (0);
538 }
539
540 tnode_t *
find_predecessor(tnode_t * tn,char * mod_name)541 find_predecessor(tnode_t *tn, char *mod_name)
542 {
543 tnode_t *pnode = topo_node_parent(tn);
544
545 while (pnode && (strcmp(topo_node_name(pnode), mod_name) != 0)) {
546 pnode = topo_node_parent(pnode);
547 }
548 return (pnode);
549 }
550
551 static int
use_predecessor_fru(tnode_t * tn,char * mod_name)552 use_predecessor_fru(tnode_t *tn, char *mod_name)
553 {
554 tnode_t *pnode = NULL;
555 nvlist_t *fru = NULL;
556 int err = 0;
557
558 if ((pnode = find_predecessor(tn, mod_name)) == NULL)
559 return (-1);
560 if ((pnode = topo_node_parent(pnode)) == NULL)
561 return (-1);
562 if (topo_node_fru(pnode, &fru, NULL, &err) != 0)
563 return (-1);
564
565 (void) topo_node_fru_set(tn, fru, 0, &err);
566 nvlist_free(fru);
567
568 return (0);
569 }
570
571 static int
use_predecessor_label(topo_mod_t * mod,tnode_t * tn,char * mod_name)572 use_predecessor_label(topo_mod_t *mod, tnode_t *tn, char *mod_name)
573 {
574 tnode_t *pnode = NULL;
575 int err = 0;
576 char *plabel = NULL;
577
578 if ((pnode = find_predecessor(tn, mod_name)) == NULL)
579 return (-1);
580 if ((pnode = topo_node_parent(pnode)) == NULL)
581 return (-1);
582 if (topo_node_label(pnode, &plabel, &err) != 0 || plabel == NULL)
583 return (-1);
584
585 (void) topo_node_label_set(tn, plabel, &err);
586
587 topo_mod_strfree(mod, plabel);
588
589 return (0);
590 }
591
592
593 /*ARGSUSED*/
594 static int
FRU_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)595 FRU_set(tnode_t *tn, did_t *pd,
596 const char *dpnm, const char *tpgrp, const char *tpnm)
597 {
598 topo_mod_t *mp;
599 char *nm;
600 int e = 0, err = 0;
601
602 nm = topo_node_name(tn);
603 mp = did_mod(pd);
604
605 /*
606 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT,
607 * check for a CPUBOARD predecessor. If found, inherit its
608 * parent's FRU. Otherwise, continue with FRU set.
609 */
610 if ((strcmp(nm, PCIEX_BUS) == 0) &&
611 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {
612
613 if (use_predecessor_fru(tn, CPUBOARD) == 0)
614 return (0);
615 }
616 /*
617 * If this topology node represents something other than an
618 * ioboard or a device that implements a slot, inherit the
619 * parent's FRU value. If there is no label, inherit our
620 * parent's FRU value. Otherwise, munge up an fmri based on
621 * the label.
622 */
623 if (strcmp(nm, IOBOARD) != 0 && strcmp(nm, PCI_DEVICE) != 0 &&
624 strcmp(nm, PCIEX_DEVICE) != 0 && strcmp(nm, PCIEX_BUS) != 0) {
625 (void) topo_node_fru_set(tn, NULL, 0, &e);
626 return (0);
627 }
628
629 /*
630 * If ioboard, set fru fmri to hc fmri
631 */
632 if (strcmp(nm, IOBOARD) == 0) {
633 e = FRU_fmri_set(mp, tn);
634 return (e);
635 } else if (strcmp(nm, PCI_DEVICE) == 0 ||
636 strcmp(nm, PCIEX_DEVICE) == 0 || strcmp(nm, PCIEX_BUS) == 0) {
637 nvlist_t *in, *out;
638
639 mp = did_mod(pd);
640 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0)
641 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL));
642 if (nvlist_add_uint64(in, "nv1", (uintptr_t)pd) != 0) {
643 nvlist_free(in);
644 return (topo_mod_seterrno(mp, EMOD_NOMEM));
645 }
646 if (topo_method_invoke(tn,
647 TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_VERSION,
648 in, &out, &err) != 0) {
649 nvlist_free(in);
650 return (topo_mod_seterrno(mp, err));
651 }
652 nvlist_free(in);
653 (void) topo_node_fru_set(tn, out, 0, &err);
654 nvlist_free(out);
655 } else
656 (void) topo_node_fru_set(tn, NULL, 0, &err);
657
658 return (0);
659 }
660
661 /*ARGSUSED*/
662 static int
label_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)663 label_set(tnode_t *tn, did_t *pd,
664 const char *dpnm, const char *tpgrp, const char *tpnm)
665 {
666 topo_mod_t *mp;
667 nvlist_t *in, *out;
668 char *label;
669 int err;
670
671 mp = did_mod(pd);
672 /*
673 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT,
674 * check for a CPUBOARD predecessor. If found, inherit its
675 * parent's Label. Otherwise, continue with label set.
676 */
677 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) &&
678 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) {
679
680 if (use_predecessor_label(mp, tn, CPUBOARD) == 0)
681 return (0);
682 }
683 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0)
684 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL));
685 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) !=
686 0) {
687 nvlist_free(in);
688 return (topo_mod_seterrno(mp, EMOD_NOMEM));
689 }
690 if (topo_method_invoke(tn,
691 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) {
692 nvlist_free(in);
693 return (topo_mod_seterrno(mp, err));
694 }
695 nvlist_free(in);
696 if (out != NULL &&
697 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) {
698 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL,
699 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) {
700 nvlist_free(out);
701 return (topo_mod_seterrno(mp, err));
702 }
703 nvlist_free(out);
704 }
705 return (0);
706 }
707
708 /*ARGSUSED*/
709 static int
EXCAP_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)710 EXCAP_set(tnode_t *tn, did_t *pd,
711 const char *dpnm, const char *tpgrp, const char *tpnm)
712 {
713 int excap = did_excap(pd);
714 int err;
715 int e = 0;
716
717 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) {
718 case PCIE_PCIECAP_DEV_TYPE_ROOT:
719 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
720 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err);
721 break;
722 case PCIE_PCIECAP_DEV_TYPE_UP:
723 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
724 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err);
725 break;
726 case PCIE_PCIECAP_DEV_TYPE_DOWN:
727 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
728 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err);
729 break;
730 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
731 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
732 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err);
733 break;
734 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
735 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
736 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err);
737 break;
738 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
739 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI,
740 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err);
741 break;
742 }
743 if (e != 0)
744 return (topo_mod_seterrno(did_mod(pd), err));
745 return (0);
746 }
747
748 /*ARGSUSED*/
749 static int
DEVprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)750 DEVprop_set(tnode_t *tn, did_t *pd,
751 const char *dpnm, const char *tpgrp, const char *tpnm)
752 {
753 topo_mod_t *mp;
754 char *dnpath;
755 char *path, *fpath;
756 int d, f;
757 int err, e;
758
759 mp = did_mod(pd);
760 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) {
761 topo_mod_dprintf(mp, "NULL di_devfs_path.\n");
762 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT));
763 }
764 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) {
765 di_devfs_path_free(dnpath);
766 return (-1);
767 }
768 di_devfs_path_free(dnpath);
769
770 /* The DEV path is modified for hostbridges */
771 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) {
772 fpath = dev_for_hostbridge(did_mod(pd), path);
773 } else {
774 did_BDF(pd, NULL, &d, &f);
775 fpath = dev_path_fix(mp, path, d, f);
776 }
777 if (fpath == NULL)
778 return (-1);
779 e = topo_prop_set_string(tn,
780 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err);
781 topo_mod_strfree(mp, fpath);
782 if (e != 0)
783 return (topo_mod_seterrno(mp, err));
784 return (0);
785 }
786
787 /*ARGSUSED*/
788 static int
DRIVERprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)789 DRIVERprop_set(tnode_t *tn, did_t *pd,
790 const char *dpnm, const char *tpgrp, const char *tpnm)
791 {
792 char *dnm;
793 int err;
794
795 if ((dnm = di_driver_name(did_dinode(pd))) == NULL)
796 return (0);
797 if (topo_prop_set_string(tn,
798 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0)
799 return (topo_mod_seterrno(did_mod(pd), err));
800
801 return (0);
802 }
803
804 /*ARGSUSED*/
805 static int
INSTprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)806 INSTprop_set(tnode_t *tn, did_t *pd,
807 const char *dpnm, const char *tpgrp, const char *tpnm)
808 {
809 int inst, err;
810
811 if ((inst = di_instance(did_dinode(pd))) == -1)
812 return (0);
813 if (topo_prop_set_uint32(tn,
814 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, inst, &err) < 0)
815 return (topo_mod_seterrno(did_mod(pd), err));
816
817 return (0);
818 }
819
820 /*ARGSUSED*/
821 static int
MODULEprop_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)822 MODULEprop_set(tnode_t *tn, did_t *pd,
823 const char *dpnm, const char *tpgrp, const char *tpnm)
824 {
825 nvlist_t *mod;
826 topo_mod_t *mp;
827 char *dnm;
828 int err;
829
830 if ((dnm = di_driver_name(did_dinode(pd))) == NULL)
831 return (0);
832
833 mp = did_mod(pd);
834 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, dnm)) == NULL)
835 return (0); /* driver maybe detached, return success */
836
837 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, mod,
838 &err) < 0) {
839 nvlist_free(mod);
840 return (topo_mod_seterrno(mp, err));
841 }
842 nvlist_free(mod);
843
844 return (0);
845 }
846
847 /*ARGSUSED*/
848 static int
maybe_di_chars_copy(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)849 maybe_di_chars_copy(tnode_t *tn, did_t *pd,
850 const char *dpnm, const char *tpgrp, const char *tpnm)
851 {
852 topo_mod_t *mp;
853 uchar_t *typbuf;
854 char *tmpbuf;
855 int sz = -1;
856 int err, e;
857
858 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
859 return (0);
860 mp = did_mod(pd);
861
862 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL)
863 return (topo_mod_seterrno(mp, EMOD_NOMEM));
864
865 bcopy(typbuf, tmpbuf, sz);
866 tmpbuf[sz] = 0;
867 e = topo_prop_set_string(tn,
868 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err);
869 topo_mod_free(mp, tmpbuf, sz + 1);
870 if (e != 0)
871 return (topo_mod_seterrno(mp, err));
872 return (0);
873 }
874
875 static int
uint_to_strprop(topo_mod_t * mp,uint_t v,tnode_t * tn,const char * tpgrp,const char * tpnm)876 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
877 const char *tpgrp, const char *tpnm)
878 {
879 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
880 int e;
881
882 (void) snprintf(str, 21, "%x", v);
883 if (topo_prop_set_string(tn,
884 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
885 return (topo_mod_seterrno(mp, e));
886 return (0);
887 }
888
889 static int
maybe_di_uint_to_str(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)890 maybe_di_uint_to_str(tnode_t *tn, did_t *pd,
891 const char *dpnm, const char *tpgrp, const char *tpnm)
892 {
893 uint_t v;
894
895 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
896 return (0);
897
898 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
899 }
900
901 static int
uint_to_dec_strprop(topo_mod_t * mp,uint_t v,tnode_t * tn,const char * tpgrp,const char * tpnm)902 uint_to_dec_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn,
903 const char *tpgrp, const char *tpnm)
904 {
905 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
906 int e;
907
908 (void) snprintf(str, 21, "%d", v);
909 if (topo_prop_set_string(tn,
910 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
911 return (topo_mod_seterrno(mp, e));
912 return (0);
913 }
914
915 static int
maybe_di_uint_to_dec_str(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)916 maybe_di_uint_to_dec_str(tnode_t *tn, did_t *pd,
917 const char *dpnm, const char *tpgrp, const char *tpnm)
918 {
919 uint_t v;
920
921 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0)
922 return (0);
923
924 return (uint_to_dec_strprop(did_mod(pd), v, tn, tpgrp, tpnm));
925 }
926
927 static int
AADDR_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)928 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
929 const char *tpnm)
930 {
931 topo_mod_t *mp;
932 uchar_t *typbuf;
933 int sz = -1;
934 int err, e;
935
936 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0)
937 return (0);
938
939 mp = did_mod(pd);
940
941 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
942 /*LINTED*/
943 (uint32_t *)typbuf, sz/4, &err);
944
945 if (e != 0)
946 return (topo_mod_seterrno(mp, err));
947 return (0);
948 }
949
950 /*ARGSUSED*/
951 static int
BDF_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)952 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
953 const char *tpnm)
954 {
955 int bdf;
956 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */
957 int e;
958
959 if ((bdf = did_bdf(pd)) <= 0)
960 return (0);
961
962 (void) snprintf(str, 23, "0x%x", bdf);
963 if (topo_prop_set_string(tn,
964 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0)
965 return (topo_mod_seterrno(did_mod(pd), e));
966 return (0);
967 }
968
969 /*ARGSUSED*/
970 static int
maybe_pcidb_set(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)971 maybe_pcidb_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
972 const char *tpnm)
973 {
974 const char *vname, *dname = NULL, *ssname = NULL;
975 uint_t vid, pid, svid, ssid;
976 pcidb_vendor_t *pciv;
977 pcidb_device_t *pcid;
978 pcidb_subvd_t *pcis = NULL;
979 pcidb_hdl_t *pcih;
980 topo_mod_t *mod = did_mod(pd);
981 int err;
982
983 /*
984 * At a minimum, we need the vid/devid of the device to be able to
985 * lookup anything in the PCI database. So if we fail to look either
986 * of those up, bail out.
987 */
988 if (di_uintprop_get(did_mod(pd), did_dinode(pd), DI_VENDIDPROP, &vid) <
989 0 || di_uintprop_get(did_mod(pd), did_dinode(pd), DI_DEVIDPROP,
990 &pid) < 0) {
991 return (0);
992 }
993 /*
994 * If we fail to lookup the vendor, by the vid that's also a
995 * deal-breaker.
996 */
997 if ((pcih = topo_mod_pcidb(mod)) == NULL ||
998 (pciv = pcidb_lookup_vendor(pcih, vid)) == NULL) {
999 return (0);
1000 }
1001
1002 /* lookup vendor-name and set the topo property, if found */
1003 vname = pcidb_vendor_name(pciv);
1004 if (vname != NULL &&
1005 topo_prop_set_string(tn, tpgrp, TOPO_PCI_VENDNM,
1006 TOPO_PROP_IMMUTABLE, vname, &err) != 0) {
1007 return (topo_mod_seterrno(mod, err));
1008 }
1009
1010 /* lookup device-name and set the topo property, if found */
1011 if ((pcid = pcidb_lookup_device_by_vendor(pciv, pid)) != NULL) {
1012 dname = pcidb_device_name(pcid);
1013 }
1014 if (dname != NULL &&
1015 topo_prop_set_string(tn, tpgrp, TOPO_PCI_DEVNM,
1016 TOPO_PROP_IMMUTABLE, dname, &err) != 0) {
1017 return (topo_mod_seterrno(mod, err));
1018 }
1019
1020 /*
1021 * Not all devices will have a subsystem-name that we can lookup,
1022 * but if both subsystem-vendorid and subsystem-id exist in devinfo and
1023 * if we were previously able to find the device by devid then we can
1024 * at least attempt a lookup. If found, set the topo property.
1025 */
1026 if (pcid != NULL &&
1027 di_uintprop_get(did_mod(pd), did_dinode(pd), DI_SUBVENDIDPROP,
1028 &svid) == 0 &&
1029 di_uintprop_get(did_mod(pd), did_dinode(pd), DI_SUBSYSTEMID,
1030 &ssid) == 0) {
1031 pcis = pcidb_lookup_subvd_by_device(pcid, svid, ssid);
1032 }
1033 if (pcis != NULL) {
1034 ssname = pcidb_subvd_name(pcis);
1035 }
1036 if (ssname != NULL && strlen(ssname) > 0 &&
1037 topo_prop_set_string(tn, tpgrp, TOPO_PCI_SUBSYSNM,
1038 TOPO_PROP_IMMUTABLE, ssname, &err) != 0) {
1039 return (topo_mod_seterrno(mod, err));
1040 }
1041 return (0);
1042 }
1043
1044 int
did_props_set(tnode_t * tn,did_t * pd,txprop_t txarray[],int txnum)1045 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum)
1046 {
1047 topo_mod_t *mp;
1048 int i, r, e;
1049
1050 mp = did_mod(pd);
1051 for (i = 0; i < txnum; i++) {
1052 /*
1053 * Ensure the property group has been created.
1054 */
1055 if (txarray[i].tx_tpgroup != NULL) {
1056 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e)
1057 < 0) {
1058 if (e != ETOPO_PROP_DEFD)
1059 return (topo_mod_seterrno(mp, e));
1060 }
1061 }
1062
1063 topo_mod_dprintf(mp,
1064 "Setting property %s in group %s.\n",
1065 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name);
1066 r = txarray[i].tx_xlate(tn, pd,
1067 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name,
1068 txarray[i].tx_tprop);
1069 if (r != 0) {
1070 topo_mod_dprintf(mp, "failed.\n");
1071 topo_mod_dprintf(mp, "Error was %s.\n",
1072 topo_strerror(topo_mod_errno(mp)));
1073 return (-1);
1074 }
1075 topo_mod_dprintf(mp, "succeeded.\n");
1076 }
1077 return (0);
1078 }
1079
1080 static int
maybe_di_int_to_uint32(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)1081 maybe_di_int_to_uint32(tnode_t *tn, did_t *pd, const char *dpnm,
1082 const char *tpgrp, const char *tpnm)
1083 {
1084 int ret, *vals;
1085
1086 ret = di_prop_lookup_ints(DDI_DEV_T_ANY, did_dinode(pd), dpnm, &vals);
1087 if (ret != 1) {
1088 return (0);
1089 }
1090
1091 if (topo_prop_set_uint32(tn, tpgrp, tpnm, 0, (uint32_t)*vals, &ret) !=
1092 0) {
1093 return (topo_mod_seterrno(did_mod(pd), ret));
1094 }
1095
1096 return (0);
1097 }
1098
1099 static int
maybe_pcie_speed(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)1100 maybe_pcie_speed(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp,
1101 const char *tpnm)
1102 {
1103 int ret;
1104 int64_t *vals;
1105
1106 ret = di_prop_lookup_int64(DDI_DEV_T_ANY, did_dinode(pd), dpnm, &vals);
1107 if (ret != 1) {
1108 return (0);
1109 }
1110
1111 if (topo_prop_set_uint64(tn, tpgrp, tpnm, 0, (uint64_t)*vals, &ret) !=
1112 0) {
1113 return (topo_mod_seterrno(did_mod(pd), ret));
1114 }
1115 return (0);
1116 }
1117
1118 static int
maybe_pcie_supported_speed(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)1119 maybe_pcie_supported_speed(tnode_t *tn, did_t *pd, const char *dpnm,
1120 const char *tpgrp, const char *tpnm)
1121 {
1122 int ret;
1123 uint_t count;
1124 int64_t *vals;
1125
1126 ret = di_prop_lookup_int64(DDI_DEV_T_ANY, did_dinode(pd), dpnm, &vals);
1127 if (ret < 1) {
1128 return (0);
1129 }
1130
1131 count = (uint_t)ret;
1132 if (topo_prop_set_uint64_array(tn, tpgrp, tpnm, 0, (uint64_t *)vals,
1133 count, &ret) != 0) {
1134 return (topo_mod_seterrno(did_mod(pd), ret));
1135 }
1136 return (0);
1137 }
1138
1139 static int
maybe_pcie_target_speed(tnode_t * tn,did_t * pd,const char * dpnm,const char * tpgrp,const char * tpnm)1140 maybe_pcie_target_speed(tnode_t *tn, did_t *pd, const char *dpnm,
1141 const char *tpgrp, const char *tpnm)
1142 {
1143 di_prop_t prop = DI_PROP_NIL;
1144 boolean_t admin = B_FALSE;
1145 int64_t *val = NULL;
1146 int ret;
1147
1148 while ((prop = di_prop_next(did_dinode(pd), prop)) != DI_PROP_NIL) {
1149 const char *n = di_prop_name(prop);
1150
1151 if (strcmp(DI_PCIE_ADMIN_TAG, n) == 0) {
1152 admin = B_TRUE;
1153 } else if (strcmp(DI_PCIE_TARG_SPEED, n) == 0) {
1154 if (di_prop_int64(prop, &val) != 1) {
1155 val = NULL;
1156 }
1157 }
1158 }
1159
1160 if (!admin || val == NULL) {
1161 return (0);
1162 }
1163
1164 if (topo_prop_set_uint64(tn, tpgrp, tpnm, 0, (uint64_t)*val, &ret) !=
1165 0) {
1166 return (topo_mod_seterrno(did_mod(pd), ret));
1167 }
1168 return (0);
1169 }
1170