xref: /titanic_52/usr/src/lib/fm/topo/modules/i86pc/x86pi/x86pi_subr.c (revision efd31e1d839d4665462b5c267a1c654548082663)
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  *  Subroutines used by the i86pc Generic Topology Enumerator
28  */
29 
30 #include <sys/types.h>
31 #include <strings.h>
32 #include <deflt.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <fm/topo_mod.h>
36 #include <fm/topo_hc.h>
37 #include <sys/devfm.h>
38 #include <sys/pci.h>
39 #include <sys/systeminfo.h>
40 #include <sys/fm/protocol.h>
41 #include <sys/utsname.h>
42 #include <sys/smbios.h>
43 #include <sys/smbios_impl.h>
44 #include <x86pi_impl.h>
45 
46 
47 static const topo_pgroup_info_t sys_pgroup = {
48 	TOPO_PGROUP_SYSTEM,
49 	TOPO_STABILITY_PRIVATE,
50 	TOPO_STABILITY_PRIVATE,
51 	1
52 };
53 
54 static const topo_pgroup_info_t auth_pgroup = {
55 	FM_FMRI_AUTHORITY,
56 	TOPO_STABILITY_PRIVATE,
57 	TOPO_STABILITY_PRIVATE,
58 	1
59 };
60 
61 
62 /*
63  * Free hcfmri strings.
64  */
65 void
66 x86pi_hcfmri_info_fini(topo_mod_t *mod, x86pi_hcfmri_t *hc)
67 {
68 	if (hc->hc_name != NULL)
69 		topo_mod_strfree(mod, (char *)hc->hc_name);
70 	if (hc->manufacturer != NULL)
71 		topo_mod_strfree(mod, (char *)hc->manufacturer);
72 	if (hc->product != NULL)
73 		topo_mod_strfree(mod, (char *)hc->product);
74 	if (hc->version != NULL)
75 		topo_mod_strfree(mod, (char *)hc->version);
76 	if (hc->serial_number != NULL)
77 		topo_mod_strfree(mod, (char *)hc->serial_number);
78 	if (hc->asset_tag != NULL)
79 		topo_mod_strfree(mod, (char *)hc->asset_tag);
80 	if (hc->location != NULL)
81 		topo_mod_strfree(mod, (char *)hc->location);
82 	if (hc->part_number != NULL)
83 		topo_mod_strfree(mod, (char *)hc->part_number);
84 }
85 
86 
87 /*
88  * Get the server hostname (the ID as far as the topo authority is
89  * concerned) from sysinfo and return a copy to the caller.
90  *
91  * The string must be freed with topo_mod_strfree()
92  */
93 char *
94 x86pi_get_serverid(topo_mod_t *mod)
95 {
96 	int result;
97 	char hostname[MAXNAMELEN];
98 
99 	topo_mod_dprintf(mod, "x86pi_get_serverid\n");
100 
101 	result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
102 	/* Everything is freed up and it's time to return the platform-id */
103 	if (result == -1) {
104 		return (NULL);
105 	}
106 	topo_mod_dprintf(mod, "x86pi_get_serverid: hostname = %s\n", hostname);
107 
108 	return (topo_mod_strdup(mod, hostname));
109 }
110 
111 
112 /*
113  * Get copy of SMBIOS.
114  */
115 smbios_hdl_t *
116 x86pi_smb_open(topo_mod_t *mod)
117 {
118 	smbios_hdl_t *smb_hdl;
119 	char *f = "x86pi_smb_open";
120 
121 	topo_mod_dprintf(mod, "%s\n", f);
122 
123 	smb_hdl = topo_mod_smbios(mod);
124 	if (smb_hdl == NULL) {
125 		topo_mod_dprintf(mod, "%s: failed to load SMBIOS\n", f);
126 		return (NULL);
127 	}
128 
129 	return (smb_hdl);
130 }
131 
132 
133 /*
134  * Go through the smbios structures looking for a type. Fill in
135  * the structure count as well as the id(s) of the struct types.
136  */
137 void
138 x86pi_smb_strcnt(topo_mod_t *mod, smbs_cnt_t *stype)
139 {
140 	const smb_struct_t *sp;
141 	int nstructs;
142 	int i, cnt;
143 	smbios_hdl_t *shp;
144 
145 	shp = topo_mod_smbios(mod);
146 	if (shp == NULL) {
147 		stype->count = 0;
148 		return;
149 	}
150 
151 	nstructs = shp->sh_nstructs;
152 	sp = shp->sh_structs;
153 
154 	for (i = 0, cnt = 0; i < nstructs; i++, sp++) {
155 		if (sp->smbst_hdr->smbh_type == stype->type) {
156 			stype->ids[cnt].node = NULL;
157 			stype->ids[cnt].id = sp->smbst_hdr->smbh_hdl;
158 			cnt++;
159 		}
160 	}
161 
162 	stype->count = cnt;
163 }
164 
165 
166 /*
167  * Calculate the authority information for a node.  Inherit the data if
168  * possible, but always create an appropriate property group.
169  */
170 int
171 x86pi_set_auth(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri, tnode_t *t_parent,
172     tnode_t *t_node)
173 {
174 	int 		result;
175 	int		err;
176 	int		is_chassis = 0;
177 	int		chassis_instance = 0;
178 	nvlist_t	*auth;
179 	char		*val = NULL;
180 	char		*prod = NULL;
181 	char		*psn = NULL;
182 	char		*csn = NULL;
183 	char		*server = NULL;
184 	char		*f = "x86pi_set_auth";
185 
186 	if (mod == NULL || t_parent == NULL || t_node == NULL) {
187 		return (-1);
188 	}
189 
190 	result = topo_pgroup_create(t_node, &auth_pgroup, &err);
191 	if (result != 0 && err != ETOPO_PROP_DEFD) {
192 		/*
193 		 * We failed to create the property group and it was not
194 		 * already defined.  Set the err code and return failure.
195 		 */
196 		(void) topo_mod_seterrno(mod, err);
197 		return (-1);
198 	}
199 
200 	/* Get the authority information already available from the parent */
201 	auth = topo_mod_auth(mod, t_parent);
202 
203 	/* Determnine if this is a chassis node and set it's instance */
204 	if ((strlen(hcfmri->hc_name) == strlen(CHASSIS)) &&
205 	    strncmp(hcfmri->hc_name, CHASSIS, strlen(CHASSIS)) == 0) {
206 		is_chassis = 1;
207 		chassis_instance = hcfmri->instance;
208 	}
209 
210 	/*
211 	 * Set the authority data, inheriting it if possible, but creating it
212 	 * if necessary.
213 	 */
214 
215 	/* product-id */
216 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
217 	    FM_FMRI_AUTH_PRODUCT, &err);
218 	if (result != 0 && err != ETOPO_PROP_DEFD) {
219 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
220 		    &prod);
221 		if (result != 0 || prod == NULL) {
222 			/*
223 			 * No product information in the parent node or auth
224 			 * list. Use the product information in the hcfrmi
225 			 * struct.
226 			 */
227 			prod = (char *)hcfmri->product;
228 			if (prod == NULL) {
229 				topo_mod_dprintf(mod, "%s: product name not "
230 				    "found for %s node\n", f, hcfmri->hc_name);
231 			}
232 		}
233 
234 		/*
235 		 * We continue even if the product information is not available
236 		 * to enumerate as much as possible.
237 		 */
238 		if (prod != NULL) {
239 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
240 			    FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
241 			    &err);
242 			if (result != 0) {
243 				/* Preserve the error and continue */
244 				(void) topo_mod_seterrno(mod, err);
245 				topo_mod_dprintf(mod, "%s: failed to set "
246 				    "property %s (%d) : %s\n", f,
247 				    FM_FMRI_AUTH_PRODUCT, err,
248 				    topo_strerror(err));
249 			}
250 		}
251 	}
252 
253 	/* product-sn */
254 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
255 	    FM_FMRI_AUTH_PRODUCT_SN, &err);
256 	if (result != 0 && err != ETOPO_PROP_DEFD) {
257 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
258 		    &psn);
259 		if (result != 0 || psn == NULL) {
260 			/*
261 			 * No product-sn information in the parent node or auth
262 			 * list.
263 			 */
264 			topo_mod_dprintf(mod, "%s: psn not found\n", f);
265 		} else {
266 			/*
267 			 * We continue even if the product-sn information is
268 			 * not available to enumerate as much as possible.
269 			 */
270 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
271 			    FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn,
272 			    &err);
273 			if (result != 0) {
274 				/* Preserve the error and continue */
275 				(void) topo_mod_seterrno(mod, err);
276 				topo_mod_dprintf(mod, "%s: failed to "
277 				    "set property %s (%d) : %s\n", f,
278 				    FM_FMRI_AUTH_PRODUCT_SN, err,
279 				    topo_strerror(err));
280 			}
281 		}
282 	}
283 
284 	/* chassis-id */
285 	if (is_chassis == 0 || (is_chassis == 1 && chassis_instance == 0)) {
286 		/* either not a chassis node, or chassis #0 */
287 		result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
288 		    FM_FMRI_AUTH_CHASSIS, &err);
289 	} else {
290 		/* chassis 'n' in a >1 chassis system */
291 		result = err = -1;
292 	}
293 	if (result != 0 && err != ETOPO_PROP_DEFD) {
294 		if (is_chassis == 0) {
295 			result = nvlist_lookup_string(auth,
296 			    FM_FMRI_AUTH_CHASSIS, &csn);
297 			if (result != 0 || csn == NULL) {
298 				/*
299 				 * No chassis information in the parent
300 				 * node or auth list.
301 				 */
302 				topo_mod_dprintf(mod,
303 				    "%s: csn name not found\n", f);
304 			}
305 		} else {
306 			/*
307 			 * So as not to blindly set the chassis-id to
308 			 * chassis #0's serial number.
309 			 */
310 			csn = val = topo_mod_strdup(mod, hcfmri->serial_number);
311 		}
312 
313 		/*
314 		 * We continue even if the chassis information is not available
315 		 * to enumerate as much as possible.
316 		 */
317 		if (csn != NULL) {
318 			if (is_chassis == 1)
319 				result = topo_prop_set_string(t_node,
320 				    FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
321 				    TOPO_PROP_MUTABLE, csn, &err);
322 			else
323 				result = topo_prop_set_string(t_node,
324 				    FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
325 				    TOPO_PROP_IMMUTABLE, csn, &err);
326 
327 			if (result != 0) {
328 				/* Preserve the error and continue */
329 				(void) topo_mod_seterrno(mod, err);
330 				topo_mod_dprintf(mod, "%s: failed to "
331 				    "set property %s (%d) : %s\n", f,
332 				    FM_FMRI_AUTH_CHASSIS, err,
333 				    topo_strerror(err));
334 			}
335 		}
336 
337 		if (val != NULL) {
338 			topo_mod_strfree(mod, val);
339 			val = NULL;
340 		}
341 	}
342 
343 	/* server-id */
344 	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
345 	    FM_FMRI_AUTH_SERVER, &err);
346 	if (result != 0 && err != ETOPO_PROP_DEFD) {
347 		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER,
348 		    &server);
349 		if (result != 0 || server == NULL) {
350 			/*
351 			 * No server information in the parent node or auth
352 			 * list.  Find the server information in hostname.
353 			 */
354 			server = val = x86pi_get_serverid(mod);
355 			if (server == NULL) {
356 				topo_mod_dprintf(mod, "%s: server "
357 				    "name not found for %s node\n", f,
358 				    hcfmri->hc_name);
359 			}
360 		}
361 
362 		/*
363 		 * We continue even if the server information is not available
364 		 * to enumerate as much as possible.
365 		 */
366 		if (server != NULL) {
367 			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
368 			    FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
369 			    &err);
370 			if (result != 0) {
371 				/* Preserve the error and continue */
372 				(void) topo_mod_seterrno(mod, err);
373 				topo_mod_dprintf(mod, "%s: failed to "
374 				    "set property %s (%d) : %s\n", f,
375 				    FM_FMRI_AUTH_SERVER, err,
376 				    topo_strerror(err));
377 			}
378 		}
379 
380 		if (val != NULL)
381 			topo_mod_strfree(mod, val);
382 	}
383 
384 	nvlist_free(auth);
385 
386 	return (0);
387 }
388 
389 
390 /*
391  * Calculate a generic FRU for the given node.  If the node is not a FRU,
392  * then inherit the FRU data from the nodes parent.
393  */
394 int
395 x86pi_set_frufmri(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri, tnode_t *t_parent,
396     tnode_t *t_node, int flag)
397 {
398 	int		result;
399 	int		err;
400 
401 	nvlist_t	*auth = NULL;
402 	nvlist_t	*frufmri = NULL;
403 
404 	if (t_node == NULL || mod == NULL) {
405 		return (-1);
406 	}
407 
408 	/*
409 	 * Determine if this node is a FRU
410 	 */
411 	if (!(flag & X86PI_ENUM_FRU)) {
412 		/* This node is not a FRU.  Inherit from parent and return */
413 		(void) topo_node_fru_set(t_node, NULL, 0, &result);
414 		return (0);
415 	}
416 
417 	/*
418 	 * This node is a FRU.  Create an FMRI.
419 	 */
420 	auth	= topo_mod_auth(mod, t_parent);
421 	frufmri	= topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION,
422 	    hcfmri->hc_name, hcfmri->instance, NULL, auth,
423 	    hcfmri->part_number, hcfmri->version, hcfmri->serial_number);
424 	if (frufmri == NULL) {
425 		topo_mod_dprintf(mod, "failed to create FRU: %s\n",
426 		    topo_strerror(topo_mod_errno(mod)));
427 	}
428 	nvlist_free(auth);
429 
430 	/* Set the FRU, whether NULL or not */
431 	result = topo_node_fru_set(t_node, frufmri, 0, &err);
432 	if (result != 0)  {
433 		(void) topo_mod_seterrno(mod, err);
434 	}
435 	nvlist_free(frufmri);
436 
437 	return (result);
438 }
439 
440 
441 /*
442  * Set the label for a topo node.
443  */
444 int
445 x86pi_set_label(topo_mod_t *mod, const char *label, const char *name,
446     tnode_t *t_node)
447 {
448 	int	result;
449 	int	err;
450 
451 	if (mod == NULL) {
452 		return (-1);
453 	}
454 
455 	/*
456 	 * Set the label for this topology node.
457 	 * Note that a NULL label will inherit the label from topology
458 	 * node's parent.
459 	 */
460 	result = topo_node_label_set(t_node, (char *)label, &err);
461 	if (result != 0) {
462 		(void) topo_mod_seterrno(mod, err);
463 		topo_mod_dprintf(mod, "x86pi_set_label: failed with label %s "
464 		    "on %s node: %s\n", (label == NULL ? "NULL" : label),
465 		    name, topo_strerror(err));
466 	}
467 
468 	return (result);
469 }
470 
471 
472 /*
473  * Calculate the system information for a node.  Inherit the data if
474  * possible, but always create an appropriate property group.
475  */
476 int
477 x86pi_set_system(topo_mod_t *mod, tnode_t *t_node)
478 {
479 	int		result;
480 	int		err;
481 	struct utsname	uts;
482 	char		isa[MAXNAMELEN];
483 
484 	if (mod == NULL || t_node == NULL) {
485 		return (-1);
486 	}
487 
488 	result = topo_pgroup_create(t_node, &sys_pgroup, &err);
489 	if (result != 0 && err != ETOPO_PROP_DEFD) {
490 		/*
491 		 * We failed to create the property group and it was not
492 		 * already defined.  Set the err code and return failure.
493 		 */
494 		(void) topo_mod_seterrno(mod, err);
495 		return (-1);
496 	}
497 
498 	result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
499 	    &err);
500 	if (result != 0 && err != ETOPO_PROP_DEFD) {
501 		isa[0] = '\0';
502 		result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
503 		if (result == -1) {
504 			/* Preserve the error and continue */
505 			topo_mod_dprintf(mod, "x86pi_set_system: failed to "
506 			    "read SI_ARCHITECTURE: %d\n", errno);
507 		}
508 		if (strnlen(isa, MAXNAMELEN) > 0) {
509 			result = topo_prop_set_string(t_node,
510 			    TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
511 			    TOPO_PROP_IMMUTABLE, isa, &err);
512 			if (result != 0) {
513 				/* Preserve the error and continue */
514 				(void) topo_mod_seterrno(mod, err);
515 				topo_mod_dprintf(mod,
516 				    "x86pi_set_auth: failed to "
517 				    "set property %s (%d) : %s\n",
518 				    TOPO_PROP_ISA, err, topo_strerror(err));
519 			}
520 		}
521 	}
522 
523 	result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM,
524 	    TOPO_PROP_MACHINE, &err);
525 	if (result != 0 && err != ETOPO_PROP_DEFD) {
526 		result = uname(&uts);
527 		if (result == -1) {
528 			/* Preserve the error and continue */
529 			(void) topo_mod_seterrno(mod, errno);
530 			topo_mod_dprintf(mod, "x86pi_set_system: failed to "
531 			    "read uname: %d\n", errno);
532 		}
533 		if (strnlen(uts.machine, sizeof (uts.machine)) > 0) {
534 			result = topo_prop_set_string(t_node,
535 			    TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
536 			    TOPO_PROP_IMMUTABLE, uts.machine, &err);
537 			if (result != 0) {
538 				/* Preserve the error and continue */
539 				(void) topo_mod_seterrno(mod, err);
540 				topo_mod_dprintf(mod,
541 				    "x86pi_set_auth: failed to "
542 				    "set property %s (%d) : %s\n",
543 				    TOPO_PROP_MACHINE, err, topo_strerror(err));
544 			}
545 		}
546 	}
547 
548 	return (0);
549 }
550 
551 /*
552  * All the checks for compatibility are done within the kernel where the
553  * ereport generators are. They'll determine first if there's a problem
554  * and the topo enum will follow suit. The /dev/fm ioclt returns the value
555  * of the x86gentopo_legacy kernel variable which determines if this platform
556  * will provide an x86 generic topo or legacy topo enumeration.
557  */
558 /* ARGSUSED */
559 int
560 x86pi_check_comp(topo_mod_t *mod)
561 {
562 	int rv;
563 	int fd;
564 	int32_t legacy;
565 	nvlist_t *nvl = NULL;
566 	fm_ioc_data_t fid;
567 	char *ibuf = NULL, *obuf = NULL;
568 	size_t insz = 0, outsz = 0;
569 	char *f = "x86pi_check_comp";
570 	smbios_hdl_t *shp;
571 
572 	shp = topo_mod_smbios(mod);
573 	if (shp == NULL)
574 		return (X86PI_NONE);
575 
576 	/* open /dev/fm */
577 	fd = open("/dev/fm", O_RDONLY);
578 	if (fd < 0) {
579 		topo_mod_dprintf(mod, "%s: failed to open /dev/fm.\n", f);
580 		return (X86PI_NONE);
581 	}
582 
583 	/* set up buffers and ioctl data structure */
584 	outsz = FM_IOC_MAXBUFSZ;
585 	obuf = topo_mod_alloc(mod, outsz);
586 	if (obuf == NULL) {
587 		perror("umem_alloc");
588 		return (X86PI_NONE);
589 	}
590 
591 	fid.fid_version = 1;
592 	fid.fid_insz = insz;
593 	fid.fid_inbuf = ibuf;
594 	fid.fid_outsz = outsz;
595 	fid.fid_outbuf = obuf;
596 
597 	/* send the ioctl to /dev/fm to retrieve legacy variable */
598 	rv = ioctl(fd, FM_IOC_GENTOPO_LEGACY, &fid);
599 	if (rv < 0) {
600 		topo_mod_dprintf(mod, "%s: ioctl to /dev/fm failed", f);
601 		perror("fm_ioctl");
602 		(void) close(fd);
603 		return (X86PI_NONE);
604 	}
605 	(void) close(fd);
606 
607 	(void) nvlist_unpack(fid.fid_outbuf, fid.fid_outsz, &nvl, 0);
608 	(void) nvlist_lookup_int32(nvl, FM_GENTOPO_LEGACY, &legacy);
609 
610 	nvlist_free(nvl);
611 	topo_mod_free(mod, obuf, outsz);
612 
613 	if (legacy == 1) {
614 		/* legacy kernel variable set; will do the same */
615 		return (X86PI_NONE);
616 	}
617 
618 	/* legacy kernel variable not set; generic topo enum */
619 	return (X86PI_FULL);
620 }
621 
622 const char *
623 x86pi_cleanup_smbios_str(topo_mod_t *mod, const char *begin, int str_type)
624 {
625 	char buf[MAXNAMELEN];
626 	const char *end, *cp;
627 	char *pp;
628 	char c;
629 	int i;
630 
631 	end = begin + strlen(begin);
632 
633 	while (begin < end && isspace(*begin))
634 		begin++;
635 	while (begin < end && isspace(*(end - 1)))
636 		end--;
637 
638 	if (begin >= end)
639 		return (NULL);
640 
641 	cp = begin;
642 	for (i = 0; i < MAXNAMELEN - 1; i++) {
643 		if (cp >= end)
644 			break;
645 		c = *cp;
646 		if (str_type == LABEL) {
647 			if (!isprint(c))
648 				buf[i] = '-';
649 			else
650 				buf[i] = c;
651 		} else {
652 			if (c == ':' || c == '=' || c == '/' ||
653 			    isspace(c) || !isprint(c))
654 				buf[i] = '-';
655 			else
656 				buf[i] = c;
657 		}
658 		cp++;
659 	}
660 	buf[i] = 0;
661 
662 	pp = topo_mod_strdup(mod, buf);
663 
664 	if (str_type == LABEL)
665 		topo_mod_strfree(mod, (char *)begin);
666 
667 	return (pp);
668 }
669 
670 /*
671  * Return Bus/Dev/Func from "reg" devinfo property.
672  */
673 uint16_t
674 x86pi_bdf(topo_mod_t *mod, di_node_t node)
675 {
676 	int *val;
677 
678 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &val) < 0) {
679 		topo_mod_dprintf(mod, "couldn't get \"reg\" prop: %s.\n",
680 		    strerror(errno));
681 		return ((uint16_t)-1);
682 	}
683 
684 	return (uint16_t)((*val & PCI_REG_BDFR_M) >> PCI_REG_FUNC_SHIFT);
685 }
686 
687 /*
688  * Return PHY from "sata-phy" devinfo proporty.
689  */
690 int
691 x86pi_phy(topo_mod_t *mod, di_node_t node)
692 {
693 	int *phy;
694 
695 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "sata-phy", &phy) < 0) {
696 		topo_mod_dprintf(mod, "couldn't get \"sata-phy\" prop: %s.\n",
697 		    strerror(errno));
698 		return (-1);
699 	}
700 
701 	return (*phy);
702 }
703