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