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