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