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