17687d0d8SRobert Mustacchi /*
27687d0d8SRobert Mustacchi  * This file and its contents are supplied under the terms of the
37687d0d8SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
47687d0d8SRobert Mustacchi  * You may only use this file in accordance with the terms of version
57687d0d8SRobert Mustacchi  * 1.0 of the CDDL.
67687d0d8SRobert Mustacchi  *
77687d0d8SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
87687d0d8SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
97687d0d8SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
107687d0d8SRobert Mustacchi  */
117687d0d8SRobert Mustacchi 
127687d0d8SRobert Mustacchi /*
13bd97c7ceSRobert Mustacchi  * Copyright 2023 Oxide Computer Company
147687d0d8SRobert Mustacchi  */
157687d0d8SRobert Mustacchi 
167687d0d8SRobert Mustacchi #include <err.h>
177687d0d8SRobert Mustacchi #include <stdio.h>
187687d0d8SRobert Mustacchi #include <unistd.h>
197687d0d8SRobert Mustacchi #include <ofmt.h>
207687d0d8SRobert Mustacchi #include <strings.h>
217687d0d8SRobert Mustacchi #include <sys/pci.h>
227687d0d8SRobert Mustacchi 
237687d0d8SRobert Mustacchi #include "pcieadm.h"
247687d0d8SRobert Mustacchi 
257687d0d8SRobert Mustacchi typedef struct pcieadm_show_devs {
267687d0d8SRobert Mustacchi 	pcieadm_t *psd_pia;
277687d0d8SRobert Mustacchi 	ofmt_handle_t psd_ofmt;
287687d0d8SRobert Mustacchi 	boolean_t psd_funcs;
297687d0d8SRobert Mustacchi 	int psd_nfilts;
307687d0d8SRobert Mustacchi 	char **psd_filts;
3192f11af9SRobert Mustacchi 	boolean_t *psd_used;
327687d0d8SRobert Mustacchi 	uint_t psd_nprint;
337687d0d8SRobert Mustacchi } pcieadm_show_devs_t;
347687d0d8SRobert Mustacchi 
357687d0d8SRobert Mustacchi typedef enum pcieadm_show_devs_otype {
367687d0d8SRobert Mustacchi 	PCIEADM_SDO_VID,
377687d0d8SRobert Mustacchi 	PCIEADM_SDO_DID,
38bd97c7ceSRobert Mustacchi 	PCIEADM_SDO_REV,
39bd97c7ceSRobert Mustacchi 	PCIEADM_SDO_SUBVID,
40bd97c7ceSRobert Mustacchi 	PCIEADM_SDO_SUBSYS,
417687d0d8SRobert Mustacchi 	PCIEADM_SDO_BDF,
427687d0d8SRobert Mustacchi 	PCIEADM_SDO_BDF_BUS,
437687d0d8SRobert Mustacchi 	PCIEADM_SDO_BDF_DEV,
447687d0d8SRobert Mustacchi 	PCIEADM_SDO_BDF_FUNC,
457687d0d8SRobert Mustacchi 	PCIEADM_SDO_DRIVER,
4676c08ae9SRobert Mustacchi 	PCIEADM_SDO_INSTANCE,
4776c08ae9SRobert Mustacchi 	PCIEADM_SDO_INSTNUM,
487687d0d8SRobert Mustacchi 	PCIEADM_SDO_TYPE,
497687d0d8SRobert Mustacchi 	PCIEADM_SDO_VENDOR,
507687d0d8SRobert Mustacchi 	PCIEADM_SDO_DEVICE,
51bd97c7ceSRobert Mustacchi 	PCIEADM_SDO_SUBVENDOR,
52bd97c7ceSRobert Mustacchi 	PCIEADM_SDO_SUBSYSTEM,
537687d0d8SRobert Mustacchi 	PCIEADM_SDO_PATH,
547687d0d8SRobert Mustacchi 	PCIEADM_SDO_MAXSPEED,
557687d0d8SRobert Mustacchi 	PCIEADM_SDO_MAXWIDTH,
567687d0d8SRobert Mustacchi 	PCIEADM_SDO_CURSPEED,
577687d0d8SRobert Mustacchi 	PCIEADM_SDO_CURWIDTH,
587687d0d8SRobert Mustacchi 	PCIEADM_SDO_SUPSPEEDS
597687d0d8SRobert Mustacchi } pcieadm_show_devs_otype_t;
607687d0d8SRobert Mustacchi 
617687d0d8SRobert Mustacchi typedef struct pcieadm_show_devs_ofmt {
627687d0d8SRobert Mustacchi 	int psdo_vid;
637687d0d8SRobert Mustacchi 	int psdo_did;
64bd97c7ceSRobert Mustacchi 	int psdo_rev;
65bd97c7ceSRobert Mustacchi 	int psdo_subvid;
66bd97c7ceSRobert Mustacchi 	int psdo_subsys;
677687d0d8SRobert Mustacchi 	uint_t psdo_bus;
687687d0d8SRobert Mustacchi 	uint_t psdo_dev;
697687d0d8SRobert Mustacchi 	uint_t psdo_func;
707687d0d8SRobert Mustacchi 	const char *psdo_path;
717687d0d8SRobert Mustacchi 	const char *psdo_vendor;
727687d0d8SRobert Mustacchi 	const char *psdo_device;
73bd97c7ceSRobert Mustacchi 	const char *psdo_subvendor;
74bd97c7ceSRobert Mustacchi 	const char *psdo_subsystem;
757687d0d8SRobert Mustacchi 	const char *psdo_driver;
767687d0d8SRobert Mustacchi 	int psdo_instance;
777687d0d8SRobert Mustacchi 	int psdo_mwidth;
787687d0d8SRobert Mustacchi 	int psdo_cwidth;
797687d0d8SRobert Mustacchi 	int64_t psdo_mspeed;
807687d0d8SRobert Mustacchi 	int64_t psdo_cspeed;
817687d0d8SRobert Mustacchi 	int psdo_nspeeds;
827687d0d8SRobert Mustacchi 	int64_t *psdo_sspeeds;
837687d0d8SRobert Mustacchi } pcieadm_show_devs_ofmt_t;
847687d0d8SRobert Mustacchi 
857687d0d8SRobert Mustacchi static uint_t
pcieadm_speed2gen(int64_t speed)867687d0d8SRobert Mustacchi pcieadm_speed2gen(int64_t speed)
877687d0d8SRobert Mustacchi {
887687d0d8SRobert Mustacchi 	if (speed == 2500000000LL) {
897687d0d8SRobert Mustacchi 		return (1);
907687d0d8SRobert Mustacchi 	} else if (speed == 5000000000LL) {
917687d0d8SRobert Mustacchi 		return (2);
927687d0d8SRobert Mustacchi 	} else if (speed == 8000000000LL) {
937687d0d8SRobert Mustacchi 		return (3);
947687d0d8SRobert Mustacchi 	} else if (speed == 16000000000LL) {
957687d0d8SRobert Mustacchi 		return (4);
967687d0d8SRobert Mustacchi 	} else if (speed == 32000000000LL) {
977687d0d8SRobert Mustacchi 		return (5);
987687d0d8SRobert Mustacchi 	} else {
997687d0d8SRobert Mustacchi 		return (0);
1007687d0d8SRobert Mustacchi 	}
1017687d0d8SRobert Mustacchi }
1027687d0d8SRobert Mustacchi 
1037687d0d8SRobert Mustacchi static const char *
pcieadm_speed2str(int64_t speed)1047687d0d8SRobert Mustacchi pcieadm_speed2str(int64_t speed)
1057687d0d8SRobert Mustacchi {
1067687d0d8SRobert Mustacchi 	if (speed == 2500000000LL) {
1077687d0d8SRobert Mustacchi 		return ("2.5");
1087687d0d8SRobert Mustacchi 	} else if (speed == 5000000000LL) {
1097687d0d8SRobert Mustacchi 		return ("5.0");
1107687d0d8SRobert Mustacchi 	} else if (speed == 8000000000LL) {
1117687d0d8SRobert Mustacchi 		return ("8.0");
1127687d0d8SRobert Mustacchi 	} else if (speed == 16000000000LL) {
1137687d0d8SRobert Mustacchi 		return ("16.0");
1147687d0d8SRobert Mustacchi 	} else if (speed == 32000000000LL) {
1157687d0d8SRobert Mustacchi 		return ("32.0");
1167687d0d8SRobert Mustacchi 	} else {
1177687d0d8SRobert Mustacchi 		return (NULL);
1187687d0d8SRobert Mustacchi 	}
1197687d0d8SRobert Mustacchi }
1207687d0d8SRobert Mustacchi 
1217687d0d8SRobert Mustacchi static boolean_t
pcieadm_show_devs_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)1227687d0d8SRobert Mustacchi pcieadm_show_devs_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
1237687d0d8SRobert Mustacchi {
1247687d0d8SRobert Mustacchi 	const char *str;
1257687d0d8SRobert Mustacchi 	pcieadm_show_devs_ofmt_t *psdo = ofarg->ofmt_cbarg;
1267687d0d8SRobert Mustacchi 	boolean_t first = B_TRUE;
1277687d0d8SRobert Mustacchi 
1287687d0d8SRobert Mustacchi 	switch (ofarg->ofmt_id) {
1297687d0d8SRobert Mustacchi 	case PCIEADM_SDO_BDF:
1307687d0d8SRobert Mustacchi 		if (snprintf(buf, buflen, "%x/%x/%x", psdo->psdo_bus,
1317687d0d8SRobert Mustacchi 		    psdo->psdo_dev, psdo->psdo_func) >= buflen) {
1327687d0d8SRobert Mustacchi 			return (B_FALSE);
1337687d0d8SRobert Mustacchi 		}
1347687d0d8SRobert Mustacchi 		break;
1357687d0d8SRobert Mustacchi 	case PCIEADM_SDO_BDF_BUS:
1367687d0d8SRobert Mustacchi 		if (snprintf(buf, buflen, "%x", psdo->psdo_bus) >= buflen) {
1377687d0d8SRobert Mustacchi 			return (B_FALSE);
1387687d0d8SRobert Mustacchi 		}
1397687d0d8SRobert Mustacchi 		break;
1407687d0d8SRobert Mustacchi 	case PCIEADM_SDO_BDF_DEV:
1417687d0d8SRobert Mustacchi 		if (snprintf(buf, buflen, "%x", psdo->psdo_dev) >= buflen) {
1427687d0d8SRobert Mustacchi 			return (B_FALSE);
1437687d0d8SRobert Mustacchi 		}
1447687d0d8SRobert Mustacchi 		break;
1457687d0d8SRobert Mustacchi 	case PCIEADM_SDO_BDF_FUNC:
1467687d0d8SRobert Mustacchi 		if (snprintf(buf, buflen, "%x", psdo->psdo_func) >= buflen) {
1477687d0d8SRobert Mustacchi 			return (B_FALSE);
1487687d0d8SRobert Mustacchi 		}
1497687d0d8SRobert Mustacchi 		break;
15076c08ae9SRobert Mustacchi 	case PCIEADM_SDO_INSTANCE:
1517687d0d8SRobert Mustacchi 		if (psdo->psdo_driver == NULL || psdo->psdo_instance == -1) {
1527687d0d8SRobert Mustacchi 			(void) snprintf(buf, buflen, "--");
1537687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "%s%d", psdo->psdo_driver,
1547687d0d8SRobert Mustacchi 		    psdo->psdo_instance) >= buflen) {
1557687d0d8SRobert Mustacchi 			return (B_FALSE);
1567687d0d8SRobert Mustacchi 		}
1577687d0d8SRobert Mustacchi 		break;
15876c08ae9SRobert Mustacchi 	case PCIEADM_SDO_DRIVER:
15976c08ae9SRobert Mustacchi 		if (psdo->psdo_driver == NULL) {
16076c08ae9SRobert Mustacchi 			(void) snprintf(buf, buflen, "--");
16176c08ae9SRobert Mustacchi 		} else if (strlcpy(buf, psdo->psdo_driver, buflen) >= buflen) {
16276c08ae9SRobert Mustacchi 			return (B_FALSE);
16376c08ae9SRobert Mustacchi 		}
16476c08ae9SRobert Mustacchi 		break;
16576c08ae9SRobert Mustacchi 	case PCIEADM_SDO_INSTNUM:
16676c08ae9SRobert Mustacchi 		if (psdo->psdo_instance == -1) {
16776c08ae9SRobert Mustacchi 			(void) snprintf(buf, buflen, "--");
16876c08ae9SRobert Mustacchi 		} else if (snprintf(buf, buflen, "%d", psdo->psdo_instance) >=
16976c08ae9SRobert Mustacchi 		    buflen) {
17076c08ae9SRobert Mustacchi 			return (B_FALSE);
17176c08ae9SRobert Mustacchi 		}
17276c08ae9SRobert Mustacchi 		break;
1737687d0d8SRobert Mustacchi 	case PCIEADM_SDO_PATH:
1747687d0d8SRobert Mustacchi 		if (strlcat(buf, psdo->psdo_path, buflen) >= buflen) {
1757687d0d8SRobert Mustacchi 			return (B_TRUE);
1767687d0d8SRobert Mustacchi 		}
1777687d0d8SRobert Mustacchi 		break;
1787687d0d8SRobert Mustacchi 	case PCIEADM_SDO_VID:
1797687d0d8SRobert Mustacchi 		if (psdo->psdo_vid == -1) {
1807687d0d8SRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
1817687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "%x", psdo->psdo_vid) >=
1827687d0d8SRobert Mustacchi 		    buflen) {
1837687d0d8SRobert Mustacchi 			return (B_FALSE);
1847687d0d8SRobert Mustacchi 		}
1857687d0d8SRobert Mustacchi 		break;
1867687d0d8SRobert Mustacchi 	case PCIEADM_SDO_DID:
1877687d0d8SRobert Mustacchi 		if (psdo->psdo_did == -1) {
1887687d0d8SRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
1897687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "%x", psdo->psdo_did) >=
1907687d0d8SRobert Mustacchi 		    buflen) {
1917687d0d8SRobert Mustacchi 			return (B_FALSE);
1927687d0d8SRobert Mustacchi 		}
1937687d0d8SRobert Mustacchi 		break;
194bd97c7ceSRobert Mustacchi 	case PCIEADM_SDO_REV:
195bd97c7ceSRobert Mustacchi 		if (psdo->psdo_rev == -1) {
196bd97c7ceSRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
197bd97c7ceSRobert Mustacchi 		} else if (snprintf(buf, buflen, "%x", psdo->psdo_rev) >=
198bd97c7ceSRobert Mustacchi 		    buflen) {
199bd97c7ceSRobert Mustacchi 			return (B_FALSE);
200bd97c7ceSRobert Mustacchi 		}
201bd97c7ceSRobert Mustacchi 		break;
202bd97c7ceSRobert Mustacchi 	case PCIEADM_SDO_SUBVID:
203bd97c7ceSRobert Mustacchi 		if (psdo->psdo_subvid == -1) {
204bd97c7ceSRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
205bd97c7ceSRobert Mustacchi 		} else if (snprintf(buf, buflen, "%x", psdo->psdo_subvid) >=
206bd97c7ceSRobert Mustacchi 		    buflen) {
207bd97c7ceSRobert Mustacchi 			return (B_FALSE);
208bd97c7ceSRobert Mustacchi 		}
209bd97c7ceSRobert Mustacchi 		break;
210bd97c7ceSRobert Mustacchi 	case PCIEADM_SDO_SUBSYS:
211bd97c7ceSRobert Mustacchi 		if (psdo->psdo_subsys == -1) {
212bd97c7ceSRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
213bd97c7ceSRobert Mustacchi 		} else if (snprintf(buf, buflen, "%x", psdo->psdo_subsys) >=
214bd97c7ceSRobert Mustacchi 		    buflen) {
215bd97c7ceSRobert Mustacchi 			return (B_FALSE);
216bd97c7ceSRobert Mustacchi 		}
217bd97c7ceSRobert Mustacchi 		break;
2187687d0d8SRobert Mustacchi 	case PCIEADM_SDO_VENDOR:
2197687d0d8SRobert Mustacchi 		if (strlcat(buf, psdo->psdo_vendor, buflen) >= buflen) {
2207687d0d8SRobert Mustacchi 			return (B_FALSE);
2217687d0d8SRobert Mustacchi 		}
2227687d0d8SRobert Mustacchi 		break;
2237687d0d8SRobert Mustacchi 	case PCIEADM_SDO_DEVICE:
2247687d0d8SRobert Mustacchi 		if (strlcat(buf, psdo->psdo_device, buflen) >= buflen) {
2257687d0d8SRobert Mustacchi 			return (B_FALSE);
2267687d0d8SRobert Mustacchi 		}
2277687d0d8SRobert Mustacchi 		break;
228bd97c7ceSRobert Mustacchi 	case PCIEADM_SDO_SUBVENDOR:
229bd97c7ceSRobert Mustacchi 		if (strlcat(buf, psdo->psdo_subvendor, buflen) >= buflen) {
230bd97c7ceSRobert Mustacchi 			return (B_FALSE);
231bd97c7ceSRobert Mustacchi 		}
232bd97c7ceSRobert Mustacchi 		break;
233bd97c7ceSRobert Mustacchi 	case PCIEADM_SDO_SUBSYSTEM:
234bd97c7ceSRobert Mustacchi 		if (strlcat(buf, psdo->psdo_subsystem, buflen) >= buflen) {
235bd97c7ceSRobert Mustacchi 			return (B_FALSE);
236bd97c7ceSRobert Mustacchi 		}
237bd97c7ceSRobert Mustacchi 		break;
2387687d0d8SRobert Mustacchi 	case PCIEADM_SDO_MAXWIDTH:
2397687d0d8SRobert Mustacchi 		if (psdo->psdo_mwidth <= 0) {
2407687d0d8SRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
2417687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "x%u", psdo->psdo_mwidth) >=
2427687d0d8SRobert Mustacchi 		    buflen) {
2437687d0d8SRobert Mustacchi 			return (B_FALSE);
2447687d0d8SRobert Mustacchi 		}
2457687d0d8SRobert Mustacchi 		break;
2467687d0d8SRobert Mustacchi 	case PCIEADM_SDO_CURWIDTH:
2477687d0d8SRobert Mustacchi 		if (psdo->psdo_cwidth <= 0) {
2487687d0d8SRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
2497687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "x%u", psdo->psdo_cwidth) >=
2507687d0d8SRobert Mustacchi 		    buflen) {
2517687d0d8SRobert Mustacchi 			return (B_FALSE);
2527687d0d8SRobert Mustacchi 		}
2537687d0d8SRobert Mustacchi 		break;
2547687d0d8SRobert Mustacchi 	case PCIEADM_SDO_MAXSPEED:
2557687d0d8SRobert Mustacchi 		str = pcieadm_speed2str(psdo->psdo_mspeed);
2567687d0d8SRobert Mustacchi 		if (str == NULL) {
2577687d0d8SRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
2587687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "%s GT/s", str) >= buflen) {
2597687d0d8SRobert Mustacchi 			return (B_FALSE);
2607687d0d8SRobert Mustacchi 		}
2617687d0d8SRobert Mustacchi 		break;
2627687d0d8SRobert Mustacchi 	case PCIEADM_SDO_CURSPEED:
2637687d0d8SRobert Mustacchi 		str = pcieadm_speed2str(psdo->psdo_cspeed);
2647687d0d8SRobert Mustacchi 		if (str == NULL) {
2657687d0d8SRobert Mustacchi 			(void) strlcat(buf, "--", buflen);
2667687d0d8SRobert Mustacchi 		} else if (snprintf(buf, buflen, "%s GT/s", str) >= buflen) {
2677687d0d8SRobert Mustacchi 			return (B_FALSE);
2687687d0d8SRobert Mustacchi 		}
2697687d0d8SRobert Mustacchi 		break;
2707687d0d8SRobert Mustacchi 	case PCIEADM_SDO_SUPSPEEDS:
2717687d0d8SRobert Mustacchi 		buf[0] = 0;
2727687d0d8SRobert Mustacchi 		for (int i = 0; i < psdo->psdo_nspeeds; i++) {
2737687d0d8SRobert Mustacchi 			const char *str;
2747687d0d8SRobert Mustacchi 
2757687d0d8SRobert Mustacchi 			str = pcieadm_speed2str(psdo->psdo_sspeeds[i]);
2767687d0d8SRobert Mustacchi 			if (str == NULL) {
2777687d0d8SRobert Mustacchi 				continue;
2787687d0d8SRobert Mustacchi 			}
2797687d0d8SRobert Mustacchi 
2807687d0d8SRobert Mustacchi 			if (!first) {
2817687d0d8SRobert Mustacchi 				if (strlcat(buf, ",", buflen) >= buflen) {
2827687d0d8SRobert Mustacchi 					return (B_FALSE);
2837687d0d8SRobert Mustacchi 				}
2847687d0d8SRobert Mustacchi 			}
2857687d0d8SRobert Mustacchi 			first = B_FALSE;
2867687d0d8SRobert Mustacchi 
2877687d0d8SRobert Mustacchi 			if (strlcat(buf, str, buflen) >= buflen) {
2887687d0d8SRobert Mustacchi 				return (B_FALSE);
2897687d0d8SRobert Mustacchi 			}
2907687d0d8SRobert Mustacchi 		}
2917687d0d8SRobert Mustacchi 		break;
2927687d0d8SRobert Mustacchi 	case PCIEADM_SDO_TYPE:
293a68304ebSRobert Mustacchi 		if (pcieadm_speed2gen(psdo->psdo_cspeed) == 0 ||
2947687d0d8SRobert Mustacchi 		    psdo->psdo_mwidth == -1) {
2957687d0d8SRobert Mustacchi 			if (strlcat(buf, "PCI", buflen) >= buflen) {
2967687d0d8SRobert Mustacchi 				return (B_FALSE);
2977687d0d8SRobert Mustacchi 			}
2987687d0d8SRobert Mustacchi 		} else {
2997687d0d8SRobert Mustacchi 			if (snprintf(buf, buflen, "PCIe Gen %ux%u",
300a68304ebSRobert Mustacchi 			    pcieadm_speed2gen(psdo->psdo_cspeed),
301a68304ebSRobert Mustacchi 			    psdo->psdo_cwidth) >= buflen) {
3027687d0d8SRobert Mustacchi 				return (B_FALSE);
3037687d0d8SRobert Mustacchi 			}
3047687d0d8SRobert Mustacchi 		}
3057687d0d8SRobert Mustacchi 		break;
3067687d0d8SRobert Mustacchi 	default:
3077687d0d8SRobert Mustacchi 		abort();
3087687d0d8SRobert Mustacchi 	}
3097687d0d8SRobert Mustacchi 	return (B_TRUE);
3107687d0d8SRobert Mustacchi }
3117687d0d8SRobert Mustacchi 
31276c08ae9SRobert Mustacchi static const char *pcieadm_show_dev_fields = "bdf,type,instance,device";
3137687d0d8SRobert Mustacchi static const char *pcieadm_show_dev_speeds =
3147687d0d8SRobert Mustacchi 	"bdf,driver,maxspeed,curspeed,maxwidth,curwidth,supspeeds";
3157687d0d8SRobert Mustacchi static const ofmt_field_t pcieadm_show_dev_ofmt[] = {
3167687d0d8SRobert Mustacchi 	{ "VID", 6, PCIEADM_SDO_VID, pcieadm_show_devs_ofmt_cb },
3177687d0d8SRobert Mustacchi 	{ "DID", 6, PCIEADM_SDO_DID, pcieadm_show_devs_ofmt_cb },
318bd97c7ceSRobert Mustacchi 	{ "REV", 6, PCIEADM_SDO_REV, pcieadm_show_devs_ofmt_cb },
319bd97c7ceSRobert Mustacchi 	{ "SUBVID", 6, PCIEADM_SDO_SUBVID, pcieadm_show_devs_ofmt_cb },
320bd97c7ceSRobert Mustacchi 	{ "SUBSYS", 6, PCIEADM_SDO_SUBSYS, pcieadm_show_devs_ofmt_cb },
3217687d0d8SRobert Mustacchi 	{ "BDF", 8, PCIEADM_SDO_BDF, pcieadm_show_devs_ofmt_cb },
3227687d0d8SRobert Mustacchi 	{ "DRIVER", 15, PCIEADM_SDO_DRIVER, pcieadm_show_devs_ofmt_cb },
32376c08ae9SRobert Mustacchi 	{ "INSTANCE", 15, PCIEADM_SDO_INSTANCE, pcieadm_show_devs_ofmt_cb },
32476c08ae9SRobert Mustacchi 	{ "INSTNUM", 8, PCIEADM_SDO_INSTNUM, pcieadm_show_devs_ofmt_cb },
3257687d0d8SRobert Mustacchi 	{ "TYPE", 15, PCIEADM_SDO_TYPE, pcieadm_show_devs_ofmt_cb },
3267687d0d8SRobert Mustacchi 	{ "VENDOR", 30, PCIEADM_SDO_VENDOR, pcieadm_show_devs_ofmt_cb },
3277687d0d8SRobert Mustacchi 	{ "DEVICE", 30, PCIEADM_SDO_DEVICE, pcieadm_show_devs_ofmt_cb },
328bd97c7ceSRobert Mustacchi 	{ "SUBVENDOR", 30, PCIEADM_SDO_SUBVENDOR, pcieadm_show_devs_ofmt_cb },
329bd97c7ceSRobert Mustacchi 	{ "SUBSYSTEM", 30, PCIEADM_SDO_SUBSYSTEM, pcieadm_show_devs_ofmt_cb },
3307687d0d8SRobert Mustacchi 	{ "PATH", 30, PCIEADM_SDO_PATH, pcieadm_show_devs_ofmt_cb },
3317687d0d8SRobert Mustacchi 	{ "BUS", 4, PCIEADM_SDO_BDF_BUS, pcieadm_show_devs_ofmt_cb },
3327687d0d8SRobert Mustacchi 	{ "DEV", 4, PCIEADM_SDO_BDF_DEV, pcieadm_show_devs_ofmt_cb },
3337687d0d8SRobert Mustacchi 	{ "FUNC", 4, PCIEADM_SDO_BDF_FUNC, pcieadm_show_devs_ofmt_cb },
3347687d0d8SRobert Mustacchi 	{ "MAXSPEED", 10, PCIEADM_SDO_MAXSPEED, pcieadm_show_devs_ofmt_cb },
3357687d0d8SRobert Mustacchi 	{ "MAXWIDTH", 10, PCIEADM_SDO_MAXWIDTH, pcieadm_show_devs_ofmt_cb },
3367687d0d8SRobert Mustacchi 	{ "CURSPEED", 10, PCIEADM_SDO_CURSPEED, pcieadm_show_devs_ofmt_cb },
3377687d0d8SRobert Mustacchi 	{ "CURWIDTH", 10, PCIEADM_SDO_CURWIDTH, pcieadm_show_devs_ofmt_cb },
3387687d0d8SRobert Mustacchi 	{ "SUPSPEEDS", 20, PCIEADM_SDO_SUPSPEEDS, pcieadm_show_devs_ofmt_cb },
3397687d0d8SRobert Mustacchi 	{ NULL, 0, 0, NULL }
3407687d0d8SRobert Mustacchi };
3417687d0d8SRobert Mustacchi 
3427687d0d8SRobert Mustacchi static boolean_t
pcieadm_show_devs_match(pcieadm_show_devs_t * psd,pcieadm_show_devs_ofmt_t * psdo)3437687d0d8SRobert Mustacchi pcieadm_show_devs_match(pcieadm_show_devs_t *psd,
3447687d0d8SRobert Mustacchi     pcieadm_show_devs_ofmt_t *psdo)
3457687d0d8SRobert Mustacchi {
3467687d0d8SRobert Mustacchi 	char dinst[128], bdf[128];
3477687d0d8SRobert Mustacchi 
3487687d0d8SRobert Mustacchi 	if (psd->psd_nfilts == 0) {
3497687d0d8SRobert Mustacchi 		return (B_TRUE);
3507687d0d8SRobert Mustacchi 	}
3517687d0d8SRobert Mustacchi 
3527687d0d8SRobert Mustacchi 	if (psdo->psdo_driver != NULL && psdo->psdo_instance != -1) {
3537687d0d8SRobert Mustacchi 		(void) snprintf(dinst, sizeof (dinst), "%s%d",
3547687d0d8SRobert Mustacchi 		    psdo->psdo_driver, psdo->psdo_instance);
3557687d0d8SRobert Mustacchi 	}
3567687d0d8SRobert Mustacchi 	(void) snprintf(bdf, sizeof (bdf), "%x/%x/%x", psdo->psdo_bus,
3577687d0d8SRobert Mustacchi 	    psdo->psdo_dev, psdo->psdo_func);
3587687d0d8SRobert Mustacchi 
3597687d0d8SRobert Mustacchi 	for (uint_t i = 0; i < psd->psd_nfilts; i++) {
3607687d0d8SRobert Mustacchi 		const char *filt = psd->psd_filts[i];
3617687d0d8SRobert Mustacchi 
3627687d0d8SRobert Mustacchi 		if (strcmp(filt, psdo->psdo_path) == 0) {
36392f11af9SRobert Mustacchi 			psd->psd_used[i] = B_TRUE;
3647687d0d8SRobert Mustacchi 			return (B_TRUE);
3657687d0d8SRobert Mustacchi 		}
3667687d0d8SRobert Mustacchi 
3677687d0d8SRobert Mustacchi 		if (strcmp(filt, bdf) == 0) {
36892f11af9SRobert Mustacchi 			psd->psd_used[i] = B_TRUE;
3697687d0d8SRobert Mustacchi 			return (B_TRUE);
3707687d0d8SRobert Mustacchi 		}
3717687d0d8SRobert Mustacchi 
3727687d0d8SRobert Mustacchi 		if (psdo->psdo_driver != NULL &&
3737687d0d8SRobert Mustacchi 		    strcmp(filt, psdo->psdo_driver) == 0) {
37492f11af9SRobert Mustacchi 			psd->psd_used[i] = B_TRUE;
3757687d0d8SRobert Mustacchi 			return (B_TRUE);
3767687d0d8SRobert Mustacchi 		}
3777687d0d8SRobert Mustacchi 
3787687d0d8SRobert Mustacchi 		if (psdo->psdo_driver != NULL && psdo->psdo_instance != -1 &&
3797687d0d8SRobert Mustacchi 		    strcmp(filt, dinst) == 0) {
38092f11af9SRobert Mustacchi 			psd->psd_used[i] = B_TRUE;
3817687d0d8SRobert Mustacchi 			return (B_TRUE);
3827687d0d8SRobert Mustacchi 		}
3837687d0d8SRobert Mustacchi 
3847687d0d8SRobert Mustacchi 		if (strncmp("/devices", filt, strlen("/devices")) == 0) {
3857687d0d8SRobert Mustacchi 			filt += strlen("/devices");
3867687d0d8SRobert Mustacchi 		}
3877687d0d8SRobert Mustacchi 
3887687d0d8SRobert Mustacchi 		if (strcmp(filt, psdo->psdo_path) == 0) {
38992f11af9SRobert Mustacchi 			psd->psd_used[i] = B_TRUE;
3907687d0d8SRobert Mustacchi 			return (B_TRUE);
3917687d0d8SRobert Mustacchi 		}
3927687d0d8SRobert Mustacchi 	}
3937687d0d8SRobert Mustacchi 	return (B_FALSE);
3947687d0d8SRobert Mustacchi }
3957687d0d8SRobert Mustacchi 
3967687d0d8SRobert Mustacchi static int
pcieadm_show_devs_walk_cb(di_node_t node,void * arg)3977687d0d8SRobert Mustacchi pcieadm_show_devs_walk_cb(di_node_t node, void *arg)
3987687d0d8SRobert Mustacchi {
399bd97c7ceSRobert Mustacchi 	int nprop, *regs = NULL, *did, *vid, *mwidth, *cwidth, *rev;
400bd97c7ceSRobert Mustacchi 	int *subvid, *subsys;
4017687d0d8SRobert Mustacchi 	int64_t *mspeed, *cspeed, *sspeeds;
4027687d0d8SRobert Mustacchi 	char *path = NULL;
4037687d0d8SRobert Mustacchi 	pcieadm_show_devs_t *psd = arg;
4047687d0d8SRobert Mustacchi 	int ret = DI_WALK_CONTINUE;
405bd97c7ceSRobert Mustacchi 	char venstr[64], devstr[64], subvenstr[64], subsysstr[64];
4067687d0d8SRobert Mustacchi 	pcieadm_show_devs_ofmt_t oarg;
4077687d0d8SRobert Mustacchi 	pcidb_hdl_t *pcidb = psd->psd_pia->pia_pcidb;
4087687d0d8SRobert Mustacchi 
4097687d0d8SRobert Mustacchi 	bzero(&oarg, sizeof (oarg));
4107687d0d8SRobert Mustacchi 
4117687d0d8SRobert Mustacchi 	path = di_devfs_path(node);
4127687d0d8SRobert Mustacchi 	if (path == NULL) {
4137687d0d8SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct devfs path for node: "
414*6b1325cfSRobert Mustacchi 		    "%s", di_node_name(node));
4157687d0d8SRobert Mustacchi 	}
4167687d0d8SRobert Mustacchi 
4177687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regs);
4187687d0d8SRobert Mustacchi 	if (nprop <= 0) {
4197687d0d8SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to lookup regs array for %s",
4207687d0d8SRobert Mustacchi 		    path);
4217687d0d8SRobert Mustacchi 	}
4227687d0d8SRobert Mustacchi 
4237687d0d8SRobert Mustacchi 	oarg.psdo_path = path;
4247687d0d8SRobert Mustacchi 	oarg.psdo_bus = PCI_REG_BUS_G(regs[0]);
4257687d0d8SRobert Mustacchi 	oarg.psdo_dev = PCI_REG_DEV_G(regs[0]);
4267687d0d8SRobert Mustacchi 	oarg.psdo_func = PCI_REG_FUNC_G(regs[0]);
4277687d0d8SRobert Mustacchi 
4287687d0d8SRobert Mustacchi 	if (oarg.psdo_func != 0 && !psd->psd_funcs) {
4297687d0d8SRobert Mustacchi 		goto done;
4307687d0d8SRobert Mustacchi 	}
4317687d0d8SRobert Mustacchi 
4327687d0d8SRobert Mustacchi 	oarg.psdo_driver = di_driver_name(node);
4337687d0d8SRobert Mustacchi 	oarg.psdo_instance = di_instance(node);
4347687d0d8SRobert Mustacchi 
4357687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &did);
4367687d0d8SRobert Mustacchi 	if (nprop != 1) {
4377687d0d8SRobert Mustacchi 		oarg.psdo_did = -1;
4387687d0d8SRobert Mustacchi 	} else {
4397687d0d8SRobert Mustacchi 		oarg.psdo_did = (uint16_t)*did;
4407687d0d8SRobert Mustacchi 	}
4417687d0d8SRobert Mustacchi 
4427687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vid);
4437687d0d8SRobert Mustacchi 	if (nprop != 1) {
4447687d0d8SRobert Mustacchi 		oarg.psdo_vid = -1;
4457687d0d8SRobert Mustacchi 	} else {
4467687d0d8SRobert Mustacchi 		oarg.psdo_vid = (uint16_t)*vid;
4477687d0d8SRobert Mustacchi 	}
4487687d0d8SRobert Mustacchi 
449bd97c7ceSRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "revision-id", &rev);
450bd97c7ceSRobert Mustacchi 	if (nprop != 1) {
451bd97c7ceSRobert Mustacchi 		oarg.psdo_rev = -1;
452bd97c7ceSRobert Mustacchi 	} else {
453bd97c7ceSRobert Mustacchi 		oarg.psdo_rev = (uint16_t)*rev;
454bd97c7ceSRobert Mustacchi 	}
455bd97c7ceSRobert Mustacchi 
456bd97c7ceSRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "subsystem-vendor-id",
457bd97c7ceSRobert Mustacchi 	    &subvid);
458bd97c7ceSRobert Mustacchi 	if (nprop != 1) {
459bd97c7ceSRobert Mustacchi 		oarg.psdo_subvid = -1;
460bd97c7ceSRobert Mustacchi 	} else {
461bd97c7ceSRobert Mustacchi 		oarg.psdo_subvid = (uint16_t)*subvid;
462bd97c7ceSRobert Mustacchi 	}
463bd97c7ceSRobert Mustacchi 
464bd97c7ceSRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "subsystem-id",
465bd97c7ceSRobert Mustacchi 	    &subsys);
466bd97c7ceSRobert Mustacchi 	if (nprop != 1) {
467bd97c7ceSRobert Mustacchi 		oarg.psdo_subsys = -1;
468bd97c7ceSRobert Mustacchi 	} else {
469bd97c7ceSRobert Mustacchi 		oarg.psdo_subsys = (uint16_t)*subsys;
470bd97c7ceSRobert Mustacchi 	}
471bd97c7ceSRobert Mustacchi 
4727687d0d8SRobert Mustacchi 	oarg.psdo_vendor = "--";
4737687d0d8SRobert Mustacchi 	if (oarg.psdo_vid != -1) {
4747687d0d8SRobert Mustacchi 		pcidb_vendor_t *vend = pcidb_lookup_vendor(pcidb,
4757687d0d8SRobert Mustacchi 		    oarg.psdo_vid);
4767687d0d8SRobert Mustacchi 		if (vend != NULL) {
4777687d0d8SRobert Mustacchi 			oarg.psdo_vendor = pcidb_vendor_name(vend);
478bc729d49SRobert Mustacchi 		} else {
479bc729d49SRobert Mustacchi 			(void) snprintf(venstr, sizeof (venstr),
480bc729d49SRobert Mustacchi 			    "Unknown vendor: 0x%x", oarg.psdo_vid);
481bc729d49SRobert Mustacchi 			oarg.psdo_vendor = venstr;
4827687d0d8SRobert Mustacchi 		}
4837687d0d8SRobert Mustacchi 	}
4847687d0d8SRobert Mustacchi 
4857687d0d8SRobert Mustacchi 	oarg.psdo_device = "--";
4867687d0d8SRobert Mustacchi 	if (oarg.psdo_vid != -1 && oarg.psdo_did != -1) {
4877687d0d8SRobert Mustacchi 		pcidb_device_t *dev = pcidb_lookup_device(pcidb,
4887687d0d8SRobert Mustacchi 		    oarg.psdo_vid, oarg.psdo_did);
4897687d0d8SRobert Mustacchi 		if (dev != NULL) {
4907687d0d8SRobert Mustacchi 			oarg.psdo_device = pcidb_device_name(dev);
491bc729d49SRobert Mustacchi 		} else {
492bc729d49SRobert Mustacchi 			(void) snprintf(devstr, sizeof (devstr),
493bc729d49SRobert Mustacchi 			    "Unknown device: 0x%x", oarg.psdo_did);
494bc729d49SRobert Mustacchi 			oarg.psdo_device = devstr;
4957687d0d8SRobert Mustacchi 		}
4967687d0d8SRobert Mustacchi 	}
4977687d0d8SRobert Mustacchi 
498bd97c7ceSRobert Mustacchi 	/*
499bd97c7ceSRobert Mustacchi 	 * The pci.ids database organizes subsystems under devices. We look at
500bd97c7ceSRobert Mustacchi 	 * the subsystem vendor separately because even if the device or other
501bd97c7ceSRobert Mustacchi 	 * information is not known, we may still be able to figure out what it
502bd97c7ceSRobert Mustacchi 	 * is.
503bd97c7ceSRobert Mustacchi 	 */
504bd97c7ceSRobert Mustacchi 	oarg.psdo_subvendor = "--";
505bd97c7ceSRobert Mustacchi 	oarg.psdo_subsystem = "--";
506bd97c7ceSRobert Mustacchi 	if (oarg.psdo_subvid != -1) {
507bd97c7ceSRobert Mustacchi 		pcidb_vendor_t *vend = pcidb_lookup_vendor(pcidb,
508bd97c7ceSRobert Mustacchi 		    oarg.psdo_subvid);
509bd97c7ceSRobert Mustacchi 		if (vend != NULL) {
510bd97c7ceSRobert Mustacchi 			oarg.psdo_subvendor = pcidb_vendor_name(vend);
511bd97c7ceSRobert Mustacchi 		} else {
512bd97c7ceSRobert Mustacchi 			(void) snprintf(subvenstr, sizeof (subvenstr),
513bd97c7ceSRobert Mustacchi 			    "Unknown vendor: 0x%x", oarg.psdo_vid);
514bd97c7ceSRobert Mustacchi 			oarg.psdo_subvendor = subvenstr;
515bd97c7ceSRobert Mustacchi 		}
516bd97c7ceSRobert Mustacchi 	}
517bd97c7ceSRobert Mustacchi 
518bd97c7ceSRobert Mustacchi 	if (oarg.psdo_vid != -1 && oarg.psdo_did != -1 &&
519bd97c7ceSRobert Mustacchi 	    oarg.psdo_subvid != -1 && oarg.psdo_subsys != -1) {
520bd97c7ceSRobert Mustacchi 		pcidb_subvd_t *subvd = pcidb_lookup_subvd(pcidb, oarg.psdo_vid,
521bd97c7ceSRobert Mustacchi 		    oarg.psdo_did, oarg.psdo_subvid, oarg.psdo_subsys);
522bd97c7ceSRobert Mustacchi 		if (subvd != NULL) {
523bd97c7ceSRobert Mustacchi 			oarg.psdo_subsystem = pcidb_subvd_name(subvd);
524bd97c7ceSRobert Mustacchi 		} else {
525bd97c7ceSRobert Mustacchi 			(void) snprintf(subsysstr, sizeof (subsysstr),
526bd97c7ceSRobert Mustacchi 			    "Unknown subsystem: 0x%x", oarg.psdo_subsys);
527bd97c7ceSRobert Mustacchi 			oarg.psdo_subsystem = subsysstr;
528bd97c7ceSRobert Mustacchi 		}
529bd97c7ceSRobert Mustacchi 	}
530bd97c7ceSRobert Mustacchi 
531bd97c7ceSRobert Mustacchi 
5327687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
5337687d0d8SRobert Mustacchi 	    "pcie-link-maximum-width", &mwidth);
5347687d0d8SRobert Mustacchi 	if (nprop != 1) {
5357687d0d8SRobert Mustacchi 		oarg.psdo_mwidth = -1;
5367687d0d8SRobert Mustacchi 	} else {
5377687d0d8SRobert Mustacchi 		oarg.psdo_mwidth = *mwidth;
5387687d0d8SRobert Mustacchi 	}
5397687d0d8SRobert Mustacchi 
5407687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
5417687d0d8SRobert Mustacchi 	    "pcie-link-current-width", &cwidth);
5427687d0d8SRobert Mustacchi 	if (nprop != 1) {
5437687d0d8SRobert Mustacchi 		oarg.psdo_cwidth = -1;
5447687d0d8SRobert Mustacchi 	} else {
5457687d0d8SRobert Mustacchi 		oarg.psdo_cwidth = *cwidth;
5467687d0d8SRobert Mustacchi 	}
5477687d0d8SRobert Mustacchi 
5487687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, node,
5497687d0d8SRobert Mustacchi 	    "pcie-link-maximum-speed", &mspeed);
5507687d0d8SRobert Mustacchi 	if (nprop != 1) {
5517687d0d8SRobert Mustacchi 		oarg.psdo_mspeed = -1;
5527687d0d8SRobert Mustacchi 	} else {
5537687d0d8SRobert Mustacchi 		oarg.psdo_mspeed = *mspeed;
5547687d0d8SRobert Mustacchi 	}
5557687d0d8SRobert Mustacchi 
5567687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, node,
5577687d0d8SRobert Mustacchi 	    "pcie-link-current-speed", &cspeed);
5587687d0d8SRobert Mustacchi 	if (nprop != 1) {
5597687d0d8SRobert Mustacchi 		oarg.psdo_cspeed = -1;
5607687d0d8SRobert Mustacchi 	} else {
5617687d0d8SRobert Mustacchi 		oarg.psdo_cspeed = *cspeed;
5627687d0d8SRobert Mustacchi 	}
5637687d0d8SRobert Mustacchi 
5647687d0d8SRobert Mustacchi 	nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, node,
5657687d0d8SRobert Mustacchi 	    "pcie-link-supported-speeds", &sspeeds);
5667687d0d8SRobert Mustacchi 	if (nprop > 0) {
5677687d0d8SRobert Mustacchi 		oarg.psdo_nspeeds = nprop;
5687687d0d8SRobert Mustacchi 		oarg.psdo_sspeeds = sspeeds;
5697687d0d8SRobert Mustacchi 	} else {
5707687d0d8SRobert Mustacchi 		oarg.psdo_nspeeds = 0;
5717687d0d8SRobert Mustacchi 		oarg.psdo_sspeeds = NULL;
5727687d0d8SRobert Mustacchi 	}
5737687d0d8SRobert Mustacchi 
5747687d0d8SRobert Mustacchi 	if (pcieadm_show_devs_match(psd, &oarg)) {
5757687d0d8SRobert Mustacchi 		ofmt_print(psd->psd_ofmt, &oarg);
5767687d0d8SRobert Mustacchi 		psd->psd_nprint++;
5777687d0d8SRobert Mustacchi 	}
5787687d0d8SRobert Mustacchi 
5797687d0d8SRobert Mustacchi done:
5807687d0d8SRobert Mustacchi 	if (path != NULL) {
5817687d0d8SRobert Mustacchi 		di_devfs_path_free(path);
5827687d0d8SRobert Mustacchi 	}
5837687d0d8SRobert Mustacchi 
5847687d0d8SRobert Mustacchi 	return (ret);
5857687d0d8SRobert Mustacchi }
5867687d0d8SRobert Mustacchi 
5877687d0d8SRobert Mustacchi void
pcieadm_show_devs_usage(FILE * f)5887687d0d8SRobert Mustacchi pcieadm_show_devs_usage(FILE *f)
5897687d0d8SRobert Mustacchi {
5907687d0d8SRobert Mustacchi 	(void) fprintf(f, "\tshow-devs\t[-F] [-H] [-s | -o field[,...] [-p]] "
5917687d0d8SRobert Mustacchi 	    "[filter...]\n");
5927687d0d8SRobert Mustacchi }
5937687d0d8SRobert Mustacchi 
5947687d0d8SRobert Mustacchi static void
pcieadm_show_devs_help(const char * fmt,...)5957687d0d8SRobert Mustacchi pcieadm_show_devs_help(const char *fmt, ...)
5967687d0d8SRobert Mustacchi {
5977687d0d8SRobert Mustacchi 	if (fmt != NULL) {
5987687d0d8SRobert Mustacchi 		va_list ap;
5997687d0d8SRobert Mustacchi 
6007687d0d8SRobert Mustacchi 		va_start(ap, fmt);
6017687d0d8SRobert Mustacchi 		vwarnx(fmt, ap);
6027687d0d8SRobert Mustacchi 		va_end(ap);
6037687d0d8SRobert Mustacchi 		(void) fprintf(stderr, "\n");
6047687d0d8SRobert Mustacchi 	}
6057687d0d8SRobert Mustacchi 
6067687d0d8SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  %s show-devs [-F] [-H] [-s | -o "
6077687d0d8SRobert Mustacchi 	    "field[,...] [-p]] [filter...]\n", pcieadm_progname);
6087687d0d8SRobert Mustacchi 
6097687d0d8SRobert Mustacchi 	(void) fprintf(stderr, "\nList PCI devices and functions in the "
6107687d0d8SRobert Mustacchi 	    "system. Each <filter> selects a set\nof devices to show and "
6117687d0d8SRobert Mustacchi 	    "can be a driver name, instance, /devices path, or\nb/d/f.\n\n"
6127687d0d8SRobert Mustacchi 	    "\t-F\t\tdo not display PCI functions\n"
6137687d0d8SRobert Mustacchi 	    "\t-H\t\tomit the column header\n"
6147687d0d8SRobert Mustacchi 	    "\t-o field\toutput fields to print\n"
6157687d0d8SRobert Mustacchi 	    "\t-p\t\tparsable output (requires -o)\n"
61676c08ae9SRobert Mustacchi 	    "\t-s\t\tlist speeds and widths\n\n"
61776c08ae9SRobert Mustacchi 	    "The following fields are supported:\n"
61876c08ae9SRobert Mustacchi 	    "\tvid\t\tthe PCI vendor ID in hex\n"
61976c08ae9SRobert Mustacchi 	    "\tdid\t\tthe PCI device ID in hex\n"
620bd97c7ceSRobert Mustacchi 	    "\trev\t\tthe PCI device revision in hex\n"
621bd97c7ceSRobert Mustacchi 	    "\tsubvid\t\tthe PCI subsystem vendor ID in hex\n"
622bd97c7ceSRobert Mustacchi 	    "\tsubsys\t\tthe PCI subsystem ID in hex\n"
62376c08ae9SRobert Mustacchi 	    "\tvendor\t\tthe name of the PCI vendor\n"
62476c08ae9SRobert Mustacchi 	    "\tdevice\t\tthe name of the PCI device\n"
625bd97c7ceSRobert Mustacchi 	    "\tsubvendor\t\tthe name of the PCI subsystem vendor\n"
626bd97c7ceSRobert Mustacchi 	    "\tsubsystem\t\tthe name of the PCI subsystem\n"
62776c08ae9SRobert Mustacchi 	    "\tinstance\tthe name of this particular instance, e.g. igb0\n"
62876c08ae9SRobert Mustacchi 	    "\tdriver\t\tthe name of the driver attached to the device\n"
62976c08ae9SRobert Mustacchi 	    "\tinstnum\t\tthe instance number of a device, e.g. 2 for nvme2\n"
63076c08ae9SRobert Mustacchi 	    "\tpath\t\tthe /devices path of the device\n"
63176c08ae9SRobert Mustacchi 	    "\tbdf\t\tthe PCI bus/device/function, with values in hex\n"
63276c08ae9SRobert Mustacchi 	    "\tbus\t\tthe PCI bus number of the device in hex\n"
63376c08ae9SRobert Mustacchi 	    "\tdev\t\tthe PCI device number of the device in hex\n"
63476c08ae9SRobert Mustacchi 	    "\tfunc\t\tthe PCI function number of the device in hex\n"
63576c08ae9SRobert Mustacchi 	    "\ttype\t\ta string describing the PCIe generation and width\n"
63676c08ae9SRobert Mustacchi 	    "\tmaxspeed\tthe maximum supported PCIe speed of the device\n"
63776c08ae9SRobert Mustacchi 	    "\tcurspeed\tthe current PCIe speed of the device\n"
63876c08ae9SRobert Mustacchi 	    "\tmaxwidth\tthe maximum supported PCIe lane count of the device\n"
63976c08ae9SRobert Mustacchi 	    "\tcurwidth\tthe current lane count of the PCIe device\n"
64076c08ae9SRobert Mustacchi 	    "\tsupspeeds\tthe list of speeds the device supports\n");
6417687d0d8SRobert Mustacchi }
6427687d0d8SRobert Mustacchi 
6437687d0d8SRobert Mustacchi int
pcieadm_show_devs(pcieadm_t * pcip,int argc,char * argv[])6447687d0d8SRobert Mustacchi pcieadm_show_devs(pcieadm_t *pcip, int argc, char *argv[])
6457687d0d8SRobert Mustacchi {
64692f11af9SRobert Mustacchi 	int c, ret;
6477687d0d8SRobert Mustacchi 	uint_t flags = 0;
6487687d0d8SRobert Mustacchi 	const char *fields = NULL;
6497687d0d8SRobert Mustacchi 	pcieadm_show_devs_t psd;
6507687d0d8SRobert Mustacchi 	pcieadm_di_walk_t walk;
6517687d0d8SRobert Mustacchi 	ofmt_status_t oferr;
6527687d0d8SRobert Mustacchi 	boolean_t parse = B_FALSE;
6537687d0d8SRobert Mustacchi 	boolean_t speeds = B_FALSE;
6547687d0d8SRobert Mustacchi 
6557687d0d8SRobert Mustacchi 	/*
6567687d0d8SRobert Mustacchi 	 * show-devs relies solely on the devinfo snapshot we already took.
6577687d0d8SRobert Mustacchi 	 * Formalize our privs immediately.
6587687d0d8SRobert Mustacchi 	 */
6597687d0d8SRobert Mustacchi 	pcieadm_init_privs(pcip);
6607687d0d8SRobert Mustacchi 
6617687d0d8SRobert Mustacchi 	bzero(&psd, sizeof (psd));
6627687d0d8SRobert Mustacchi 	psd.psd_pia = pcip;
6637687d0d8SRobert Mustacchi 	psd.psd_funcs = B_TRUE;
6647687d0d8SRobert Mustacchi 
6657687d0d8SRobert Mustacchi 	while ((c = getopt(argc, argv, ":FHo:ps")) != -1) {
6667687d0d8SRobert Mustacchi 		switch (c) {
6677687d0d8SRobert Mustacchi 		case 'F':
6687687d0d8SRobert Mustacchi 			psd.psd_funcs = B_FALSE;
6697687d0d8SRobert Mustacchi 			break;
6707687d0d8SRobert Mustacchi 		case 'p':
6717687d0d8SRobert Mustacchi 			parse = B_TRUE;
6727687d0d8SRobert Mustacchi 			flags |= OFMT_PARSABLE;
6737687d0d8SRobert Mustacchi 			break;
6747687d0d8SRobert Mustacchi 		case 'H':
6757687d0d8SRobert Mustacchi 			flags |= OFMT_NOHEADER;
6767687d0d8SRobert Mustacchi 			break;
6777687d0d8SRobert Mustacchi 		case 's':
6787687d0d8SRobert Mustacchi 			speeds = B_TRUE;
6797687d0d8SRobert Mustacchi 			break;
6807687d0d8SRobert Mustacchi 		case 'o':
6817687d0d8SRobert Mustacchi 			fields = optarg;
6827687d0d8SRobert Mustacchi 			break;
6837687d0d8SRobert Mustacchi 		case ':':
6847687d0d8SRobert Mustacchi 			pcieadm_show_devs_help("option -%c requires an "
6857687d0d8SRobert Mustacchi 			    "argument", optopt);
6867687d0d8SRobert Mustacchi 			exit(EXIT_USAGE);
6877687d0d8SRobert Mustacchi 		case '?':
6887687d0d8SRobert Mustacchi 			pcieadm_show_devs_help("unknown option: -%c", optopt);
6897687d0d8SRobert Mustacchi 			exit(EXIT_USAGE);
6907687d0d8SRobert Mustacchi 		}
6917687d0d8SRobert Mustacchi 	}
6927687d0d8SRobert Mustacchi 
6937687d0d8SRobert Mustacchi 	if (parse && fields == NULL) {
6947687d0d8SRobert Mustacchi 		errx(EXIT_USAGE, "-p requires fields specified with -o");
6957687d0d8SRobert Mustacchi 	}
6967687d0d8SRobert Mustacchi 
6977687d0d8SRobert Mustacchi 	if (fields != NULL && speeds) {
6987687d0d8SRobert Mustacchi 		errx(EXIT_USAGE, "-s cannot be used with with -o");
6997687d0d8SRobert Mustacchi 	}
7007687d0d8SRobert Mustacchi 
7017687d0d8SRobert Mustacchi 	if (fields == NULL) {
7027687d0d8SRobert Mustacchi 		if (speeds) {
7037687d0d8SRobert Mustacchi 			fields = pcieadm_show_dev_speeds;
7047687d0d8SRobert Mustacchi 		} else {
7057687d0d8SRobert Mustacchi 			fields = pcieadm_show_dev_fields;
7067687d0d8SRobert Mustacchi 		}
7077687d0d8SRobert Mustacchi 	}
7087687d0d8SRobert Mustacchi 
7097687d0d8SRobert Mustacchi 	argc -= optind;
7107687d0d8SRobert Mustacchi 	argv += optind;
7117687d0d8SRobert Mustacchi 
7127687d0d8SRobert Mustacchi 	if (argc > 0) {
7137687d0d8SRobert Mustacchi 		psd.psd_nfilts = argc;
7147687d0d8SRobert Mustacchi 		psd.psd_filts = argv;
71592f11af9SRobert Mustacchi 		psd.psd_used = calloc(argc, sizeof (boolean_t));
71692f11af9SRobert Mustacchi 		if (psd.psd_used == NULL) {
71792f11af9SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate filter tracking "
71892f11af9SRobert Mustacchi 			    "memory");
71992f11af9SRobert Mustacchi 		}
7207687d0d8SRobert Mustacchi 	}
7217687d0d8SRobert Mustacchi 
7227687d0d8SRobert Mustacchi 	oferr = ofmt_open(fields, pcieadm_show_dev_ofmt, flags, 0,
7237687d0d8SRobert Mustacchi 	    &psd.psd_ofmt);
7247687d0d8SRobert Mustacchi 	ofmt_check(oferr, parse, psd.psd_ofmt, pcieadm_ofmt_errx, warnx);
7257687d0d8SRobert Mustacchi 
7267687d0d8SRobert Mustacchi 	walk.pdw_arg = &psd;
7277687d0d8SRobert Mustacchi 	walk.pdw_func = pcieadm_show_devs_walk_cb;
7287687d0d8SRobert Mustacchi 
7297687d0d8SRobert Mustacchi 	pcieadm_di_walk(pcip, &walk);
7307687d0d8SRobert Mustacchi 
73192f11af9SRobert Mustacchi 	ret = EXIT_SUCCESS;
73292f11af9SRobert Mustacchi 	for (int i = 0; i < psd.psd_nfilts; i++) {
73392f11af9SRobert Mustacchi 		if (!psd.psd_used[i]) {
73492f11af9SRobert Mustacchi 			warnx("filter '%s' did not match any devices",
73592f11af9SRobert Mustacchi 			    psd.psd_filts[i]);
73692f11af9SRobert Mustacchi 			ret = EXIT_FAILURE;
73792f11af9SRobert Mustacchi 		}
7387687d0d8SRobert Mustacchi 	}
73992f11af9SRobert Mustacchi 
74092f11af9SRobert Mustacchi 	if (psd.psd_nprint == 0) {
74192f11af9SRobert Mustacchi 		ret = EXIT_FAILURE;
74292f11af9SRobert Mustacchi 	}
74392f11af9SRobert Mustacchi 
74492f11af9SRobert Mustacchi 	return (ret);
7457687d0d8SRobert Mustacchi }
746