xref: /titanic_53/usr/src/cmd/pcitool/pcitool.c (revision 269473047d747f7815af570197e4ef7322d3632c)
1d5ace945SErwin T Tsaur /*
2d5ace945SErwin T Tsaur  * CDDL HEADER START
3d5ace945SErwin T Tsaur  *
4d5ace945SErwin T Tsaur  * The contents of this file are subject to the terms of the
5d5ace945SErwin T Tsaur  * Common Development and Distribution License (the "License").
6d5ace945SErwin T Tsaur  * You may not use this file except in compliance with the License.
7d5ace945SErwin T Tsaur  *
8d5ace945SErwin T Tsaur  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d5ace945SErwin T Tsaur  * or http://www.opensolaris.org/os/licensing.
10d5ace945SErwin T Tsaur  * See the License for the specific language governing permissions
11d5ace945SErwin T Tsaur  * and limitations under the License.
12d5ace945SErwin T Tsaur  *
13d5ace945SErwin T Tsaur  * When distributing Covered Code, include this CDDL HEADER in each
14d5ace945SErwin T Tsaur  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d5ace945SErwin T Tsaur  * If applicable, add the following below this CDDL HEADER, with the
16d5ace945SErwin T Tsaur  * fields enclosed by brackets "[]" replaced with your own identifying
17d5ace945SErwin T Tsaur  * information: Portions Copyright [yyyy] [name of copyright owner]
18d5ace945SErwin T Tsaur  *
19d5ace945SErwin T Tsaur  * CDDL HEADER END
20d5ace945SErwin T Tsaur  */
21d5ace945SErwin T Tsaur /*
22d5ace945SErwin T Tsaur  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23d5ace945SErwin T Tsaur  * Use is subject to license terms.
24d5ace945SErwin T Tsaur  */
25d5ace945SErwin T Tsaur 
26d5ace945SErwin T Tsaur /* This file is the main module for the pcitool. */
27d5ace945SErwin T Tsaur 
28d5ace945SErwin T Tsaur #include <stdio.h>
29d5ace945SErwin T Tsaur #include <stdlib.h>
30d5ace945SErwin T Tsaur #include <unistd.h>
31d5ace945SErwin T Tsaur #include <sys/inttypes.h>
32d5ace945SErwin T Tsaur #include <signal.h>
33d5ace945SErwin T Tsaur #include <sys/types.h>
34d5ace945SErwin T Tsaur #include <sys/param.h>
35d5ace945SErwin T Tsaur #include <fcntl.h>
36d5ace945SErwin T Tsaur #include <strings.h>
37d5ace945SErwin T Tsaur #include <ctype.h>
38d5ace945SErwin T Tsaur #include <errno.h>
39d5ace945SErwin T Tsaur #include <libdevinfo.h>
40d5ace945SErwin T Tsaur #include <sys/sunddi.h>
41d5ace945SErwin T Tsaur 
42d5ace945SErwin T Tsaur #ifdef __x86
43d5ace945SErwin T Tsaur #include <sys/apic_ctlr.h>
44d5ace945SErwin T Tsaur #endif
45d5ace945SErwin T Tsaur 
46d5ace945SErwin T Tsaur #include <sys/pci.h>
47d5ace945SErwin T Tsaur #include <sys/pci_tools.h>
48d5ace945SErwin T Tsaur 
49d5ace945SErwin T Tsaur #include "pcitool_ui.h"
50d5ace945SErwin T Tsaur 
51d5ace945SErwin T Tsaur /* First 16 longs of device PCI config header. */
52d5ace945SErwin T Tsaur typedef union {
53d5ace945SErwin T Tsaur 	uint8_t bytes[16 * sizeof (uint32_t)];
54d5ace945SErwin T Tsaur 	uint32_t dwords[16];
55d5ace945SErwin T Tsaur } pci_conf_hdr_t;
56d5ace945SErwin T Tsaur 
57d5ace945SErwin T Tsaur /* Used by probe printing functions. */
58d5ace945SErwin T Tsaur typedef struct {
59d5ace945SErwin T Tsaur 	uint16_t cfg_offset;	/* Offset of data within config space. */
60d5ace945SErwin T Tsaur 	uint8_t size;		/* Size of desired data field. */
61d5ace945SErwin T Tsaur 	char *abbrev_hdr;	/* Abbreviated header for this data. */
62d5ace945SErwin T Tsaur 	char *full_hdr;		/* Full header for this data, verbose option. */
63d5ace945SErwin T Tsaur } field_type_t;
64d5ace945SErwin T Tsaur 
65d5ace945SErwin T Tsaur /* Used to package many args into one arg for probe di_node walk function. */
66d5ace945SErwin T Tsaur typedef struct {
67d5ace945SErwin T Tsaur 	pcitool_uiargs_t *input_args_p;
68d5ace945SErwin T Tsaur 	char *pathname;
69d5ace945SErwin T Tsaur 	di_prom_handle_t di_phdl;
70d5ace945SErwin T Tsaur } probe_walk_args_t;
71d5ace945SErwin T Tsaur 
72d5ace945SErwin T Tsaur /*
73d5ace945SErwin T Tsaur  * Read config space in native processor endianness.  Endian-neutral
74d5ace945SErwin T Tsaur  * processing can then take place.  On big endian machines, MSB and LSB
75d5ace945SErwin T Tsaur  * of little endian data end up switched if read as little endian.
76d5ace945SErwin T Tsaur  * They are in correct order if read as big endian.
77d5ace945SErwin T Tsaur  */
78d5ace945SErwin T Tsaur #if defined(__sparc)
79d5ace945SErwin T Tsaur #define	NATIVE_ENDIAN	PCITOOL_ACC_ATTR_ENDN_BIG
80d5ace945SErwin T Tsaur #elif defined(__x86)
81d5ace945SErwin T Tsaur #define	NATIVE_ENDIAN	PCITOOL_ACC_ATTR_ENDN_LTL
82d5ace945SErwin T Tsaur #else
83d5ace945SErwin T Tsaur #error "ISA is neither __sparc nor __x86"
84d5ace945SErwin T Tsaur #endif
85d5ace945SErwin T Tsaur 
86d5ace945SErwin T Tsaur /* status error lookup table. */
87d5ace945SErwin T Tsaur static struct {
88d5ace945SErwin T Tsaur 	pcitool_errno_t	value;
89d5ace945SErwin T Tsaur 	char		*string;
90d5ace945SErwin T Tsaur } pcitool_stat_str[] = {
91d5ace945SErwin T Tsaur 	{ PCITOOL_SUCCESS,
92d5ace945SErwin T Tsaur 		"No error status returned from driver" },
93d5ace945SErwin T Tsaur 	{ PCITOOL_INVALID_CPUID,
94d5ace945SErwin T Tsaur 		"CPU is non-existent or not online" },
95d5ace945SErwin T Tsaur 	{ PCITOOL_INVALID_INO,
96d5ace945SErwin T Tsaur 		"INO is out of range or invalid" },
9709b1eac2SEvan Yan 	{ PCITOOL_INVALID_MSI,
9809b1eac2SEvan Yan 		"MSI is out of range or invalid" },
99d5ace945SErwin T Tsaur 	{ PCITOOL_PENDING_INTRTIMEOUT,
100d5ace945SErwin T Tsaur 		"Timeout waiting for pending interrupts to clear" },
101d5ace945SErwin T Tsaur 	{ PCITOOL_REGPROP_NOTWELLFORMED,
102d5ace945SErwin T Tsaur 		"Reg property has invalid format" },
103d5ace945SErwin T Tsaur 	{ PCITOOL_INVALID_ADDRESS,
104d5ace945SErwin T Tsaur 		"Address out of range or invalid" },
105d5ace945SErwin T Tsaur 	{ PCITOOL_NOT_ALIGNED,
106d5ace945SErwin T Tsaur 		"Improper address alignment for access attempted" },
107d5ace945SErwin T Tsaur 	{ PCITOOL_OUT_OF_RANGE,
108d5ace945SErwin T Tsaur 		"Argument out of range" },
109d5ace945SErwin T Tsaur 	{ PCITOOL_END_OF_RANGE,
110d5ace945SErwin T Tsaur 		"End of address range" },
111d5ace945SErwin T Tsaur 	{ PCITOOL_ROM_DISABLED,
112d5ace945SErwin T Tsaur 		"Device ROM is disabled.  Cannot read" },
113d5ace945SErwin T Tsaur 	{ PCITOOL_ROM_WRITE,
114d5ace945SErwin T Tsaur 		"Write to ROM not allowed" },
115d5ace945SErwin T Tsaur 	{ PCITOOL_IO_ERROR,
116d5ace945SErwin T Tsaur 		"IO error encountered" },
117d5ace945SErwin T Tsaur 	{ PCITOOL_INVALID_SIZE,
118d5ace945SErwin T Tsaur 		"Size is invalid for this platform" },
119d5ace945SErwin T Tsaur 	{ 0, NULL }
120d5ace945SErwin T Tsaur };
121d5ace945SErwin T Tsaur 
122d5ace945SErwin T Tsaur 
123d5ace945SErwin T Tsaur /* Used with ^C handler to stop looping in repeat mode in do_device_or_nexus. */
124d5ace945SErwin T Tsaur static boolean_t keep_looping = B_TRUE;
125d5ace945SErwin T Tsaur 
126d5ace945SErwin T Tsaur static void signal_handler(int dummy);
127d5ace945SErwin T Tsaur static char *strstatus(pcitool_errno_t pcitool_status);
128d5ace945SErwin T Tsaur static int open_node(char *device, pcitool_uiargs_t *input_args_p);
129d5ace945SErwin T Tsaur static void print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset,
130d5ace945SErwin T Tsaur     uint8_t size);
131d5ace945SErwin T Tsaur static void print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p,
132d5ace945SErwin T Tsaur     pcitool_reg_t *info_p);
133d5ace945SErwin T Tsaur static void print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p,
134d5ace945SErwin T Tsaur     pcitool_reg_t *info_p);
135d5ace945SErwin T Tsaur static void print_probe_info(pci_conf_hdr_t *config_hdr_p,
136d5ace945SErwin T Tsaur     pcitool_reg_t *info_p, boolean_t verbose);
137d5ace945SErwin T Tsaur static int get_config_header(int fd, uint8_t bus_no, uint8_t dev_no,
138d5ace945SErwin T Tsaur     uint8_t func_no, pci_conf_hdr_t *config_hdr_p);
139*26947304SEvan Yan static int supports_ari(int fd, uint8_t bus_no);
140d5ace945SErwin T Tsaur static int probe_dev(int fd, pcitool_reg_t *prg_p,
141d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p);
142d5ace945SErwin T Tsaur static int do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl,
143d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p);
144d5ace945SErwin T Tsaur static int process_nexus_node(di_node_t node, di_minor_t minor, void *arg);
145d5ace945SErwin T Tsaur static int do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname);
146d5ace945SErwin T Tsaur static void print_bytedump_header(boolean_t do_chardump);
147d5ace945SErwin T Tsaur static int bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p,
148d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p);
149d5ace945SErwin T Tsaur static uint32_t set_acc_attr(pcitool_uiargs_t *input_args_p);
150d5ace945SErwin T Tsaur static int do_single_access(int fd, int cmd, pcitool_reg_t *prg_p,
151d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p);
152d5ace945SErwin T Tsaur static int do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p);
153d5ace945SErwin T Tsaur static void print_intr_info(pcitool_intr_get_t *iget_p);
154d5ace945SErwin T Tsaur static int get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp,
155d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p);
156d5ace945SErwin T Tsaur static int get_interrupts(int fd, pcitool_uiargs_t *input_args_p);
157d5ace945SErwin T Tsaur static int set_interrupts(int fd, pcitool_uiargs_t *input_args_p);
158d5ace945SErwin T Tsaur static int do_interrupts(int fd, pcitool_uiargs_t *input_args_p);
159d5ace945SErwin T Tsaur 
160d5ace945SErwin T Tsaur 
161d5ace945SErwin T Tsaur /* *************** General ************** */
162d5ace945SErwin T Tsaur 
163d5ace945SErwin T Tsaur /*
164d5ace945SErwin T Tsaur  * Handler for ^C to stop looping.
165d5ace945SErwin T Tsaur  */
166d5ace945SErwin T Tsaur /*ARGSUSED*/
167d5ace945SErwin T Tsaur static void
168d5ace945SErwin T Tsaur signal_handler(int dummy)
169d5ace945SErwin T Tsaur {
170d5ace945SErwin T Tsaur 	keep_looping = B_FALSE;
171d5ace945SErwin T Tsaur }
172d5ace945SErwin T Tsaur 
173d5ace945SErwin T Tsaur 
174d5ace945SErwin T Tsaur /*
175d5ace945SErwin T Tsaur  * Print string based on PCItool status returned from driver.
176d5ace945SErwin T Tsaur  */
177d5ace945SErwin T Tsaur static char *
178d5ace945SErwin T Tsaur strstatus(pcitool_errno_t pcitool_status)
179d5ace945SErwin T Tsaur {
180d5ace945SErwin T Tsaur 	int i;
181d5ace945SErwin T Tsaur 
182d5ace945SErwin T Tsaur 	for (i = 0; pcitool_stat_str[i].string != NULL; i++) {
183d5ace945SErwin T Tsaur 		if (pcitool_stat_str[i].value == pcitool_status) {
184d5ace945SErwin T Tsaur 
185d5ace945SErwin T Tsaur 			return (pcitool_stat_str[i].string);
186d5ace945SErwin T Tsaur 		}
187d5ace945SErwin T Tsaur 	}
188d5ace945SErwin T Tsaur 
189d5ace945SErwin T Tsaur 	return ("Unknown status returned from driver.");
190d5ace945SErwin T Tsaur }
191d5ace945SErwin T Tsaur 
192d5ace945SErwin T Tsaur 
193d5ace945SErwin T Tsaur static int
194d5ace945SErwin T Tsaur open_node(char *device, pcitool_uiargs_t *input_args_p)
195d5ace945SErwin T Tsaur {
196d5ace945SErwin T Tsaur 	int fd;
197d5ace945SErwin T Tsaur 	char *path;			/* For building full nexus pathname. */
198d5ace945SErwin T Tsaur 	int stringsize;			/* Device name size. */
199d5ace945SErwin T Tsaur 	char *prefix;
200d5ace945SErwin T Tsaur 	char *suffix;
201d5ace945SErwin T Tsaur 	char *format;
202d5ace945SErwin T Tsaur 
203d5ace945SErwin T Tsaur 	static char slash_devices[] = {"/devices"};
204d5ace945SErwin T Tsaur 	static char wcolon[] = {"%s%s:%s"};
205d5ace945SErwin T Tsaur 	static char wocolon[] = {"%s%s%s"};
206d5ace945SErwin T Tsaur 
207d5ace945SErwin T Tsaur 	/* Check for names starting with /devices. */
208d5ace945SErwin T Tsaur 	prefix = (strstr(device, slash_devices) == device) ? "" : slash_devices;
209d5ace945SErwin T Tsaur 
210d5ace945SErwin T Tsaur 	format = wcolon;
211d5ace945SErwin T Tsaur 	if (input_args_p->flags & INTR_FLAG) {
212d5ace945SErwin T Tsaur 		if (strstr(device, PCI_MINOR_INTR) ==
213d5ace945SErwin T Tsaur 		    device + (strlen(device) - strlen(PCI_MINOR_INTR))) {
214d5ace945SErwin T Tsaur 			suffix = "";
215d5ace945SErwin T Tsaur 			format = wocolon;
216d5ace945SErwin T Tsaur 		} else {
217d5ace945SErwin T Tsaur 			suffix = PCI_MINOR_INTR;
218d5ace945SErwin T Tsaur 		}
219d5ace945SErwin T Tsaur 	} else {
220d5ace945SErwin T Tsaur 		if (strstr(device, PCI_MINOR_REG) ==
221d5ace945SErwin T Tsaur 		    device + (strlen(device) - strlen(PCI_MINOR_REG))) {
222d5ace945SErwin T Tsaur 			suffix = "";
223d5ace945SErwin T Tsaur 			format = wocolon;
224d5ace945SErwin T Tsaur 		} else {
225d5ace945SErwin T Tsaur 			suffix = PCI_MINOR_REG;
226d5ace945SErwin T Tsaur 		}
227d5ace945SErwin T Tsaur 	}
228d5ace945SErwin T Tsaur 
229d5ace945SErwin T Tsaur 	/*
230d5ace945SErwin T Tsaur 	 * Build nexus pathname.
231d5ace945SErwin T Tsaur 	 * User specified /pci@1f,700000 becomes /devices/pci@1f,700000:intr
232d5ace945SErwin T Tsaur 	 * for interrupt nodes, and ...:reg for register nodes.
233d5ace945SErwin T Tsaur 	 *
234d5ace945SErwin T Tsaur 	 * ...The 2 at the end leaves room for a : and the terminating NULL.
235d5ace945SErwin T Tsaur 	 */
236d5ace945SErwin T Tsaur 	stringsize = strlen(prefix) + strlen(device) + strlen(suffix) + 2;
237d5ace945SErwin T Tsaur 	path = malloc(stringsize);
238d5ace945SErwin T Tsaur 
239d5ace945SErwin T Tsaur 	/*LINTED*/
240d5ace945SErwin T Tsaur 	(void) snprintf(path, stringsize, format, prefix, device, suffix);
241d5ace945SErwin T Tsaur 
242d5ace945SErwin T Tsaur 	/* Open the nexus. */
243d5ace945SErwin T Tsaur 	if ((fd = open(path, O_RDWR)) == -1) {
244d5ace945SErwin T Tsaur 		if (!(IS_QUIET(input_args_p->flags))) {
245d5ace945SErwin T Tsaur 			(void) fprintf(stderr,
246d5ace945SErwin T Tsaur 			    "Could not open nexus node %s: %s\n",
247d5ace945SErwin T Tsaur 			    path, strerror(errno));
248d5ace945SErwin T Tsaur 		}
249d5ace945SErwin T Tsaur 	}
250d5ace945SErwin T Tsaur 
251d5ace945SErwin T Tsaur 	return (fd);
252d5ace945SErwin T Tsaur }
253d5ace945SErwin T Tsaur 
254d5ace945SErwin T Tsaur 
255d5ace945SErwin T Tsaur /* ****************** Probe **************** */
256d5ace945SErwin T Tsaur 
257d5ace945SErwin T Tsaur /* The following are used by the probe printing functions. */
258d5ace945SErwin T Tsaur 
259d5ace945SErwin T Tsaur /* Header 0 and 1 config space headers have these fields. */
260d5ace945SErwin T Tsaur static field_type_t first_fields[] = {
261d5ace945SErwin T Tsaur 	{ PCI_CONF_VENID, 2, "Vend", "Vendor ID" },
262d5ace945SErwin T Tsaur 	{ PCI_CONF_DEVID, 2, "Dev ", "Device ID" },
263d5ace945SErwin T Tsaur 	{ PCI_CONF_COMM, 2, "Cmd ", "Command" },
264d5ace945SErwin T Tsaur 	{ PCI_CONF_STAT, 2, "Stat", "Status" },
265d5ace945SErwin T Tsaur 	{ PCI_CONF_REVID, 1, "Rv", "Revision ID" },
266d5ace945SErwin T Tsaur 	{ PCI_CONF_PROGCLASS, 3, "Class ", "Class Code" },
267d5ace945SErwin T Tsaur 	{ PCI_CONF_CACHE_LINESZ, 1, "Ca", "Cache Line Size" },
268d5ace945SErwin T Tsaur 	{ PCI_CONF_LATENCY_TIMER, 1, "LT", "Latency Timer" },
269d5ace945SErwin T Tsaur 	{ PCI_CONF_HEADER, 1, "Hd", "Header Type" },
270d5ace945SErwin T Tsaur 	{ PCI_CONF_BIST, 1, "BI", "BIST" },
271d5ace945SErwin T Tsaur 	{ 0, 0, NULL, NULL }
272d5ace945SErwin T Tsaur };
273d5ace945SErwin T Tsaur 
274d5ace945SErwin T Tsaur /* Header 0 (for regular devices) have these fields. */
275d5ace945SErwin T Tsaur static field_type_t last_dev_fields[] = {
276d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE0, 4, "BAR0", "Base Address Register 0 (@10)" },
277d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE1, 4, "BAR1", "Base Address Register 1 (@14)" },
278d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE2, 4, "BAR2", "Base Address Register 2 (@18)" },
279d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE3, 4, "BAR3", "Base Address Register 3 (@1C)" },
280d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE4, 4, "BAR4", "Base Address Register 4 (@20)" },
281d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE5, 4, "BAR5", "Base Address Register 5 (@24)" },
282d5ace945SErwin T Tsaur 	{ PCI_CONF_ROM, 4, "ROM", "Expansion ROM Base Address Register (@30)" },
283d5ace945SErwin T Tsaur 	{ 0, 0, NULL, NULL }
284d5ace945SErwin T Tsaur };
285d5ace945SErwin T Tsaur 
286d5ace945SErwin T Tsaur /* Header 1 (PCI-PCI bridge devices) have these fields. */
287d5ace945SErwin T Tsaur static field_type_t last_pcibrg_fields[] = {
288d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE0, 4, "BAR0", "Base Address Register 0 (@10)" },
289d5ace945SErwin T Tsaur 	{ PCI_CONF_BASE1, 4, "BAR1", "Base Address Register 1 (@14)" },
290d5ace945SErwin T Tsaur 	{ PCI_BCNF_ROM, 4, "ROM", "Expansion ROM Base Address Register (@38)" },
291d5ace945SErwin T Tsaur 	{ 0, 0, NULL, NULL }
292d5ace945SErwin T Tsaur };
293d5ace945SErwin T Tsaur 
294d5ace945SErwin T Tsaur /* Header 2 (PCI-Cardbus bridge devices) have these fields. */
295d5ace945SErwin T Tsaur static field_type_t last_cbbrg_fields[] = {
296d5ace945SErwin T Tsaur 	{ PCI_CBUS_SOCK_REG, 4, "SCKT", "Socket/ExCA Base Address (@10)" },
297d5ace945SErwin T Tsaur 	{ 0, 0, NULL, NULL }
298d5ace945SErwin T Tsaur };
299d5ace945SErwin T Tsaur 
300d5ace945SErwin T Tsaur #define	FMT_SIZE 7
301d5ace945SErwin T Tsaur 
302d5ace945SErwin T Tsaur static void
303d5ace945SErwin T Tsaur print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset, uint8_t size)
304d5ace945SErwin T Tsaur {
305d5ace945SErwin T Tsaur 
306d5ace945SErwin T Tsaur 	char format[FMT_SIZE];
307d5ace945SErwin T Tsaur 
308d5ace945SErwin T Tsaur 
309d5ace945SErwin T Tsaur 	/* Size cannot be any larger than 4 bytes.  This is not checked. */
310d5ace945SErwin T Tsaur 	uint32_t value = 0;
311d5ace945SErwin T Tsaur 
312d5ace945SErwin T Tsaur 	/* Build format of print, "%<size*2>.<size*2>x" */
313d5ace945SErwin T Tsaur 	(void) snprintf(format, FMT_SIZE, "%%%d.%dx ", size * 2, size * 2);
314d5ace945SErwin T Tsaur 
315d5ace945SErwin T Tsaur 	while (size-- > 0) {
316d5ace945SErwin T Tsaur 		value = (value << 8) + config_hdr_p->bytes[offset + size];
317d5ace945SErwin T Tsaur 	}
318d5ace945SErwin T Tsaur 
319d5ace945SErwin T Tsaur 	/*LINTED*/
320d5ace945SErwin T Tsaur 	(void) printf(format, value);
321d5ace945SErwin T Tsaur }
322d5ace945SErwin T Tsaur 
323d5ace945SErwin T Tsaur static void
324d5ace945SErwin T Tsaur print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p)
325d5ace945SErwin T Tsaur {
326d5ace945SErwin T Tsaur 	field_type_t *last_fields = NULL;
327d5ace945SErwin T Tsaur 	int i;
328d5ace945SErwin T Tsaur 
329d5ace945SErwin T Tsaur 	(void) printf("\n"
330d5ace945SErwin T Tsaur 	    "Bus Number: %x Device Number: %x Function Number: %x\n",
331d5ace945SErwin T Tsaur 	    info_p->bus_no, info_p->dev_no, info_p->func_no);
332d5ace945SErwin T Tsaur 	if (info_p->phys_addr != 0) {
333d5ace945SErwin T Tsaur 		(void) printf("Physical Address: 0x%" PRIx64 " \n",
334d5ace945SErwin T Tsaur 		    info_p->phys_addr);
335d5ace945SErwin T Tsaur 	}
336d5ace945SErwin T Tsaur 
337d5ace945SErwin T Tsaur 	switch (config_hdr_p->bytes[PCI_CONF_HEADER] & PCI_HEADER_TYPE_M) {
338d5ace945SErwin T Tsaur 
339d5ace945SErwin T Tsaur 	case PCI_HEADER_ZERO:	/* Header type 0 is a regular device. */
340d5ace945SErwin T Tsaur 		last_fields = last_dev_fields;
341d5ace945SErwin T Tsaur 		break;
342d5ace945SErwin T Tsaur 
343d5ace945SErwin T Tsaur 	case PCI_HEADER_PPB:	/* Header type 1 is a PCI-PCI bridge. */
344d5ace945SErwin T Tsaur 		last_fields = last_pcibrg_fields;
345d5ace945SErwin T Tsaur 		(void) printf("PCI-PCI bridge\n");
346d5ace945SErwin T Tsaur 		break;
347d5ace945SErwin T Tsaur 
348d5ace945SErwin T Tsaur 	case PCI_HEADER_CARDBUS: /* Header type 2 is a cardbus bridge */
349d5ace945SErwin T Tsaur 		last_fields = last_cbbrg_fields;
350d5ace945SErwin T Tsaur 		(void) printf("PCI-Cardbus bridge\n");
351d5ace945SErwin T Tsaur 		break;
352d5ace945SErwin T Tsaur 
353d5ace945SErwin T Tsaur 	default:
354d5ace945SErwin T Tsaur 		(void) printf("Unknown device\n");
355d5ace945SErwin T Tsaur 		break;
356d5ace945SErwin T Tsaur 	}
357d5ace945SErwin T Tsaur 
358d5ace945SErwin T Tsaur 	if (last_fields != NULL) {
359d5ace945SErwin T Tsaur 
360d5ace945SErwin T Tsaur 		for (i = 0; first_fields[i].size != 0; i++) {
361d5ace945SErwin T Tsaur 			(void) printf("%s: ", first_fields[i].full_hdr);
362d5ace945SErwin T Tsaur 			print_probe_value(config_hdr_p,
363d5ace945SErwin T Tsaur 			    first_fields[i].cfg_offset, first_fields[i].size);
364d5ace945SErwin T Tsaur 			(void) putchar('\n');
365d5ace945SErwin T Tsaur 		}
366d5ace945SErwin T Tsaur 
367d5ace945SErwin T Tsaur 		for (i = 0; last_fields[i].size != 0; i++) {
368d5ace945SErwin T Tsaur 			(void) printf("%s: ", last_fields[i].full_hdr);
369d5ace945SErwin T Tsaur 			print_probe_value(config_hdr_p,
370d5ace945SErwin T Tsaur 			    last_fields[i].cfg_offset, last_fields[i].size);
371d5ace945SErwin T Tsaur 			(void) putchar('\n');
372d5ace945SErwin T Tsaur 		}
373d5ace945SErwin T Tsaur 	}
374d5ace945SErwin T Tsaur }
375d5ace945SErwin T Tsaur 
376d5ace945SErwin T Tsaur static void
377d5ace945SErwin T Tsaur print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p)
378d5ace945SErwin T Tsaur {
379d5ace945SErwin T Tsaur 	int i;
380d5ace945SErwin T Tsaur 
381d5ace945SErwin T Tsaur 	(void) printf("%2.2x %2.2x %1.1x ",
382d5ace945SErwin T Tsaur 	    info_p->bus_no, info_p->dev_no, info_p->func_no);
383d5ace945SErwin T Tsaur 	for (i = 0; first_fields[i].size != 0; i++) {
384d5ace945SErwin T Tsaur 		print_probe_value(config_hdr_p,
385d5ace945SErwin T Tsaur 		    first_fields[i].cfg_offset, first_fields[i].size);
386d5ace945SErwin T Tsaur 	}
387d5ace945SErwin T Tsaur 	(void) putchar('\n');
388d5ace945SErwin T Tsaur }
389d5ace945SErwin T Tsaur 
390d5ace945SErwin T Tsaur 
391d5ace945SErwin T Tsaur /*
392d5ace945SErwin T Tsaur  * Print device information retrieved during probe mode.
393d5ace945SErwin T Tsaur  * Takes the PCI config header, plus address information retrieved from the
394d5ace945SErwin T Tsaur  * driver.
395d5ace945SErwin T Tsaur  *
396d5ace945SErwin T Tsaur  * When called with config_hdr_p == NULL, this function just prints a header
397d5ace945SErwin T Tsaur  * when not in verbose mode.
398d5ace945SErwin T Tsaur  */
399d5ace945SErwin T Tsaur 
400d5ace945SErwin T Tsaur static void
401d5ace945SErwin T Tsaur print_probe_info(
402d5ace945SErwin T Tsaur     pci_conf_hdr_t *config_hdr_p, pcitool_reg_t *info_p, boolean_t verbose)
403d5ace945SErwin T Tsaur {
404d5ace945SErwin T Tsaur 	int i;
405d5ace945SErwin T Tsaur 
406d5ace945SErwin T Tsaur 	/* Print header if not in verbose mode. */
407d5ace945SErwin T Tsaur 	if (config_hdr_p == NULL) {
408d5ace945SErwin T Tsaur 		if (!verbose) {
409d5ace945SErwin T Tsaur 
410d5ace945SErwin T Tsaur 			/* Bus dev func not from tble */
411d5ace945SErwin T Tsaur 			(void) printf("B  D  F ");
412d5ace945SErwin T Tsaur 
413d5ace945SErwin T Tsaur 			for (i = 0; first_fields[i].size != 0; i++) {
414d5ace945SErwin T Tsaur 				(void) printf("%s ",
415d5ace945SErwin T Tsaur 				    first_fields[i].abbrev_hdr);
416d5ace945SErwin T Tsaur 			}
417d5ace945SErwin T Tsaur 			(void) putchar('\n');
418d5ace945SErwin T Tsaur 		}
419d5ace945SErwin T Tsaur 
420d5ace945SErwin T Tsaur 		return;
421d5ace945SErwin T Tsaur 	}
422d5ace945SErwin T Tsaur 
423d5ace945SErwin T Tsaur 	if (verbose) {
424d5ace945SErwin T Tsaur 		print_probe_info_verbose(config_hdr_p, info_p);
425d5ace945SErwin T Tsaur 	} else {
426d5ace945SErwin T Tsaur 		print_probe_info_nonverbose(config_hdr_p, info_p);
427d5ace945SErwin T Tsaur 	}
428d5ace945SErwin T Tsaur }
429d5ace945SErwin T Tsaur 
430d5ace945SErwin T Tsaur 
431d5ace945SErwin T Tsaur /*
432d5ace945SErwin T Tsaur  * Retrieve first 16 dwords of device's config header, except for the first
433d5ace945SErwin T Tsaur  * dword.  First 16 dwords are defined by the PCI specification.
434d5ace945SErwin T Tsaur  */
435d5ace945SErwin T Tsaur static int
436d5ace945SErwin T Tsaur get_config_header(int fd, uint8_t bus_no, uint8_t dev_no, uint8_t func_no,
437d5ace945SErwin T Tsaur     pci_conf_hdr_t *config_hdr_p)
438d5ace945SErwin T Tsaur {
439d5ace945SErwin T Tsaur 	pcitool_reg_t cfg_prg;
440d5ace945SErwin T Tsaur 	int i;
441d5ace945SErwin T Tsaur 	int rval = SUCCESS;
442d5ace945SErwin T Tsaur 
443d5ace945SErwin T Tsaur 	/* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
444d5ace945SErwin T Tsaur 	cfg_prg.offset = 0;
445d5ace945SErwin T Tsaur 	cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
446d5ace945SErwin T Tsaur 	cfg_prg.bus_no = bus_no;
447d5ace945SErwin T Tsaur 	cfg_prg.dev_no = dev_no;
448d5ace945SErwin T Tsaur 	cfg_prg.func_no = func_no;
449d5ace945SErwin T Tsaur 	cfg_prg.barnum = 0;
450d5ace945SErwin T Tsaur 	cfg_prg.user_version = PCITOOL_VERSION;
451d5ace945SErwin T Tsaur 
452d5ace945SErwin T Tsaur 	/* Get dwords 1-15 of config space. They must be read as uint32_t. */
453d5ace945SErwin T Tsaur 	for (i = 1; i < (sizeof (pci_conf_hdr_t) / sizeof (uint32_t)); i++) {
454d5ace945SErwin T Tsaur 		cfg_prg.offset += sizeof (uint32_t);
455d5ace945SErwin T Tsaur 		if ((rval =
456d5ace945SErwin T Tsaur 		    ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg)) != SUCCESS) {
457d5ace945SErwin T Tsaur 			break;
458d5ace945SErwin T Tsaur 		}
459d5ace945SErwin T Tsaur 		config_hdr_p->dwords[i] = (uint32_t)cfg_prg.data;
460d5ace945SErwin T Tsaur 	}
461d5ace945SErwin T Tsaur 	return (rval);
462d5ace945SErwin T Tsaur }
463d5ace945SErwin T Tsaur 
464*26947304SEvan Yan static int
465*26947304SEvan Yan supports_ari(int fd, uint8_t bus_no)
466*26947304SEvan Yan {
467*26947304SEvan Yan 	pcitool_reg_t cfg_prg;
468*26947304SEvan Yan 	int deadcount = 0;
469*26947304SEvan Yan 	uint32_t data, hdr_next_ptr, hdr_cap_id;
470*26947304SEvan Yan 	uint8_t dev_no = 0;
471*26947304SEvan Yan 	uint8_t func_no = 0;
472*26947304SEvan Yan 
473*26947304SEvan Yan 	/* Prepare a local pcitool_reg_t so as to not disturb the caller's. */
474*26947304SEvan Yan 	cfg_prg.bus_no = bus_no;
475*26947304SEvan Yan 	cfg_prg.dev_no = dev_no;
476*26947304SEvan Yan 	cfg_prg.func_no = func_no;
477*26947304SEvan Yan 	cfg_prg.barnum = 0;
478*26947304SEvan Yan 	cfg_prg.user_version = PCITOOL_VERSION;
479*26947304SEvan Yan 	cfg_prg.offset = PCI_CONF_COMM;
480*26947304SEvan Yan 	cfg_prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + PCITOOL_ACC_ATTR_ENDN_LTL;
481*26947304SEvan Yan 
482*26947304SEvan Yan 	if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
483*26947304SEvan Yan 		return (FAILURE);
484*26947304SEvan Yan 	}
485*26947304SEvan Yan 
486*26947304SEvan Yan 	data = (uint32_t)cfg_prg.data;
487*26947304SEvan Yan 
488*26947304SEvan Yan 	if (!((data >> 16) & PCI_STAT_CAP))
489*26947304SEvan Yan 		return (FAILURE);
490*26947304SEvan Yan 
491*26947304SEvan Yan 	cfg_prg.offset = PCI_CONF_CAP_PTR;
492*26947304SEvan Yan 	if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
493*26947304SEvan Yan 		return (FAILURE);
494*26947304SEvan Yan 	}
495*26947304SEvan Yan 	data = (uint32_t)cfg_prg.data;
496*26947304SEvan Yan 	hdr_next_ptr = data & 0xff;
497*26947304SEvan Yan 	hdr_cap_id = 0;
498*26947304SEvan Yan 
499*26947304SEvan Yan 	/*
500*26947304SEvan Yan 	 * Find the PCIe capability.
501*26947304SEvan Yan 	 */
502*26947304SEvan Yan 	while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
503*26947304SEvan Yan 	    (hdr_cap_id != PCI_CAP_ID_PCI_E)) {
504*26947304SEvan Yan 
505*26947304SEvan Yan 		if (hdr_next_ptr < 0x40)
506*26947304SEvan Yan 			break;
507*26947304SEvan Yan 
508*26947304SEvan Yan 		cfg_prg.offset = hdr_next_ptr;
509*26947304SEvan Yan 
510*26947304SEvan Yan 		if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS)
511*26947304SEvan Yan 			return (FAILURE);
512*26947304SEvan Yan 
513*26947304SEvan Yan 		data = (uint32_t)cfg_prg.data;
514*26947304SEvan Yan 
515*26947304SEvan Yan 		hdr_next_ptr = (data >> 8) & 0xFF;
516*26947304SEvan Yan 		hdr_cap_id = data & 0xFF;
517*26947304SEvan Yan 
518*26947304SEvan Yan 		if (deadcount++ > 100)
519*26947304SEvan Yan 			return (FAILURE);
520*26947304SEvan Yan 	}
521*26947304SEvan Yan 
522*26947304SEvan Yan 	if (hdr_cap_id != PCI_CAP_ID_PCI_E)
523*26947304SEvan Yan 		return (FAILURE);
524*26947304SEvan Yan 
525*26947304SEvan Yan 	/* Found a PCIe Capability */
526*26947304SEvan Yan 
527*26947304SEvan Yan 	hdr_next_ptr = 0x100;
528*26947304SEvan Yan 	hdr_cap_id = 0;
529*26947304SEvan Yan 
530*26947304SEvan Yan 	/*
531*26947304SEvan Yan 	 * Now find the ARI Capability.
532*26947304SEvan Yan 	 */
533*26947304SEvan Yan 	while ((hdr_next_ptr != PCI_CAP_NEXT_PTR_NULL) &&
534*26947304SEvan Yan 	    (hdr_cap_id != 0xe)) {
535*26947304SEvan Yan 
536*26947304SEvan Yan 		if (hdr_next_ptr < 0x40)
537*26947304SEvan Yan 			break;
538*26947304SEvan Yan 
539*26947304SEvan Yan 		cfg_prg.offset = hdr_next_ptr;
540*26947304SEvan Yan 
541*26947304SEvan Yan 		if (ioctl(fd, PCITOOL_DEVICE_GET_REG, &cfg_prg) != SUCCESS) {
542*26947304SEvan Yan 			return (FAILURE);
543*26947304SEvan Yan 		}
544*26947304SEvan Yan 		data = (uint32_t)cfg_prg.data;
545*26947304SEvan Yan 
546*26947304SEvan Yan 		hdr_next_ptr = (data >> 20) & 0xFFF;
547*26947304SEvan Yan 		hdr_cap_id = data & 0xFFFF;
548*26947304SEvan Yan 
549*26947304SEvan Yan 		if (deadcount++ > 100)
550*26947304SEvan Yan 			return (FAILURE);
551*26947304SEvan Yan 	}
552*26947304SEvan Yan 
553*26947304SEvan Yan 	if (hdr_cap_id != 0xe)
554*26947304SEvan Yan 		return (FAILURE);
555*26947304SEvan Yan 
556*26947304SEvan Yan 	return (SUCCESS);
557*26947304SEvan Yan }
558*26947304SEvan Yan 
559d5ace945SErwin T Tsaur /*
560d5ace945SErwin T Tsaur  * Identify problematic southbridges.  These have device id 0x5249 and
561d5ace945SErwin T Tsaur  * vendor id 0x10b9.  Check for revision ID 0 and class code 060400 as well.
562d5ace945SErwin T Tsaur  * Values are little endian, so they are reversed for SPARC.
563d5ace945SErwin T Tsaur  *
564d5ace945SErwin T Tsaur  * Check for these southbridges on all architectures, as the issue is a
565d5ace945SErwin T Tsaur  * southbridge issue, independent of processor.
566d5ace945SErwin T Tsaur  *
567d5ace945SErwin T Tsaur  * If one of these is found during probing, skip probing other devs/funcs on
568d5ace945SErwin T Tsaur  * the rest of the bus, since the southbridge and all devs underneath will
569d5ace945SErwin T Tsaur  * otherwise disappear.
570d5ace945SErwin T Tsaur  */
571d5ace945SErwin T Tsaur #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG)
572d5ace945SErwin T Tsaur #define	U45_SB_DEVID_VID	0xb9104952
573d5ace945SErwin T Tsaur #define	U45_SB_CLASS_RID	0x00000406
574d5ace945SErwin T Tsaur #else
575d5ace945SErwin T Tsaur #define	U45_SB_DEVID_VID	0x524910b9
576d5ace945SErwin T Tsaur #define	U45_SB_CLASS_RID	0x06040000
577d5ace945SErwin T Tsaur #endif
578d5ace945SErwin T Tsaur 
579d5ace945SErwin T Tsaur /*
580d5ace945SErwin T Tsaur  * Probe device's functions.  Modifies many fields in the prg_p.
581d5ace945SErwin T Tsaur  */
582d5ace945SErwin T Tsaur static int
583d5ace945SErwin T Tsaur probe_dev(int fd, pcitool_reg_t *prg_p, pcitool_uiargs_t *input_args_p)
584d5ace945SErwin T Tsaur {
585d5ace945SErwin T Tsaur 	pci_conf_hdr_t	config_hdr;
586*26947304SEvan Yan 	boolean_t	multi_function_device = B_FALSE;
587d5ace945SErwin T Tsaur 	int		func;
588d5ace945SErwin T Tsaur 	int		first_func = 0;
589d5ace945SErwin T Tsaur 	int		last_func = PCI_REG_FUNC_M >> PCI_REG_FUNC_SHIFT;
590d5ace945SErwin T Tsaur 	int		rval = SUCCESS;
591d5ace945SErwin T Tsaur 
592d5ace945SErwin T Tsaur 	if (input_args_p->flags & FUNC_SPEC_FLAG) {
593d5ace945SErwin T Tsaur 		first_func = last_func = input_args_p->function;
594*26947304SEvan Yan 	} else if (supports_ari(fd, prg_p->bus_no) == SUCCESS) {
595*26947304SEvan Yan 		multi_function_device = B_TRUE;
596*26947304SEvan Yan 		if (!(input_args_p->flags & DEV_SPEC_FLAG))
597*26947304SEvan Yan 			last_func = 255;
598d5ace945SErwin T Tsaur 	}
599d5ace945SErwin T Tsaur 
600d5ace945SErwin T Tsaur 	/*
601d5ace945SErwin T Tsaur 	 * Loop through at least func=first_func.  Continue looping through
602d5ace945SErwin T Tsaur 	 * functions if there are no errors and the device is a multi-function
603d5ace945SErwin T Tsaur 	 * device.
604d5ace945SErwin T Tsaur 	 *
605d5ace945SErwin T Tsaur 	 * (Note, if first_func == 0, header will show whether multifunction
606d5ace945SErwin T Tsaur 	 * device and set multi_function_device.  If first_func != 0, then we
607d5ace945SErwin T Tsaur 	 * will force the loop as the user wants a specific function to be
608d5ace945SErwin T Tsaur 	 * checked.
609d5ace945SErwin T Tsaur 	 */
610*26947304SEvan Yan 	for (func = first_func;  ((func <= last_func) &&
611d5ace945SErwin T Tsaur 	    ((func == first_func) || (multi_function_device)));
612d5ace945SErwin T Tsaur 	    func++) {
613*26947304SEvan Yan 		if (last_func > 7) {
614*26947304SEvan Yan 			prg_p->func_no = func & 0x7;
615*26947304SEvan Yan 			prg_p->dev_no = (func >> 3) & 0x1f;
616*26947304SEvan Yan 		} else
617d5ace945SErwin T Tsaur 			prg_p->func_no = func;
618d5ace945SErwin T Tsaur 
619d5ace945SErwin T Tsaur 		/*
620d5ace945SErwin T Tsaur 		 * Four things can happen here:
621d5ace945SErwin T Tsaur 		 *
622d5ace945SErwin T Tsaur 		 * 1) ioctl comes back as EFAULT and prg_p->status is
623d5ace945SErwin T Tsaur 		 *    PCITOOL_INVALID_ADDRESS.  There is no device at this
624d5ace945SErwin T Tsaur 		 *    location.
625d5ace945SErwin T Tsaur 		 *
626d5ace945SErwin T Tsaur 		 * 2) ioctl comes back successful and the data comes back as
627d5ace945SErwin T Tsaur 		 *    zero.  Config space is mapped but no device responded.
628d5ace945SErwin T Tsaur 		 *
629d5ace945SErwin T Tsaur 		 * 3) ioctl comes back successful and the data comes back as
630d5ace945SErwin T Tsaur 		 *    non-zero.  We've found a device.
631d5ace945SErwin T Tsaur 		 *
632d5ace945SErwin T Tsaur 		 * 4) Some other error occurs in an ioctl.
633d5ace945SErwin T Tsaur 		 */
634d5ace945SErwin T Tsaur 
635d5ace945SErwin T Tsaur 		prg_p->status = PCITOOL_SUCCESS;
636d5ace945SErwin T Tsaur 		prg_p->offset = 0;
637d5ace945SErwin T Tsaur 		prg_p->data = 0;
638d5ace945SErwin T Tsaur 		prg_p->user_version = PCITOOL_VERSION;
639d5ace945SErwin T Tsaur 		if (((rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, prg_p)) != 0) ||
640d5ace945SErwin T Tsaur 		    (prg_p->data == 0xffffffff)) {
641d5ace945SErwin T Tsaur 
642d5ace945SErwin T Tsaur 			/*
643d5ace945SErwin T Tsaur 			 * Accept errno == EINVAL along with status of
644d5ace945SErwin T Tsaur 			 * PCITOOL_OUT_OF_RANGE because some systems
645d5ace945SErwin T Tsaur 			 * don't implement the full range of config space.
646d5ace945SErwin T Tsaur 			 * Leave the loop quietly in this case.
647d5ace945SErwin T Tsaur 			 */
648d5ace945SErwin T Tsaur 			if ((errno == EINVAL) ||
649d5ace945SErwin T Tsaur 			    (prg_p->status == PCITOOL_OUT_OF_RANGE)) {
650d5ace945SErwin T Tsaur 				break;
651d5ace945SErwin T Tsaur 			}
652d5ace945SErwin T Tsaur 
653d5ace945SErwin T Tsaur 			/*
654d5ace945SErwin T Tsaur 			 * Exit silently with ENXIO as this means that there are
655d5ace945SErwin T Tsaur 			 * no devices under the pci root nexus.
656d5ace945SErwin T Tsaur 			 */
657d5ace945SErwin T Tsaur 			else if ((errno == ENXIO) &&
658d5ace945SErwin T Tsaur 			    (prg_p->status == PCITOOL_IO_ERROR)) {
659d5ace945SErwin T Tsaur 				break;
660d5ace945SErwin T Tsaur 			}
661d5ace945SErwin T Tsaur 
662d5ace945SErwin T Tsaur 			/*
663d5ace945SErwin T Tsaur 			 * Expect errno == EFAULT along with status of
664d5ace945SErwin T Tsaur 			 * PCITOOL_INVALID_ADDRESS because there won't be
665d5ace945SErwin T Tsaur 			 * devices at each stop.  Quit on any other error.
666d5ace945SErwin T Tsaur 			 */
667d5ace945SErwin T Tsaur 			else if (((errno != EFAULT) ||
668d5ace945SErwin T Tsaur 			    (prg_p->status != PCITOOL_INVALID_ADDRESS)) &&
669d5ace945SErwin T Tsaur 			    (prg_p->data != 0xffffffff)) {
670d5ace945SErwin T Tsaur 
671d5ace945SErwin T Tsaur 				if (!(IS_QUIET(input_args_p->flags))) {
672d5ace945SErwin T Tsaur 					(void) fprintf(stderr,
673d5ace945SErwin T Tsaur 					    "Ioctl error: %s\n",
674d5ace945SErwin T Tsaur 					    strerror(errno));
675d5ace945SErwin T Tsaur 				}
676d5ace945SErwin T Tsaur 				break;
677d5ace945SErwin T Tsaur 
678d5ace945SErwin T Tsaur 			/*
679d5ace945SErwin T Tsaur 			 * If no function at this location,
680d5ace945SErwin T Tsaur 			 * just advance to the next function.
681d5ace945SErwin T Tsaur 			 */
682d5ace945SErwin T Tsaur 			} else {
683d5ace945SErwin T Tsaur 				rval = SUCCESS;
684d5ace945SErwin T Tsaur 			}
685d5ace945SErwin T Tsaur 
686d5ace945SErwin T Tsaur 		/*
687d5ace945SErwin T Tsaur 		 * Data came back as 0.
688d5ace945SErwin T Tsaur 		 * Treat as unresponsive device amd check next device.
689d5ace945SErwin T Tsaur 		 */
690d5ace945SErwin T Tsaur 		} else if (prg_p->data == 0) {
691d5ace945SErwin T Tsaur 			rval = SUCCESS;
692d5ace945SErwin T Tsaur 		/* Found something. */
693d5ace945SErwin T Tsaur 		} else {
694d5ace945SErwin T Tsaur 			config_hdr.dwords[0] = (uint32_t)prg_p->data;
695d5ace945SErwin T Tsaur 
696d5ace945SErwin T Tsaur 			/* Get the rest of the PCI header. */
697d5ace945SErwin T Tsaur 			if ((rval = get_config_header(fd, prg_p->bus_no,
698d5ace945SErwin T Tsaur 			    prg_p->dev_no, prg_p->func_no, &config_hdr)) !=
699d5ace945SErwin T Tsaur 			    SUCCESS) {
700d5ace945SErwin T Tsaur 				break;
701d5ace945SErwin T Tsaur 			}
702d5ace945SErwin T Tsaur 
703d5ace945SErwin T Tsaur 			/* Print the found information. */
704d5ace945SErwin T Tsaur 			print_probe_info(&config_hdr, prg_p,
705d5ace945SErwin T Tsaur 			    IS_VERBOSE(input_args_p->flags));
706d5ace945SErwin T Tsaur 
707d5ace945SErwin T Tsaur 			/*
708d5ace945SErwin T Tsaur 			 * Special case for the type of Southbridge found on
709d5ace945SErwin T Tsaur 			 * Ultra-45 and other sun4u fire workstations.
710d5ace945SErwin T Tsaur 			 */
711d5ace945SErwin T Tsaur 			if ((config_hdr.dwords[0] == U45_SB_DEVID_VID) &&
712d5ace945SErwin T Tsaur 			    (config_hdr.dwords[2] == U45_SB_CLASS_RID)) {
713d5ace945SErwin T Tsaur 				rval = ECANCELED;
714d5ace945SErwin T Tsaur 				break;
715d5ace945SErwin T Tsaur 			}
716d5ace945SErwin T Tsaur 
717d5ace945SErwin T Tsaur 			/*
718d5ace945SErwin T Tsaur 			 * Accomodate devices which state their
719d5ace945SErwin T Tsaur 			 * multi-functionality only in their function 0 config
720d5ace945SErwin T Tsaur 			 * space.  Note multi-functionality throughout probing
721d5ace945SErwin T Tsaur 			 * of all of this device's functions.
722d5ace945SErwin T Tsaur 			 */
723d5ace945SErwin T Tsaur 			if (config_hdr.bytes[PCI_CONF_HEADER] &
724d5ace945SErwin T Tsaur 			    PCI_HEADER_MULTI) {
725d5ace945SErwin T Tsaur 				multi_function_device = B_TRUE;
726d5ace945SErwin T Tsaur 			}
727d5ace945SErwin T Tsaur 		}
728d5ace945SErwin T Tsaur 	}
729d5ace945SErwin T Tsaur 
730d5ace945SErwin T Tsaur 	return (rval);
731d5ace945SErwin T Tsaur }
732d5ace945SErwin T Tsaur 
733d5ace945SErwin T Tsaur 
734d5ace945SErwin T Tsaur /*
735d5ace945SErwin T Tsaur  * Probe a given nexus config space for devices.
736d5ace945SErwin T Tsaur  *
737d5ace945SErwin T Tsaur  * fd is the file descriptor of the nexus.
738d5ace945SErwin T Tsaur  * input_args contains commandline options as specified by the user.
739d5ace945SErwin T Tsaur  */
740d5ace945SErwin T Tsaur static int
741d5ace945SErwin T Tsaur do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl,
742d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p)
743d5ace945SErwin T Tsaur {
744d5ace945SErwin T Tsaur 	pcitool_reg_t prg;
745d5ace945SErwin T Tsaur 	int bus;
746d5ace945SErwin T Tsaur 	int dev;
747d5ace945SErwin T Tsaur 	int last_bus = PCI_REG_BUS_M >> PCI_REG_BUS_SHIFT;
748d5ace945SErwin T Tsaur 	int last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
749d5ace945SErwin T Tsaur 	int first_bus = 0;
750d5ace945SErwin T Tsaur 	int first_dev = 0;
751d5ace945SErwin T Tsaur 	int rval = SUCCESS;
752d5ace945SErwin T Tsaur 
753d5ace945SErwin T Tsaur 	prg.barnum = 0;	/* Config space. */
754d5ace945SErwin T Tsaur 
755d5ace945SErwin T Tsaur 	/* Must read in 4-byte quantities. */
756d5ace945SErwin T Tsaur 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 + NATIVE_ENDIAN;
757d5ace945SErwin T Tsaur 
758d5ace945SErwin T Tsaur 	prg.data = 0;
759d5ace945SErwin T Tsaur 
760d5ace945SErwin T Tsaur 	/* If an explicit bus was specified by the user, go with it. */
761d5ace945SErwin T Tsaur 	if (input_args_p->flags & BUS_SPEC_FLAG) {
762d5ace945SErwin T Tsaur 		first_bus = last_bus = input_args_p->bus;
763d5ace945SErwin T Tsaur 
764d5ace945SErwin T Tsaur 	} else if (input_args_p->flags & PROBERNG_FLAG) {
765d5ace945SErwin T Tsaur 		/* Otherwise get the bus range from properties. */
766d5ace945SErwin T Tsaur 		int len;
767d5ace945SErwin T Tsaur 		uint32_t *rangebuf = NULL;
768d5ace945SErwin T Tsaur 
769d5ace945SErwin T Tsaur 		len = di_prop_lookup_ints(DDI_DEV_T_ANY, di_node,
770d5ace945SErwin T Tsaur 		    "bus-range", (int **)&rangebuf);
771d5ace945SErwin T Tsaur 
772d5ace945SErwin T Tsaur 		/* Try PROM property */
773d5ace945SErwin T Tsaur 		if (len <= 0) {
774d5ace945SErwin T Tsaur 			len = di_prom_prop_lookup_ints(di_phdl, di_node,
775d5ace945SErwin T Tsaur 			    "bus-range", (int **)&rangebuf);
776d5ace945SErwin T Tsaur 		}
777d5ace945SErwin T Tsaur 
778d5ace945SErwin T Tsaur 		/* Take full range for default if cannot get property. */
779d5ace945SErwin T Tsaur 		if (len > 0) {
780d5ace945SErwin T Tsaur 			first_bus = rangebuf[0];
781d5ace945SErwin T Tsaur 			last_bus = rangebuf[1];
782d5ace945SErwin T Tsaur 		}
783d5ace945SErwin T Tsaur 	}
784d5ace945SErwin T Tsaur 
785d5ace945SErwin T Tsaur 	/* Take full range for default if not PROBERNG and not BUS_SPEC. */
786d5ace945SErwin T Tsaur 
787d5ace945SErwin T Tsaur 	if (last_bus == first_bus) {
788d5ace945SErwin T Tsaur 		if (input_args_p->flags & DEV_SPEC_FLAG) {
789d5ace945SErwin T Tsaur 			/* Explicit device given.  Not probing a whole bus. */
790d5ace945SErwin T Tsaur 			(void) puts("");
791d5ace945SErwin T Tsaur 		} else {
792d5ace945SErwin T Tsaur 			(void) printf("*********** Probing bus %x "
793d5ace945SErwin T Tsaur 			    "***********\n\n", first_bus);
794d5ace945SErwin T Tsaur 		}
795d5ace945SErwin T Tsaur 	} else {
796d5ace945SErwin T Tsaur 		(void) printf("*********** Probing buses %x through %x "
797d5ace945SErwin T Tsaur 		    "***********\n\n", first_bus, last_bus);
798d5ace945SErwin T Tsaur 	}
799d5ace945SErwin T Tsaur 
800d5ace945SErwin T Tsaur 	/* Print header. */
801d5ace945SErwin T Tsaur 	print_probe_info(NULL, NULL, IS_VERBOSE(input_args_p->flags));
802d5ace945SErwin T Tsaur 
803d5ace945SErwin T Tsaur 	/* Device number explicitly specified. */
804d5ace945SErwin T Tsaur 	if (input_args_p->flags & DEV_SPEC_FLAG) {
805d5ace945SErwin T Tsaur 		first_dev = last_dev = input_args_p->device;
806d5ace945SErwin T Tsaur 	}
807d5ace945SErwin T Tsaur 
808d5ace945SErwin T Tsaur 	/*
809d5ace945SErwin T Tsaur 	 * Loop through all valid bus / dev / func combinations to check for
810d5ace945SErwin T Tsaur 	 * all devices, with the following exceptions:
811d5ace945SErwin T Tsaur 	 *
812d5ace945SErwin T Tsaur 	 * When nothing is found at function 0 of a bus / dev combination, skip
813d5ace945SErwin T Tsaur 	 * the other functions of that bus / dev combination.
814d5ace945SErwin T Tsaur 	 *
815d5ace945SErwin T Tsaur 	 * When a found device's function 0 is probed and it is determined that
816d5ace945SErwin T Tsaur 	 * it is not a multifunction device, skip probing of that device's
817d5ace945SErwin T Tsaur 	 * other functions.
818d5ace945SErwin T Tsaur 	 */
819d5ace945SErwin T Tsaur 	for (bus = first_bus; ((bus <= last_bus) && (rval == SUCCESS)); bus++) {
820d5ace945SErwin T Tsaur 		prg.bus_no = bus;
821*26947304SEvan Yan 
822*26947304SEvan Yan 		/* Device number explicitly specified. */
823*26947304SEvan Yan 		if (input_args_p->flags & DEV_SPEC_FLAG) {
824*26947304SEvan Yan 			first_dev = last_dev = input_args_p->device;
825*26947304SEvan Yan 		} else if (supports_ari(fd, bus) == SUCCESS) {
826*26947304SEvan Yan 			last_dev = 0;
827*26947304SEvan Yan 			first_dev = 0;
828*26947304SEvan Yan 		} else {
829*26947304SEvan Yan 			last_dev = PCI_REG_DEV_M >> PCI_REG_DEV_SHIFT;
830*26947304SEvan Yan 		}
831*26947304SEvan Yan 
832d5ace945SErwin T Tsaur 		for (dev = first_dev;
833d5ace945SErwin T Tsaur 		    ((dev <= last_dev) && (rval == SUCCESS)); dev++) {
834d5ace945SErwin T Tsaur 			prg.dev_no = dev;
835d5ace945SErwin T Tsaur 			rval = probe_dev(fd, &prg, input_args_p);
836d5ace945SErwin T Tsaur 		}
837d5ace945SErwin T Tsaur 
838d5ace945SErwin T Tsaur 		/*
839d5ace945SErwin T Tsaur 		 * Ultra-45 southbridge workaround:
840d5ace945SErwin T Tsaur 		 * ECANCELED tells to skip to the next bus.
841d5ace945SErwin T Tsaur 		 */
842d5ace945SErwin T Tsaur 		if (rval == ECANCELED) {
843d5ace945SErwin T Tsaur 			rval = SUCCESS;
844d5ace945SErwin T Tsaur 		}
845d5ace945SErwin T Tsaur 	}
846d5ace945SErwin T Tsaur 
847d5ace945SErwin T Tsaur 	return (rval);
848d5ace945SErwin T Tsaur }
849d5ace945SErwin T Tsaur 
850d5ace945SErwin T Tsaur /*
851d5ace945SErwin T Tsaur  * This function is called-back from di_walk_minor() when any PROBE is processed
852d5ace945SErwin T Tsaur  */
853d5ace945SErwin T Tsaur /*ARGSUSED*/
854d5ace945SErwin T Tsaur static int
855d5ace945SErwin T Tsaur process_nexus_node(di_node_t di_node, di_minor_t minor, void *arg)
856d5ace945SErwin T Tsaur {
857d5ace945SErwin T Tsaur 	int fd;
858d5ace945SErwin T Tsaur 	char *trunc;
859d5ace945SErwin T Tsaur 	probe_walk_args_t *walk_args_p = (probe_walk_args_t *)arg;
860d5ace945SErwin T Tsaur 	char *pathname = walk_args_p->pathname;
861d5ace945SErwin T Tsaur 	char *nexus_path = di_devfs_minor_path(minor);
862d5ace945SErwin T Tsaur 
863d5ace945SErwin T Tsaur 	if (nexus_path == NULL) {
864d5ace945SErwin T Tsaur 		(void) fprintf(stderr, "Error getting nexus path: %s\n",
865d5ace945SErwin T Tsaur 		    strerror(errno));
866d5ace945SErwin T Tsaur 		return (DI_WALK_CONTINUE);
867d5ace945SErwin T Tsaur 	}
868d5ace945SErwin T Tsaur 
869d5ace945SErwin T Tsaur 	/*
870d5ace945SErwin T Tsaur 	 * Display this node if pathname not specified (as all nodes are
871d5ace945SErwin T Tsaur 	 * displayed) or if the current node matches the single specified
872d5ace945SErwin T Tsaur 	 * pathname. Pathname form: xxx, nexus form: xxx:reg
873d5ace945SErwin T Tsaur 	 */
874d5ace945SErwin T Tsaur 	if ((pathname != NULL) &&
875d5ace945SErwin T Tsaur 	    ((strstr(nexus_path, pathname) != nexus_path) ||
876d5ace945SErwin T Tsaur 	    (strlen(nexus_path) !=
877d5ace945SErwin T Tsaur 	    (strlen(pathname) + strlen(PCI_MINOR_REG) + 1)))) {
878d5ace945SErwin T Tsaur 		di_devfs_path_free(nexus_path);
879d5ace945SErwin T Tsaur 		return (DI_WALK_CONTINUE);
880d5ace945SErwin T Tsaur 	}
881d5ace945SErwin T Tsaur 
882d5ace945SErwin T Tsaur 	if ((fd = open_node(nexus_path, walk_args_p->input_args_p)) >= 0) {
883d5ace945SErwin T Tsaur 
884d5ace945SErwin T Tsaur 		/* Strip off the suffix at the end of the nexus path. */
885d5ace945SErwin T Tsaur 		if ((trunc = strstr(nexus_path, PCI_MINOR_REG)) != NULL) {
886d5ace945SErwin T Tsaur 			trunc--;	/* Get the : just before too. */
887d5ace945SErwin T Tsaur 			*trunc = '\0';
888d5ace945SErwin T Tsaur 		}
889d5ace945SErwin T Tsaur 
890d5ace945SErwin T Tsaur 		/* Show header only if no explicit nexus node name given. */
891d5ace945SErwin T Tsaur 		(void) puts("");
892d5ace945SErwin T Tsaur 		if (pathname == NULL) {
893d5ace945SErwin T Tsaur 			(void) printf("********** Devices in tree under %s "
894d5ace945SErwin T Tsaur 			    "**********\n", nexus_path);
895d5ace945SErwin T Tsaur 		}
896d5ace945SErwin T Tsaur 
897d5ace945SErwin T Tsaur 		/*
898d5ace945SErwin T Tsaur 		 * Exit silently with ENXIO as this means that there are
899d5ace945SErwin T Tsaur 		 * no devices under the pci root nexus.
900d5ace945SErwin T Tsaur 		 */
901d5ace945SErwin T Tsaur 		if ((do_probe(fd, di_node, walk_args_p->di_phdl,
902d5ace945SErwin T Tsaur 		    walk_args_p->input_args_p) != SUCCESS) &&
903d5ace945SErwin T Tsaur 		    (errno != ENXIO)) {
904d5ace945SErwin T Tsaur 			(void) fprintf(stderr, "Error probing node %s: %s\n",
905d5ace945SErwin T Tsaur 			    nexus_path, strerror(errno));
906d5ace945SErwin T Tsaur 		}
907d5ace945SErwin T Tsaur 
908d5ace945SErwin T Tsaur 		(void) close(fd);
909d5ace945SErwin T Tsaur 	}
910d5ace945SErwin T Tsaur 	di_devfs_path_free(nexus_path);
911d5ace945SErwin T Tsaur 
912d5ace945SErwin T Tsaur 	/*
913d5ace945SErwin T Tsaur 	 * If node was explicitly specified, it has just been displayed
914d5ace945SErwin T Tsaur 	 * and no more looping is required.
915d5ace945SErwin T Tsaur 	 * Otherwise, keep looping for more nodes.
916d5ace945SErwin T Tsaur 	 */
917d5ace945SErwin T Tsaur 	return ((pathname == NULL) ? DI_WALK_CONTINUE : DI_WALK_TERMINATE);
918d5ace945SErwin T Tsaur }
919d5ace945SErwin T Tsaur 
920d5ace945SErwin T Tsaur 
921d5ace945SErwin T Tsaur /*
922d5ace945SErwin T Tsaur  * Start of probe.  If pathname is NULL, search all devices.
923d5ace945SErwin T Tsaur  *
924d5ace945SErwin T Tsaur  * di_walk_minor() walks all DDI_NT_REGACC (PCItool register access) nodes
925d5ace945SErwin T Tsaur  * and calls process_nexus_node on them.  process_nexus_node will then check
926d5ace945SErwin T Tsaur  * the pathname for a match, unless it is NULL which works like a wildcard.
927d5ace945SErwin T Tsaur  */
928d5ace945SErwin T Tsaur static int
929d5ace945SErwin T Tsaur do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname)
930d5ace945SErwin T Tsaur {
931d5ace945SErwin T Tsaur 	di_node_t di_node;
932d5ace945SErwin T Tsaur 	di_prom_handle_t di_phdl = DI_PROM_HANDLE_NIL;
933d5ace945SErwin T Tsaur 	probe_walk_args_t walk_args;
934d5ace945SErwin T Tsaur 
935d5ace945SErwin T Tsaur 	int rval = SUCCESS;
936d5ace945SErwin T Tsaur 
937d5ace945SErwin T Tsaur 	if ((di_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
938d5ace945SErwin T Tsaur 		(void) fprintf(stderr, "di_init() failed: %s\n",
939d5ace945SErwin T Tsaur 		    strerror(errno));
940d5ace945SErwin T Tsaur 		rval = errno;
941d5ace945SErwin T Tsaur 
942d5ace945SErwin T Tsaur 	} else if ((input_args_p->flags & PROBERNG_FLAG) &&
943d5ace945SErwin T Tsaur 	    ((di_phdl = di_prom_init()) == DI_PROM_HANDLE_NIL)) {
944d5ace945SErwin T Tsaur 		(void) fprintf(stderr, "di_prom_init failed: %s\n",
945d5ace945SErwin T Tsaur 		    strerror(errno));
946d5ace945SErwin T Tsaur 		rval = errno;
947d5ace945SErwin T Tsaur 
948d5ace945SErwin T Tsaur 	} else {
949d5ace945SErwin T Tsaur 		walk_args.input_args_p = input_args_p;
950d5ace945SErwin T Tsaur 		walk_args.di_phdl = di_phdl;
951d5ace945SErwin T Tsaur 		walk_args.pathname = pathname;
952d5ace945SErwin T Tsaur 		(void) di_walk_minor(di_node, DDI_NT_REGACC, 0,
953d5ace945SErwin T Tsaur 		    &walk_args, process_nexus_node);
954d5ace945SErwin T Tsaur 	}
955d5ace945SErwin T Tsaur 
956d5ace945SErwin T Tsaur 	if (di_phdl != DI_PROM_HANDLE_NIL) {
957d5ace945SErwin T Tsaur 		di_prom_fini(di_phdl);
958d5ace945SErwin T Tsaur 	}
959d5ace945SErwin T Tsaur 
960d5ace945SErwin T Tsaur 	if (di_node != DI_NODE_NIL) {
961d5ace945SErwin T Tsaur 		di_fini(di_node);
962d5ace945SErwin T Tsaur 	}
963d5ace945SErwin T Tsaur 
964d5ace945SErwin T Tsaur 	return (rval);
965d5ace945SErwin T Tsaur }
966d5ace945SErwin T Tsaur 
967d5ace945SErwin T Tsaur 
968d5ace945SErwin T Tsaur /* **************** Byte dump specific **************** */
969d5ace945SErwin T Tsaur 
970d5ace945SErwin T Tsaur static void
971d5ace945SErwin T Tsaur print_bytedump_header(boolean_t do_chardump)
972d5ace945SErwin T Tsaur {
973d5ace945SErwin T Tsaur 	static char header1[] = {"                    "
974d5ace945SErwin T Tsaur 	    "0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00"};
975d5ace945SErwin T Tsaur 	static char header2[] = {"                    "
976d5ace945SErwin T Tsaur 	    "-----------------------------------------------"};
977d5ace945SErwin T Tsaur 	static char cheader1[] = {" 0123456789ABCDEF"};
978d5ace945SErwin T Tsaur 	static char cheader2[] = {" ----------------"};
979d5ace945SErwin T Tsaur 
980d5ace945SErwin T Tsaur 	(void) puts("");
981d5ace945SErwin T Tsaur 	(void) printf(header1);
982d5ace945SErwin T Tsaur 	if (do_chardump) {
983d5ace945SErwin T Tsaur 		(void) printf(cheader1);
984d5ace945SErwin T Tsaur 	}
985d5ace945SErwin T Tsaur 	(void) puts("");
986d5ace945SErwin T Tsaur 	(void) printf(header2);
987d5ace945SErwin T Tsaur 	if (do_chardump) {
988d5ace945SErwin T Tsaur 		(void) printf(cheader2);
989d5ace945SErwin T Tsaur 	}
990d5ace945SErwin T Tsaur }
991d5ace945SErwin T Tsaur 
992d5ace945SErwin T Tsaur 
993d5ace945SErwin T Tsaur /* Number of bytes per line in a dump. */
994d5ace945SErwin T Tsaur #define	DUMP_BUF_SIZE		16
995d5ace945SErwin T Tsaur #define	LINES_BTWN_HEADER	16
996d5ace945SErwin T Tsaur 
997d5ace945SErwin T Tsaur /*
998d5ace945SErwin T Tsaur  * Retrieve several bytes over several reads, and print a formatted byte-dump
999d5ace945SErwin T Tsaur  *
1000d5ace945SErwin T Tsaur  * fd is the nexus by which device is accessed.
1001d5ace945SErwin T Tsaur  * prg provided has bus, dev, func, bank, initial offset already specified,
1002d5ace945SErwin T Tsaur  * as well as size and endian attributes.
1003d5ace945SErwin T Tsaur  *
1004d5ace945SErwin T Tsaur  * No checking is made that this is a read operation, although only read
1005d5ace945SErwin T Tsaur  * operations are allowed.
1006d5ace945SErwin T Tsaur  */
1007d5ace945SErwin T Tsaur static int
1008d5ace945SErwin T Tsaur bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p,
1009d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p)
1010d5ace945SErwin T Tsaur {
1011d5ace945SErwin T Tsaur 	typedef union {
1012d5ace945SErwin T Tsaur 		uint8_t	bytes[DUMP_BUF_SIZE];
1013d5ace945SErwin T Tsaur 		uint16_t shorts[DUMP_BUF_SIZE / sizeof (uint16_t)];
1014d5ace945SErwin T Tsaur 		uint32_t dwords[DUMP_BUF_SIZE / sizeof (uint32_t)];
1015d5ace945SErwin T Tsaur 		uint64_t longs[DUMP_BUF_SIZE / sizeof (uint64_t)];
1016d5ace945SErwin T Tsaur 	} buffer_t;
1017d5ace945SErwin T Tsaur 
1018d5ace945SErwin T Tsaur 	/*
1019d5ace945SErwin T Tsaur 	 * Local copy of pcitool_reg_t, since offset and phys_addrs are
1020d5ace945SErwin T Tsaur 	 * modified.
1021d5ace945SErwin T Tsaur 	 */
1022d5ace945SErwin T Tsaur 	pcitool_reg_t local_prg;
1023d5ace945SErwin T Tsaur 
1024d5ace945SErwin T Tsaur 	/* Loop parameters. */
1025d5ace945SErwin T Tsaur 	uint32_t dump_end = prg_p->offset + input_args_p->bytedump_amt;
1026d5ace945SErwin T Tsaur 	uint32_t dump_curr = prg_p->offset;
1027d5ace945SErwin T Tsaur 
1028d5ace945SErwin T Tsaur 	int read_size = input_args_p->size;
1029d5ace945SErwin T Tsaur 
1030d5ace945SErwin T Tsaur 	/* How many stores to the buffer before it is full. */
1031d5ace945SErwin T Tsaur 	int wrap_size = DUMP_BUF_SIZE / read_size;
1032d5ace945SErwin T Tsaur 
1033d5ace945SErwin T Tsaur 	/* Address prints at the beginning of each line. */
1034d5ace945SErwin T Tsaur 	uint64_t print_addr = 0;
1035d5ace945SErwin T Tsaur 
1036d5ace945SErwin T Tsaur 	/* Skip this num bytes at the beginning of the first dump. */
1037d5ace945SErwin T Tsaur 	int skip_begin;
1038d5ace945SErwin T Tsaur 
1039d5ace945SErwin T Tsaur 	/* Skip this num bytes at the end of the last dump. */
1040d5ace945SErwin T Tsaur 	int skip_end = 0;
1041d5ace945SErwin T Tsaur 
1042d5ace945SErwin T Tsaur 	/* skip_begin and skip_end are needed twice. */
1043d5ace945SErwin T Tsaur 	int skip_begin2;
1044d5ace945SErwin T Tsaur 	int skip_end2;
1045d5ace945SErwin T Tsaur 
1046d5ace945SErwin T Tsaur 	/* Number of lines between headers */
1047d5ace945SErwin T Tsaur 	int lines_since_header = 0;
1048d5ace945SErwin T Tsaur 
1049d5ace945SErwin T Tsaur 	boolean_t do_chardump = input_args_p->flags & CHARDUMP_FLAG;
1050d5ace945SErwin T Tsaur 	boolean_t continue_on_errs = input_args_p->flags & ERRCONT_FLAG;
1051d5ace945SErwin T Tsaur 
1052d5ace945SErwin T Tsaur 	int rval = SUCCESS;	/* Return status. */
1053d5ace945SErwin T Tsaur 
1054d5ace945SErwin T Tsaur 	int next;
1055d5ace945SErwin T Tsaur 	int i;
1056d5ace945SErwin T Tsaur 
1057d5ace945SErwin T Tsaur 	buffer_t buffer;
1058d5ace945SErwin T Tsaur 	uint16_t error_mask = 0; /* 1 bit/byte in buf.  Err when set */
1059d5ace945SErwin T Tsaur 
1060d5ace945SErwin T Tsaur 	bzero(buffer.bytes, sizeof (uint8_t) * DUMP_BUF_SIZE);
1061d5ace945SErwin T Tsaur 
1062d5ace945SErwin T Tsaur 	local_prg = *prg_p;	/* Make local copy. */
1063d5ace945SErwin T Tsaur 
1064d5ace945SErwin T Tsaur 	/*
1065d5ace945SErwin T Tsaur 	 * Flip the bytes to proper order if reading on a big endian machine.
1066d5ace945SErwin T Tsaur 	 * Do this by reading big as little and vs.
1067d5ace945SErwin T Tsaur 	 */
1068d5ace945SErwin T Tsaur #if (NATIVE_ENDIAN == PCITOOL_ACC_ATTR_ENDN_BIG)
1069d5ace945SErwin T Tsaur 		local_prg.acc_attr =
1070d5ace945SErwin T Tsaur 		    (PCITOOL_ACC_IS_BIG_ENDIAN(local_prg.acc_attr) ?
1071d5ace945SErwin T Tsaur 		    (local_prg.acc_attr & ~PCITOOL_ACC_ATTR_ENDN_BIG) :
1072d5ace945SErwin T Tsaur 		    (local_prg.acc_attr | PCITOOL_ACC_ATTR_ENDN_BIG));
1073d5ace945SErwin T Tsaur #endif
1074d5ace945SErwin T Tsaur 
1075d5ace945SErwin T Tsaur 	/*
1076d5ace945SErwin T Tsaur 	 * Get offset into buffer for first store.  Assumes the buffer size is
1077d5ace945SErwin T Tsaur 	 * a multiple of the read size.  "next" is the next buffer index to do
1078d5ace945SErwin T Tsaur 	 * a store.
1079d5ace945SErwin T Tsaur 	 */
1080d5ace945SErwin T Tsaur 	skip_begin = local_prg.offset % DUMP_BUF_SIZE;
1081d5ace945SErwin T Tsaur 	next = skip_begin / read_size;
1082d5ace945SErwin T Tsaur 
1083d5ace945SErwin T Tsaur 	print_bytedump_header(do_chardump);
1084d5ace945SErwin T Tsaur 
1085d5ace945SErwin T Tsaur 	while (dump_curr < dump_end) {
1086d5ace945SErwin T Tsaur 
1087d5ace945SErwin T Tsaur 		/* For reading from the next location. */
1088d5ace945SErwin T Tsaur 		local_prg.offset = dump_curr;
1089d5ace945SErwin T Tsaur 
1090d5ace945SErwin T Tsaur 		/* Access the device.  Abort on error. */
1091d5ace945SErwin T Tsaur 		if (((rval = ioctl(fd, cmd, &local_prg)) != SUCCESS) &&
1092d5ace945SErwin T Tsaur 		    (!(continue_on_errs))) {
1093d5ace945SErwin T Tsaur 			if (!(IS_QUIET(input_args_p->flags))) {
1094d5ace945SErwin T Tsaur 				(void) fprintf(stderr,
1095d5ace945SErwin T Tsaur 				    "Ioctl failed:\n errno: %s\n status: %s\n",
1096d5ace945SErwin T Tsaur 				    strerror(errno),
1097d5ace945SErwin T Tsaur 				    strstatus(local_prg.status));
1098d5ace945SErwin T Tsaur 			}
1099d5ace945SErwin T Tsaur 			break;
1100d5ace945SErwin T Tsaur 		}
1101d5ace945SErwin T Tsaur 
1102d5ace945SErwin T Tsaur 		/*
1103d5ace945SErwin T Tsaur 		 * Initialize print_addr first time through, in case printing
1104d5ace945SErwin T Tsaur 		 * is starting in the middle of the buffer.  Also reinitialize
1105d5ace945SErwin T Tsaur 		 * when wrap.
1106d5ace945SErwin T Tsaur 		 */
1107d5ace945SErwin T Tsaur 		if (print_addr == 0) {
1108d5ace945SErwin T Tsaur 
1109d5ace945SErwin T Tsaur 			/*
1110d5ace945SErwin T Tsaur 			 * X86 config space doesn't return phys addr.
1111d5ace945SErwin T Tsaur 			 * Use offset instead in this case.
1112d5ace945SErwin T Tsaur 			 */
1113d5ace945SErwin T Tsaur 			if (local_prg.phys_addr == 0) {	/* No phys addr ret */
1114d5ace945SErwin T Tsaur 				print_addr = local_prg.offset -
1115d5ace945SErwin T Tsaur 				    (local_prg.offset % DUMP_BUF_SIZE);
1116d5ace945SErwin T Tsaur 			} else {
1117d5ace945SErwin T Tsaur 				print_addr = local_prg.phys_addr -
1118d5ace945SErwin T Tsaur 				    (local_prg.phys_addr % DUMP_BUF_SIZE);
1119d5ace945SErwin T Tsaur 			}
1120d5ace945SErwin T Tsaur 		}
1121d5ace945SErwin T Tsaur 
1122d5ace945SErwin T Tsaur 		/*
1123d5ace945SErwin T Tsaur 		 * Read error occurred.
1124d5ace945SErwin T Tsaur 		 * Shift the right number of error bits ((1 << read_size) - 1)
1125d5ace945SErwin T Tsaur 		 * into the right place (next * read_size)
1126d5ace945SErwin T Tsaur 		 */
1127d5ace945SErwin T Tsaur 		if (rval != SUCCESS) {	/* Read error occurred */
1128d5ace945SErwin T Tsaur 			error_mask |=
1129d5ace945SErwin T Tsaur 			    ((1 << read_size) - 1) << (next * read_size);
1130d5ace945SErwin T Tsaur 
1131d5ace945SErwin T Tsaur 		} else {	/* Save data to the buffer. */
1132d5ace945SErwin T Tsaur 
1133d5ace945SErwin T Tsaur 			switch (read_size) {
1134d5ace945SErwin T Tsaur 			case 1:
1135d5ace945SErwin T Tsaur 				buffer.bytes[next] = (uint8_t)local_prg.data;
1136d5ace945SErwin T Tsaur 				break;
1137d5ace945SErwin T Tsaur 			case 2:
1138d5ace945SErwin T Tsaur 				buffer.shorts[next] = (uint16_t)local_prg.data;
1139d5ace945SErwin T Tsaur 				break;
1140d5ace945SErwin T Tsaur 			case 4:
1141d5ace945SErwin T Tsaur 				buffer.dwords[next] = (uint32_t)local_prg.data;
1142d5ace945SErwin T Tsaur 				break;
1143d5ace945SErwin T Tsaur 			case 8:
1144d5ace945SErwin T Tsaur 				buffer.longs[next] = (uint64_t)local_prg.data;
1145d5ace945SErwin T Tsaur 				break;
1146d5ace945SErwin T Tsaur 			default:
1147d5ace945SErwin T Tsaur 				rval = EIO;
1148d5ace945SErwin T Tsaur 				break;
1149d5ace945SErwin T Tsaur 			}
1150d5ace945SErwin T Tsaur 		}
1151d5ace945SErwin T Tsaur 		next++;
1152d5ace945SErwin T Tsaur 
1153d5ace945SErwin T Tsaur 		/* Increment index for next store, and wrap. */
1154d5ace945SErwin T Tsaur 		next %= wrap_size;
1155d5ace945SErwin T Tsaur 		dump_curr += read_size;
1156d5ace945SErwin T Tsaur 
1157d5ace945SErwin T Tsaur 		/* Zero out the remainder of the buffer if done. */
1158d5ace945SErwin T Tsaur 		if (dump_curr >= dump_end) {
1159d5ace945SErwin T Tsaur 			if (next != 0) {
1160d5ace945SErwin T Tsaur 				bzero(&buffer.bytes[next * read_size],
1161d5ace945SErwin T Tsaur 				    (wrap_size - next) * read_size);
1162d5ace945SErwin T Tsaur 				skip_end = (wrap_size - next) * read_size;
1163d5ace945SErwin T Tsaur 				next = 0;	/* For printing below. */
1164d5ace945SErwin T Tsaur 			}
1165d5ace945SErwin T Tsaur 		}
1166d5ace945SErwin T Tsaur 
1167d5ace945SErwin T Tsaur 		/* Dump the buffer if full or if done. */
1168d5ace945SErwin T Tsaur 		if (next == 0) {
1169d5ace945SErwin T Tsaur 
1170d5ace945SErwin T Tsaur 			skip_begin2 = skip_begin;
1171d5ace945SErwin T Tsaur 			skip_end2 = skip_end;
1172d5ace945SErwin T Tsaur 
1173d5ace945SErwin T Tsaur 			(void) printf("\n0x%16.16" PRIx64 ":", print_addr);
1174d5ace945SErwin T Tsaur 			for (i = DUMP_BUF_SIZE - 1; i >= 0; i--) {
1175d5ace945SErwin T Tsaur 				if (skip_end) {
1176d5ace945SErwin T Tsaur 					skip_end--;
1177d5ace945SErwin T Tsaur 					(void) printf(" --");
1178d5ace945SErwin T Tsaur 				} else if (skip_begin > i) {
1179d5ace945SErwin T Tsaur 					skip_begin--;
1180d5ace945SErwin T Tsaur 					(void) printf(" --");
1181d5ace945SErwin T Tsaur 				} else if (error_mask & (1 << i)) {
1182d5ace945SErwin T Tsaur 					(void) printf(" XX");
1183d5ace945SErwin T Tsaur 				} else {
1184d5ace945SErwin T Tsaur 					(void) printf(" %2.2x",
1185d5ace945SErwin T Tsaur 					    buffer.bytes[i]);
1186d5ace945SErwin T Tsaur 				}
1187d5ace945SErwin T Tsaur 			}
1188d5ace945SErwin T Tsaur 
1189d5ace945SErwin T Tsaur 			if (do_chardump) {
1190d5ace945SErwin T Tsaur 				(void) putchar(' ');
1191d5ace945SErwin T Tsaur 				for (i = 0; i < DUMP_BUF_SIZE; i++) {
1192d5ace945SErwin T Tsaur 					if (skip_begin2) {
1193d5ace945SErwin T Tsaur 						skip_begin2--;
1194d5ace945SErwin T Tsaur 						(void) printf("-");
1195d5ace945SErwin T Tsaur 					} else if (
1196d5ace945SErwin T Tsaur 					    (DUMP_BUF_SIZE - skip_end2) <= i) {
1197d5ace945SErwin T Tsaur 						(void) printf("-");
1198d5ace945SErwin T Tsaur 					} else if (error_mask & (1 << i)) {
1199d5ace945SErwin T Tsaur 						(void) putchar('X');
1200d5ace945SErwin T Tsaur 					} else if (isprint(buffer.bytes[i])) {
1201d5ace945SErwin T Tsaur 						(void) putchar(buffer.bytes[i]);
1202d5ace945SErwin T Tsaur 					} else {
1203d5ace945SErwin T Tsaur 						(void) putchar('@');
1204d5ace945SErwin T Tsaur 					}
1205d5ace945SErwin T Tsaur 				}
1206d5ace945SErwin T Tsaur 			}
1207d5ace945SErwin T Tsaur 
1208d5ace945SErwin T Tsaur 			if ((++lines_since_header == LINES_BTWN_HEADER) &&
1209d5ace945SErwin T Tsaur 			    (dump_curr < dump_end)) {
1210d5ace945SErwin T Tsaur 				lines_since_header = 0;
1211d5ace945SErwin T Tsaur 				(void) puts("");
1212d5ace945SErwin T Tsaur 				print_bytedump_header(do_chardump);
1213d5ace945SErwin T Tsaur 			}
1214d5ace945SErwin T Tsaur 
1215d5ace945SErwin T Tsaur 			print_addr += DUMP_BUF_SIZE;
1216d5ace945SErwin T Tsaur 			error_mask = 0;
1217d5ace945SErwin T Tsaur 		}
1218d5ace945SErwin T Tsaur 	}
1219d5ace945SErwin T Tsaur 	(void) printf("\n");
1220d5ace945SErwin T Tsaur 
1221d5ace945SErwin T Tsaur 	return (rval);
1222d5ace945SErwin T Tsaur }
1223d5ace945SErwin T Tsaur 
1224d5ace945SErwin T Tsaur 
1225d5ace945SErwin T Tsaur /* ************** Device and nexus access commands ************** */
1226d5ace945SErwin T Tsaur 
1227d5ace945SErwin T Tsaur /*
1228d5ace945SErwin T Tsaur  * Helper function to set access attributes.  Assumes size is valid.
1229d5ace945SErwin T Tsaur  */
1230d5ace945SErwin T Tsaur static uint32_t
1231d5ace945SErwin T Tsaur set_acc_attr(pcitool_uiargs_t *input_args_p)
1232d5ace945SErwin T Tsaur {
1233d5ace945SErwin T Tsaur 	uint32_t access_attrs;
1234d5ace945SErwin T Tsaur 
1235d5ace945SErwin T Tsaur 	switch (input_args_p->size) {
1236d5ace945SErwin T Tsaur 	case 1:
1237d5ace945SErwin T Tsaur 		access_attrs = PCITOOL_ACC_ATTR_SIZE_1;
1238d5ace945SErwin T Tsaur 		break;
1239d5ace945SErwin T Tsaur 	case 2:
1240d5ace945SErwin T Tsaur 		access_attrs = PCITOOL_ACC_ATTR_SIZE_2;
1241d5ace945SErwin T Tsaur 		break;
1242d5ace945SErwin T Tsaur 	case 4:
1243d5ace945SErwin T Tsaur 		access_attrs = PCITOOL_ACC_ATTR_SIZE_4;
1244d5ace945SErwin T Tsaur 		break;
1245d5ace945SErwin T Tsaur 	case 8:
1246d5ace945SErwin T Tsaur 		access_attrs = PCITOOL_ACC_ATTR_SIZE_8;
1247d5ace945SErwin T Tsaur 		break;
1248d5ace945SErwin T Tsaur 	}
1249d5ace945SErwin T Tsaur 
1250d5ace945SErwin T Tsaur 	if (input_args_p->big_endian) {
1251d5ace945SErwin T Tsaur 		access_attrs |= PCITOOL_ACC_ATTR_ENDN_BIG;
1252d5ace945SErwin T Tsaur 	}
1253d5ace945SErwin T Tsaur 
1254d5ace945SErwin T Tsaur 	return (access_attrs);
1255d5ace945SErwin T Tsaur }
1256d5ace945SErwin T Tsaur 
1257d5ace945SErwin T Tsaur static int
1258d5ace945SErwin T Tsaur do_single_access(int fd, int cmd, pcitool_reg_t *prg_p,
1259d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p)
1260d5ace945SErwin T Tsaur {
1261d5ace945SErwin T Tsaur 	boolean_t is_write = B_FALSE;
1262d5ace945SErwin T Tsaur 	int rval;
1263d5ace945SErwin T Tsaur 
1264d5ace945SErwin T Tsaur 	switch (cmd) {
1265d5ace945SErwin T Tsaur 		case PCITOOL_NEXUS_SET_REG:
1266d5ace945SErwin T Tsaur 		case PCITOOL_DEVICE_SET_REG:
1267d5ace945SErwin T Tsaur 			is_write = B_TRUE;
1268d5ace945SErwin T Tsaur 			break;
1269d5ace945SErwin T Tsaur 		default:
1270d5ace945SErwin T Tsaur 			break;
1271d5ace945SErwin T Tsaur 	}
1272d5ace945SErwin T Tsaur 
1273d5ace945SErwin T Tsaur 	/* Do the access.  Return on error. */
1274d5ace945SErwin T Tsaur 	if ((rval = ioctl(fd, cmd, prg_p)) != SUCCESS) {
1275d5ace945SErwin T Tsaur 		if (!(IS_QUIET(input_args_p->flags))) {
1276d5ace945SErwin T Tsaur 			(void) fprintf(stderr,
1277d5ace945SErwin T Tsaur 			    "%s ioctl failed:\n errno: %s\n status: %s\n",
1278d5ace945SErwin T Tsaur 			    is_write ? "write" : "read",
1279d5ace945SErwin T Tsaur 			    strerror(errno), strstatus(prg_p->status));
1280d5ace945SErwin T Tsaur 		}
1281d5ace945SErwin T Tsaur 
1282d5ace945SErwin T Tsaur 		return (rval);
1283d5ace945SErwin T Tsaur 	}
1284d5ace945SErwin T Tsaur 
1285d5ace945SErwin T Tsaur 	/* Print on all verbose requests. */
1286d5ace945SErwin T Tsaur 	if (IS_VERBOSE(input_args_p->flags)) {
1287d5ace945SErwin T Tsaur 
1288d5ace945SErwin T Tsaur 		/*
1289d5ace945SErwin T Tsaur 		 * Return offset on platforms which return phys_addr == 0
1290d5ace945SErwin T Tsaur 		 * for config space.
1291d5ace945SErwin T Tsaur 		 */
1292d5ace945SErwin T Tsaur 		if (prg_p->phys_addr == 0)
1293d5ace945SErwin T Tsaur 			prg_p->phys_addr = input_args_p->offset;
1294d5ace945SErwin T Tsaur 
1295d5ace945SErwin T Tsaur 		(void) printf("Addr:0x%" PRIx64 ", %d-byte %s endian "
1296d5ace945SErwin T Tsaur 		    "register value: 0x%" PRIx64 "\n",
1297d5ace945SErwin T Tsaur 		    prg_p->phys_addr, input_args_p->size,
1298d5ace945SErwin T Tsaur 		    (input_args_p->big_endian ? "big" : "little"), prg_p->data);
1299d5ace945SErwin T Tsaur 
1300d5ace945SErwin T Tsaur 	/* Non-verbose, read requests. */
1301d5ace945SErwin T Tsaur 	} else if (!(is_write)) {
1302d5ace945SErwin T Tsaur 		(void) printf("0x%" PRIx64 "\n", prg_p->data);
1303d5ace945SErwin T Tsaur 	}
1304d5ace945SErwin T Tsaur 
1305d5ace945SErwin T Tsaur 	return (rval);
1306d5ace945SErwin T Tsaur }
1307d5ace945SErwin T Tsaur 
1308d5ace945SErwin T Tsaur 
1309d5ace945SErwin T Tsaur /*
1310d5ace945SErwin T Tsaur  * fd is the file descriptor of the nexus to access, either to get its
1311d5ace945SErwin T Tsaur  * registers or to access a device through that nexus.
1312d5ace945SErwin T Tsaur  *
1313d5ace945SErwin T Tsaur  * input args are commandline arguments specified by the user.
1314d5ace945SErwin T Tsaur  */
1315d5ace945SErwin T Tsaur static int
1316d5ace945SErwin T Tsaur do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p)
1317d5ace945SErwin T Tsaur {
1318d5ace945SErwin T Tsaur 	pcitool_reg_t prg;	/* Request details given to the driver. */
1319d5ace945SErwin T Tsaur 	uint32_t write_cmd = 0;	/* Command given to the driver. */
1320d5ace945SErwin T Tsaur 	uint32_t read_cmd = 0;	/* Command given to the driver. */
1321d5ace945SErwin T Tsaur 	int rval = SUCCESS;	/* Return status. */
1322d5ace945SErwin T Tsaur 
1323d5ace945SErwin T Tsaur 	if (input_args_p->flags & WRITE_FLAG) {
1324d5ace945SErwin T Tsaur 		prg.data = input_args_p->write_value;
1325d5ace945SErwin T Tsaur 		if (input_args_p->flags & NEXUS_FLAG) {
1326d5ace945SErwin T Tsaur 			write_cmd = PCITOOL_NEXUS_SET_REG;
1327d5ace945SErwin T Tsaur 		} else {
1328d5ace945SErwin T Tsaur 			write_cmd = PCITOOL_DEVICE_SET_REG;
1329d5ace945SErwin T Tsaur 		}
1330d5ace945SErwin T Tsaur 	}
1331d5ace945SErwin T Tsaur 	if (input_args_p->flags & READ_FLAG) {
1332d5ace945SErwin T Tsaur 		if (input_args_p->flags & NEXUS_FLAG) {
1333d5ace945SErwin T Tsaur 			read_cmd = PCITOOL_NEXUS_GET_REG;
1334d5ace945SErwin T Tsaur 		} else {
1335d5ace945SErwin T Tsaur 			read_cmd = PCITOOL_DEVICE_GET_REG;
1336d5ace945SErwin T Tsaur 		}
1337d5ace945SErwin T Tsaur 	}
1338d5ace945SErwin T Tsaur 
1339d5ace945SErwin T Tsaur 	/* Finish initializing access details for driver. */
1340d5ace945SErwin T Tsaur 
1341d5ace945SErwin T Tsaur 	/*
1342d5ace945SErwin T Tsaur 	 * For nexus, barnum is the exact bank number, unless it is 0xFF, which
1343d5ace945SErwin T Tsaur 	 * indicates that it is inactive and a base_address should be read from
1344d5ace945SErwin T Tsaur 	 * the input_args instead.
1345d5ace945SErwin T Tsaur 	 *
1346d5ace945SErwin T Tsaur 	 * For devices, barnum is the offset to the desired BAR, or 0 for
1347d5ace945SErwin T Tsaur 	 * config space.
1348d5ace945SErwin T Tsaur 	 */
1349d5ace945SErwin T Tsaur 	if ((input_args_p->flags & (BASE_SPEC_FLAG | NEXUS_FLAG)) ==
1350d5ace945SErwin T Tsaur 	    (BASE_SPEC_FLAG | NEXUS_FLAG)) {
1351d5ace945SErwin T Tsaur 		prg.barnum = PCITOOL_BASE;
1352d5ace945SErwin T Tsaur 		prg.phys_addr = input_args_p->base_address;
1353d5ace945SErwin T Tsaur 	} else
1354d5ace945SErwin T Tsaur 		prg.barnum = input_args_p->bank;
1355d5ace945SErwin T Tsaur 
1356d5ace945SErwin T Tsaur 	prg.offset = input_args_p->offset;
1357d5ace945SErwin T Tsaur 	prg.acc_attr = set_acc_attr(input_args_p);
1358d5ace945SErwin T Tsaur 	prg.bus_no = input_args_p->bus;
1359d5ace945SErwin T Tsaur 	prg.dev_no = input_args_p->device;
1360d5ace945SErwin T Tsaur 	prg.func_no = input_args_p->function;
1361d5ace945SErwin T Tsaur 	prg.user_version = PCITOOL_VERSION;
1362d5ace945SErwin T Tsaur 
1363d5ace945SErwin T Tsaur 	do {
1364d5ace945SErwin T Tsaur 		/* Do a bytedump if desired, or else do single ioctl access. */
1365d5ace945SErwin T Tsaur 		if (input_args_p->flags & BYTEDUMP_FLAG) {
1366d5ace945SErwin T Tsaur 
1367d5ace945SErwin T Tsaur 			if (IS_VERBOSE(input_args_p->flags)) {
1368d5ace945SErwin T Tsaur 				(void) printf(
1369d5ace945SErwin T Tsaur 				    "\nDoing %d-byte %s endian reads:",
1370d5ace945SErwin T Tsaur 				    input_args_p->size,
1371d5ace945SErwin T Tsaur 				    input_args_p->big_endian ?
1372d5ace945SErwin T Tsaur 				    "big" : "little");
1373d5ace945SErwin T Tsaur 			}
1374d5ace945SErwin T Tsaur 			rval = bytedump_get(fd, read_cmd, &prg, input_args_p);
1375d5ace945SErwin T Tsaur 
1376d5ace945SErwin T Tsaur 		} else {
1377d5ace945SErwin T Tsaur 
1378d5ace945SErwin T Tsaur 			/* Single write and/or read. */
1379d5ace945SErwin T Tsaur 			if (write_cmd != 0) {
1380d5ace945SErwin T Tsaur 				rval = do_single_access(
1381d5ace945SErwin T Tsaur 				    fd, write_cmd, &prg, input_args_p);
1382d5ace945SErwin T Tsaur 			}
1383d5ace945SErwin T Tsaur 
1384d5ace945SErwin T Tsaur 			if ((rval == SUCCESS) && (read_cmd != 0)) {
1385d5ace945SErwin T Tsaur 				rval = do_single_access(
1386d5ace945SErwin T Tsaur 				    fd, read_cmd, &prg, input_args_p);
1387d5ace945SErwin T Tsaur 			}
1388d5ace945SErwin T Tsaur 		}
1389d5ace945SErwin T Tsaur 	} while ((IS_LOOP(input_args_p->flags)) && (rval == SUCCESS) &&
1390d5ace945SErwin T Tsaur 	    (keep_looping));
1391d5ace945SErwin T Tsaur 
1392d5ace945SErwin T Tsaur 	return (rval != SUCCESS ? errno : SUCCESS);
1393d5ace945SErwin T Tsaur }
1394d5ace945SErwin T Tsaur 
1395d5ace945SErwin T Tsaur /* *************** Interrupt routing ************** */
1396d5ace945SErwin T Tsaur 
1397d5ace945SErwin T Tsaur /*
1398d5ace945SErwin T Tsaur  * Display interrupt information.
1399d5ace945SErwin T Tsaur  * iget is filled in with the info to display
1400d5ace945SErwin T Tsaur  */
1401d5ace945SErwin T Tsaur static void
1402d5ace945SErwin T Tsaur print_intr_info(pcitool_intr_get_t *iget_p)
1403d5ace945SErwin T Tsaur {
1404d5ace945SErwin T Tsaur 	int i;
1405d5ace945SErwin T Tsaur 
140609b1eac2SEvan Yan 	if (iget_p->flags & PCITOOL_INTR_FLAG_GET_MSI)
140709b1eac2SEvan Yan 		(void) printf("\nmsi 0x%x mapped to cpu 0x%x\n",
140809b1eac2SEvan Yan 		    iget_p->msi,  iget_p->cpu_id);
140909b1eac2SEvan Yan 	else
141009b1eac2SEvan Yan 		(void) printf("\nino 0x%x mapped to cpu 0x%x\n",
1411d5ace945SErwin T Tsaur 		    iget_p->ino,  iget_p->cpu_id);
141209b1eac2SEvan Yan 
1413d5ace945SErwin T Tsaur 	for (i = 0; i < iget_p->num_devs; i++) {
1414d5ace945SErwin T Tsaur 		(void) printf("Device: %s\n", iget_p->dev[i].path);
1415d5ace945SErwin T Tsaur 		(void) printf("  Driver: %s, instance %d\n",
1416d5ace945SErwin T Tsaur 		    iget_p->dev[i].driver_name, iget_p->dev[i].dev_inst);
1417d5ace945SErwin T Tsaur 	}
1418d5ace945SErwin T Tsaur }
1419d5ace945SErwin T Tsaur 
1420d5ace945SErwin T Tsaur /*
1421d5ace945SErwin T Tsaur  * Interrupt command support.
1422d5ace945SErwin T Tsaur  *
1423d5ace945SErwin T Tsaur  * fd is the file descriptor of the nexus being probed.
1424d5ace945SErwin T Tsaur  * input_args are commandline options entered by the user.
1425d5ace945SErwin T Tsaur  */
1426d5ace945SErwin T Tsaur static int
1427d5ace945SErwin T Tsaur get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp,
1428d5ace945SErwin T Tsaur     pcitool_uiargs_t *input_args_p)
1429d5ace945SErwin T Tsaur {
1430d5ace945SErwin T Tsaur 	pcitool_intr_get_t *iget_p = *iget_pp;
143109b1eac2SEvan Yan 	const char	*str_type = NULL;
143209b1eac2SEvan Yan 	uint32_t	intr;
143309b1eac2SEvan Yan 
143409b1eac2SEvan Yan 	if (input_args_p->flags & MSI_SPEC_FLAG) {
143509b1eac2SEvan Yan 		intr = input_args_p->intr_msi;
143609b1eac2SEvan Yan 		str_type = "msi";
143709b1eac2SEvan Yan 	} else {
143809b1eac2SEvan Yan 		intr = input_args_p->intr_ino;
143909b1eac2SEvan Yan 		str_type = "ino";
144009b1eac2SEvan Yan 	}
1441d5ace945SErwin T Tsaur 
1442d5ace945SErwin T Tsaur 	/*
144309b1eac2SEvan Yan 	 * Check if interrupts are active on this ino/msi. Get as much
1444d5ace945SErwin T Tsaur 	 * device info as there is room for at the moment. If there
1445d5ace945SErwin T Tsaur 	 * is not enough room for all devices, will call again with a
1446d5ace945SErwin T Tsaur 	 * larger buffer.
1447d5ace945SErwin T Tsaur 	 */
1448d5ace945SErwin T Tsaur 	if (ioctl(fd, PCITOOL_DEVICE_GET_INTR, iget_p) != 0) {
1449d5ace945SErwin T Tsaur 		/*
1450d5ace945SErwin T Tsaur 		 * Let EIO errors silently slip through, as
1451d5ace945SErwin T Tsaur 		 * some inos may not be viewable by design.
1452d5ace945SErwin T Tsaur 		 * We don't want to stop or print an error for these.
1453d5ace945SErwin T Tsaur 		 */
1454d5ace945SErwin T Tsaur 		if (errno == EIO) {
1455d5ace945SErwin T Tsaur 			return (SUCCESS);
1456d5ace945SErwin T Tsaur 		}
1457d5ace945SErwin T Tsaur 
1458d5ace945SErwin T Tsaur 		if (!(IS_QUIET(input_args_p->flags))) {
145909b1eac2SEvan Yan 			(void) fprintf(stderr, "Ioctl to get %s 0x%x "
146009b1eac2SEvan Yan 			    "info failed: %s\n", str_type, intr,
146109b1eac2SEvan Yan 			    strerror(errno));
146209b1eac2SEvan Yan 
1463d5ace945SErwin T Tsaur 			if (errno != EFAULT) {
1464d5ace945SErwin T Tsaur 				(void) fprintf(stderr, "Pcitool status: %s\n",
1465d5ace945SErwin T Tsaur 				    strstatus(iget_p->status));
1466d5ace945SErwin T Tsaur 			}
1467d5ace945SErwin T Tsaur 		}
1468d5ace945SErwin T Tsaur 		return (errno);
1469d5ace945SErwin T Tsaur 	}
1470d5ace945SErwin T Tsaur 
1471d5ace945SErwin T Tsaur 	/* Nothing to report for this interrupt. */
1472d5ace945SErwin T Tsaur 	if (iget_p->num_devs == 0) {
1473d5ace945SErwin T Tsaur 		return (SUCCESS);
1474d5ace945SErwin T Tsaur 	}
1475d5ace945SErwin T Tsaur 
1476d5ace945SErwin T Tsaur 	/* Need more room to return additional device info. */
1477d5ace945SErwin T Tsaur 	if (iget_p->num_devs_ret < iget_p->num_devs) {
1478d5ace945SErwin T Tsaur 		iget_p = *iget_pp =
1479d5ace945SErwin T Tsaur 		    realloc(iget_p, PCITOOL_IGET_SIZE(iget_p->num_devs));
1480d5ace945SErwin T Tsaur 		iget_p->num_devs_ret = iget_p->num_devs;
148109b1eac2SEvan Yan 
1482d5ace945SErwin T Tsaur 		if (ioctl(fd, PCITOOL_DEVICE_GET_INTR, iget_p) != 0) {
1483d5ace945SErwin T Tsaur 			if (!(IS_QUIET(input_args_p->flags))) {
148409b1eac2SEvan Yan 				(void) fprintf(stderr, "Ioctl to get %s 0x%x"
148509b1eac2SEvan Yan 				    "device info failed: %s\n", str_type,
148609b1eac2SEvan Yan 				    intr, strerror(errno));
1487d5ace945SErwin T Tsaur 				if (errno != EFAULT) {
1488d5ace945SErwin T Tsaur 					(void) fprintf(stderr,
1489d5ace945SErwin T Tsaur 					    "Pcitool status: %s\n",
1490d5ace945SErwin T Tsaur 					    strstatus(iget_p->status));
1491d5ace945SErwin T Tsaur 				}
1492d5ace945SErwin T Tsaur 			}
1493d5ace945SErwin T Tsaur 			return (errno);
1494d5ace945SErwin T Tsaur 		}
1495d5ace945SErwin T Tsaur 	}
1496d5ace945SErwin T Tsaur 
1497d5ace945SErwin T Tsaur 	print_intr_info(iget_p);
1498d5ace945SErwin T Tsaur 	return (SUCCESS);
1499d5ace945SErwin T Tsaur }
1500d5ace945SErwin T Tsaur 
1501d5ace945SErwin T Tsaur #define	INIT_NUM_DEVS	0
1502d5ace945SErwin T Tsaur 
1503d5ace945SErwin T Tsaur static int
1504d5ace945SErwin T Tsaur get_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1505d5ace945SErwin T Tsaur {
1506d5ace945SErwin T Tsaur 	int rval = SUCCESS;	/* Return status. */
1507d5ace945SErwin T Tsaur 
1508d5ace945SErwin T Tsaur 	/*
1509d5ace945SErwin T Tsaur 	 * Start with a struct with space for info of INIT_NUM_DEVS devs
1510d5ace945SErwin T Tsaur 	 * to be returned.
1511d5ace945SErwin T Tsaur 	 */
1512d5ace945SErwin T Tsaur 	pcitool_intr_get_t *iget_p = malloc(PCITOOL_IGET_SIZE(INIT_NUM_DEVS));
1513d5ace945SErwin T Tsaur 
1514d5ace945SErwin T Tsaur 	iget_p->num_devs_ret = INIT_NUM_DEVS;
1515d5ace945SErwin T Tsaur 	iget_p->user_version = PCITOOL_VERSION;
1516d5ace945SErwin T Tsaur 
151709b1eac2SEvan Yan 	/* Explicit MSI requested. */
151809b1eac2SEvan Yan 	if (input_args_p->flags & MSI_SPEC_FLAG) {
151909b1eac2SEvan Yan 		iget_p->msi = input_args_p->intr_msi;
152009b1eac2SEvan Yan 		iget_p->flags = PCITOOL_INTR_FLAG_GET_MSI;
1521d5ace945SErwin T Tsaur 		rval = get_single_interrupt(fd, &iget_p, input_args_p);
152209b1eac2SEvan Yan 		/* Return all MSIs. */
152309b1eac2SEvan Yan 	} else if (input_args_p->flags & MSI_ALL_FLAG) {
1524d5ace945SErwin T Tsaur 		pcitool_intr_info_t intr_info;
152509b1eac2SEvan Yan 		intr_info.flags = PCITOOL_INTR_FLAG_GET_MSI;
1526d5ace945SErwin T Tsaur 
1527d5ace945SErwin T Tsaur 		if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) {
1528d5ace945SErwin T Tsaur 			if (!(IS_QUIET(input_args_p->flags))) {
1529d5ace945SErwin T Tsaur 				(void) fprintf(stderr,
1530d5ace945SErwin T Tsaur 				    "intr info ioctl failed: %s\n",
1531d5ace945SErwin T Tsaur 				    strerror(errno));
1532d5ace945SErwin T Tsaur 			}
1533d5ace945SErwin T Tsaur 		} else {
153409b1eac2SEvan Yan 			int msi;
1535d5ace945SErwin T Tsaur 
153609b1eac2SEvan Yan 			/*
153709b1eac2SEvan Yan 			 * Search through all interrupts.
153809b1eac2SEvan Yan 			 * Display info on enabled ones.
153909b1eac2SEvan Yan 			 */
154009b1eac2SEvan Yan 			for (msi = 0;
154109b1eac2SEvan Yan 			    ((msi < intr_info.num_intr) && (rval == SUCCESS));
154209b1eac2SEvan Yan 			    msi++) {
154309b1eac2SEvan Yan 				bzero(iget_p, sizeof (pcitool_intr_get_t));
154409b1eac2SEvan Yan 				iget_p->num_devs_ret = INIT_NUM_DEVS;
154509b1eac2SEvan Yan 				iget_p->user_version = PCITOOL_VERSION;
154609b1eac2SEvan Yan 				iget_p->flags = PCITOOL_INTR_FLAG_GET_MSI;
154709b1eac2SEvan Yan 				iget_p->msi = msi;
154809b1eac2SEvan Yan 				rval = get_single_interrupt(
154909b1eac2SEvan Yan 				    fd, &iget_p, input_args_p);
155009b1eac2SEvan Yan 			}
155109b1eac2SEvan Yan 		}
155209b1eac2SEvan Yan 		/* Explicit INO requested. */
155309b1eac2SEvan Yan 	} else if (input_args_p->flags & INO_SPEC_FLAG) {
155409b1eac2SEvan Yan 		iget_p->ino = input_args_p->intr_ino;
155509b1eac2SEvan Yan 		rval = get_single_interrupt(fd, &iget_p, input_args_p);
155609b1eac2SEvan Yan 		/* Return all INOs. */
155709b1eac2SEvan Yan 	} else if (input_args_p->flags & INO_ALL_FLAG) {
155809b1eac2SEvan Yan 		pcitool_intr_info_t intr_info;
155909b1eac2SEvan Yan 		intr_info.flags = 0;
156009b1eac2SEvan Yan 
156109b1eac2SEvan Yan 		if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) {
156209b1eac2SEvan Yan 			if (!(IS_QUIET(input_args_p->flags))) {
156309b1eac2SEvan Yan 				(void) fprintf(stderr,
156409b1eac2SEvan Yan 				    "intr info ioctl failed: %s\n",
156509b1eac2SEvan Yan 				    strerror(errno));
156609b1eac2SEvan Yan 			}
156709b1eac2SEvan Yan 		} else {
1568d5ace945SErwin T Tsaur 			int ino;
1569d5ace945SErwin T Tsaur 
1570d5ace945SErwin T Tsaur 			/*
1571d5ace945SErwin T Tsaur 			 * Search through all interrupts.
1572d5ace945SErwin T Tsaur 			 * Display info on enabled ones.
1573d5ace945SErwin T Tsaur 			 */
1574d5ace945SErwin T Tsaur 			for (ino = 0;
1575d5ace945SErwin T Tsaur 			    ((ino < intr_info.num_intr) && (rval == SUCCESS));
1576d5ace945SErwin T Tsaur 			    ino++) {
157709b1eac2SEvan Yan 				bzero(iget_p, sizeof (pcitool_intr_get_t));
157809b1eac2SEvan Yan 				iget_p->num_devs_ret = INIT_NUM_DEVS;
157909b1eac2SEvan Yan 				iget_p->user_version = PCITOOL_VERSION;
1580d5ace945SErwin T Tsaur 				iget_p->ino = ino;
1581d5ace945SErwin T Tsaur 				rval = get_single_interrupt(
1582d5ace945SErwin T Tsaur 				    fd, &iget_p, input_args_p);
1583d5ace945SErwin T Tsaur 			}
1584d5ace945SErwin T Tsaur 		}
1585d5ace945SErwin T Tsaur 	}
1586d5ace945SErwin T Tsaur 
1587d5ace945SErwin T Tsaur 	free(iget_p);
1588d5ace945SErwin T Tsaur 
1589d5ace945SErwin T Tsaur 	return (rval);
1590d5ace945SErwin T Tsaur }
1591d5ace945SErwin T Tsaur 
1592d5ace945SErwin T Tsaur 
1593d5ace945SErwin T Tsaur static int
1594d5ace945SErwin T Tsaur get_interrupt_ctlr(int fd, pcitool_uiargs_t *input_args_p)
1595d5ace945SErwin T Tsaur {
1596d5ace945SErwin T Tsaur 	pcitool_intr_info_t intr_info;
1597d5ace945SErwin T Tsaur 	char *ctlr_type = NULL;
1598d5ace945SErwin T Tsaur 	int rval = SUCCESS;
1599d5ace945SErwin T Tsaur 
160009b1eac2SEvan Yan 	intr_info.flags = 0;
1601d5ace945SErwin T Tsaur 	if (ioctl(fd, PCITOOL_SYSTEM_INTR_INFO, &intr_info) != 0) {
1602d5ace945SErwin T Tsaur 		if (!(IS_QUIET(input_args_p->flags))) {
1603d5ace945SErwin T Tsaur 			(void) perror("Ioctl to get intr ctlr info failed");
1604d5ace945SErwin T Tsaur 		}
1605d5ace945SErwin T Tsaur 		rval = errno;
1606d5ace945SErwin T Tsaur 
1607d5ace945SErwin T Tsaur 	} else {
1608d5ace945SErwin T Tsaur 		(void) fputs("Controller type: ", stdout);
1609d5ace945SErwin T Tsaur 		switch (intr_info.ctlr_type) {
1610d5ace945SErwin T Tsaur 		case PCITOOL_CTLR_TYPE_RISC:
1611d5ace945SErwin T Tsaur 			ctlr_type = "RISC";
1612d5ace945SErwin T Tsaur 			break;
1613d5ace945SErwin T Tsaur 		case PCITOOL_CTLR_TYPE_UPPC:
1614d5ace945SErwin T Tsaur 			ctlr_type = "UPPC";
1615d5ace945SErwin T Tsaur 			break;
1616d5ace945SErwin T Tsaur 		case PCITOOL_CTLR_TYPE_PCPLUSMP:
1617d5ace945SErwin T Tsaur 			ctlr_type = "PCPLUSMP";
1618d5ace945SErwin T Tsaur 			break;
1619d5ace945SErwin T Tsaur 		default:
1620d5ace945SErwin T Tsaur 			break;
1621d5ace945SErwin T Tsaur 		}
1622d5ace945SErwin T Tsaur 
1623d5ace945SErwin T Tsaur 		if (ctlr_type == NULL) {
1624d5ace945SErwin T Tsaur 			(void) printf("Unknown or new (%d)",
1625d5ace945SErwin T Tsaur 			    intr_info.ctlr_type);
1626d5ace945SErwin T Tsaur 		} else {
1627d5ace945SErwin T Tsaur 			(void) fputs(ctlr_type, stdout);
1628d5ace945SErwin T Tsaur 		}
1629d5ace945SErwin T Tsaur 
1630d5ace945SErwin T Tsaur #ifdef __x86
1631d5ace945SErwin T Tsaur 		if (intr_info.ctlr_type == PCITOOL_CTLR_TYPE_PCPLUSMP)
1632d5ace945SErwin T Tsaur 			(void) printf(", IO APIC version: 0x%x, "
1633d5ace945SErwin T Tsaur 			    "local APIC version: 0x%x\n",
1634d5ace945SErwin T Tsaur 			    PSMAT_IO_APIC_VER(intr_info.ctlr_version),
1635d5ace945SErwin T Tsaur 			    PSMAT_LOCAL_APIC_VER(intr_info.ctlr_version));
1636d5ace945SErwin T Tsaur 		else
1637d5ace945SErwin T Tsaur #endif /* __x86 */
1638d5ace945SErwin T Tsaur 			(void) printf(", version: %2.2x.%2.2x.%2.2x.%2.2x\n",
1639d5ace945SErwin T Tsaur 			    ((intr_info.ctlr_version >> 24) & 0xff),
1640d5ace945SErwin T Tsaur 			    ((intr_info.ctlr_version >> 16) & 0xff),
1641d5ace945SErwin T Tsaur 			    ((intr_info.ctlr_version >> 8) & 0xff),
1642d5ace945SErwin T Tsaur 			    (intr_info.ctlr_version & 0xff));
1643d5ace945SErwin T Tsaur 	}
1644d5ace945SErwin T Tsaur 
1645d5ace945SErwin T Tsaur 	return (rval);
1646d5ace945SErwin T Tsaur }
1647d5ace945SErwin T Tsaur 
1648d5ace945SErwin T Tsaur /*
1649d5ace945SErwin T Tsaur  *
1650d5ace945SErwin T Tsaur  * fd is the file descriptor of the nexus being changed.
1651d5ace945SErwin T Tsaur  * input_args are commandline options entered by the user.
1652d5ace945SErwin T Tsaur  */
1653d5ace945SErwin T Tsaur static int
1654d5ace945SErwin T Tsaur set_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1655d5ace945SErwin T Tsaur {
165609b1eac2SEvan Yan 	pcitool_intr_set_t	iset;
165709b1eac2SEvan Yan 	const char		*str_type = NULL;
165809b1eac2SEvan Yan 	uint32_t		intr;
1659d5ace945SErwin T Tsaur 	int			rval = SUCCESS;	/* Return status. */
1660d5ace945SErwin T Tsaur 
1661d5ace945SErwin T Tsaur 	/* Load interrupt number and cpu from commandline. */
166209b1eac2SEvan Yan 	if (input_args_p->flags & MSI_SPEC_FLAG) {
166309b1eac2SEvan Yan 		iset.msi = intr = input_args_p->intr_msi;
166409b1eac2SEvan Yan 		iset.flags = PCITOOL_INTR_FLAG_SET_MSI;
166509b1eac2SEvan Yan 		str_type = "msi";
166609b1eac2SEvan Yan 	} else {
166709b1eac2SEvan Yan 		iset.ino = intr = input_args_p->intr_ino;
166809b1eac2SEvan Yan 		iset.flags = 0;
166909b1eac2SEvan Yan 		str_type = "ino";
167009b1eac2SEvan Yan 	}
167109b1eac2SEvan Yan 
1672d5ace945SErwin T Tsaur 	iset.cpu_id = input_args_p->intr_cpu;
1673d5ace945SErwin T Tsaur 	iset.user_version = PCITOOL_VERSION;
167409b1eac2SEvan Yan 	iset.flags |= (input_args_p->flags & SETGRP_FLAG) ?
167509b1eac2SEvan Yan 	    PCITOOL_INTR_FLAG_SET_GROUP : 0;
1676d5ace945SErwin T Tsaur 
1677d5ace945SErwin T Tsaur 	/* Do the deed. */
1678d5ace945SErwin T Tsaur 	if (ioctl(fd, PCITOOL_DEVICE_SET_INTR, &iset) != 0) {
1679d5ace945SErwin T Tsaur 		if (!(IS_QUIET(input_args_p->flags))) {
1680d5ace945SErwin T Tsaur 			(void) fprintf(stderr,
168109b1eac2SEvan Yan 			    "Ioctl to set %s 0x%x failed: %s\n",
168209b1eac2SEvan Yan 			    str_type, intr, strerror(errno));
1683d5ace945SErwin T Tsaur 			(void) fprintf(stderr, "pcitool status: %s\n",
1684d5ace945SErwin T Tsaur 			    strstatus(iset.status));
1685d5ace945SErwin T Tsaur 		}
1686d5ace945SErwin T Tsaur 		rval = errno;
1687d5ace945SErwin T Tsaur 	} else {
1688d5ace945SErwin T Tsaur 		if (input_args_p->flags & SETGRP_FLAG) {
168909b1eac2SEvan Yan 			(void) printf("\nInterrupts on %s group starting "
169009b1eac2SEvan Yan 			    "at %s 0x%x reassigned:", str_type, str_type, intr);
1691d5ace945SErwin T Tsaur 		} else {
169209b1eac2SEvan Yan 			(void) printf("\nInterrupts on %s 0x%x reassigned:",
169309b1eac2SEvan Yan 			    str_type, intr);
1694d5ace945SErwin T Tsaur 		}
169509b1eac2SEvan Yan 		(void) printf(" Old cpu: 0x%x, New cpu: 0x%x\n", iset.cpu_id,
1696d5ace945SErwin T Tsaur 		    input_args_p->intr_cpu);
1697d5ace945SErwin T Tsaur 	}
1698d5ace945SErwin T Tsaur 
1699d5ace945SErwin T Tsaur 	return (rval);
1700d5ace945SErwin T Tsaur }
1701d5ace945SErwin T Tsaur 
1702d5ace945SErwin T Tsaur 
1703d5ace945SErwin T Tsaur static int
1704d5ace945SErwin T Tsaur do_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1705d5ace945SErwin T Tsaur {
1706d5ace945SErwin T Tsaur 	if (input_args_p->flags & READ_FLAG) {
1707d5ace945SErwin T Tsaur 
1708d5ace945SErwin T Tsaur 		int gic_rval;
1709d5ace945SErwin T Tsaur 		int gi_rval;
1710d5ace945SErwin T Tsaur 
1711d5ace945SErwin T Tsaur 		if (input_args_p->flags &  SHOWCTLR_FLAG) {
1712d5ace945SErwin T Tsaur 			gic_rval = get_interrupt_ctlr(fd, input_args_p);
1713d5ace945SErwin T Tsaur 		}
1714d5ace945SErwin T Tsaur 
1715d5ace945SErwin T Tsaur 		gi_rval = get_interrupts(fd, input_args_p);
1716d5ace945SErwin T Tsaur 		return ((gi_rval != SUCCESS) ? gi_rval : gic_rval);
1717d5ace945SErwin T Tsaur 
1718d5ace945SErwin T Tsaur 	} else {
1719d5ace945SErwin T Tsaur 
1720d5ace945SErwin T Tsaur 		return (set_interrupts(fd, input_args_p));
1721d5ace945SErwin T Tsaur 	}
1722d5ace945SErwin T Tsaur }
1723d5ace945SErwin T Tsaur 
1724d5ace945SErwin T Tsaur 
1725d5ace945SErwin T Tsaur /* *********** Where it all begins... ************* */
1726d5ace945SErwin T Tsaur 
1727d5ace945SErwin T Tsaur int
1728d5ace945SErwin T Tsaur main(int argc, char **argv)
1729d5ace945SErwin T Tsaur {
1730d5ace945SErwin T Tsaur 	pcitool_uiargs_t input_args;	/* Commandline args. */
1731d5ace945SErwin T Tsaur 	int fd;				/* Nexus file descriptor. */
1732d5ace945SErwin T Tsaur 	int rval = SUCCESS;		/* Return status value. */
1733d5ace945SErwin T Tsaur 
1734d5ace945SErwin T Tsaur 
1735d5ace945SErwin T Tsaur 	/* Get commandline args and options from user. */
1736d5ace945SErwin T Tsaur 	if (get_commandline_args(argc, argv, &input_args) != SUCCESS) {
1737d5ace945SErwin T Tsaur 		return (EINVAL);
1738d5ace945SErwin T Tsaur 	}
1739d5ace945SErwin T Tsaur 
1740d5ace945SErwin T Tsaur 	/* Help. */
1741d5ace945SErwin T Tsaur 	if (!(input_args.flags & ALL_COMMANDS))
1742d5ace945SErwin T Tsaur 		return (SUCCESS);
1743d5ace945SErwin T Tsaur 
1744d5ace945SErwin T Tsaur 	/*
1745d5ace945SErwin T Tsaur 	 * Probe mode.
1746d5ace945SErwin T Tsaur 	 * Nexus is provided as argv[1] unless PROBEALL mode.
1747d5ace945SErwin T Tsaur 	 */
1748d5ace945SErwin T Tsaur 	if (input_args.flags & PROBE_FLAGS) {
1749d5ace945SErwin T Tsaur 		rval = do_probe_walk(&input_args,
1750d5ace945SErwin T Tsaur 		    ((input_args.flags & PROBEALL_FLAG) ? NULL : argv[1]));
1751d5ace945SErwin T Tsaur 
1752d5ace945SErwin T Tsaur 	} else if ((fd = open_node(argv[1], &input_args)) >= 0) {
1753d5ace945SErwin T Tsaur 		if (input_args.flags & (NEXUS_FLAG | LEAF_FLAG)) {
1754d5ace945SErwin T Tsaur 			(void) signal(SIGINT, signal_handler);
1755d5ace945SErwin T Tsaur 			(void) signal(SIGTERM, signal_handler);
1756d5ace945SErwin T Tsaur 			rval = do_device_or_nexus(fd, &input_args);
1757d5ace945SErwin T Tsaur 		} else if (input_args.flags & INTR_FLAG) {
1758d5ace945SErwin T Tsaur 			rval = do_interrupts(fd, &input_args);
1759d5ace945SErwin T Tsaur 		} else {
1760d5ace945SErwin T Tsaur 			/* Should never see this. */
1761d5ace945SErwin T Tsaur 			(void) fprintf(stderr, "Nothing to do.\n");
1762d5ace945SErwin T Tsaur 			rval = ENOTTY;
1763d5ace945SErwin T Tsaur 		}
1764d5ace945SErwin T Tsaur 
1765d5ace945SErwin T Tsaur 		(void) close(fd);
1766d5ace945SErwin T Tsaur 	}
1767d5ace945SErwin T Tsaur 
1768d5ace945SErwin T Tsaur 	return (rval);
1769d5ace945SErwin T Tsaur }
1770