xref: /illumos-gate/usr/src/cmd/pcitool/pcitool.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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. */
52 typedef 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. */
58 typedef 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. */
66 typedef 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. */
87 static 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. */
124 static boolean_t keep_looping = B_TRUE;
125 
126 static void signal_handler(int dummy);
127 static char *strstatus(pcitool_errno_t pcitool_status);
128 static int open_node(char *device, pcitool_uiargs_t *input_args_p);
129 static void print_probe_value(pci_conf_hdr_t *config_hdr_p, uint16_t offset,
130     uint8_t size);
131 static void print_probe_info_verbose(pci_conf_hdr_t *config_hdr_p,
132     pcitool_reg_t *info_p);
133 static void print_probe_info_nonverbose(pci_conf_hdr_t *config_hdr_p,
134     pcitool_reg_t *info_p);
135 static void print_probe_info(pci_conf_hdr_t *config_hdr_p,
136     pcitool_reg_t *info_p, boolean_t verbose);
137 static 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);
139 static int supports_ari(int fd, uint8_t bus_no);
140 static int probe_dev(int fd, pcitool_reg_t *prg_p,
141     pcitool_uiargs_t *input_args_p);
142 static int do_probe(int fd, di_node_t di_node, di_prom_handle_t di_phdl,
143     pcitool_uiargs_t *input_args_p);
144 static int process_nexus_node(di_node_t node, di_minor_t minor, void *arg);
145 static int do_probe_walk(pcitool_uiargs_t *input_args_p, char *pathname);
146 static void print_bytedump_header(boolean_t do_chardump);
147 static int bytedump_get(int fd, int cmd, pcitool_reg_t *prg_p,
148     pcitool_uiargs_t *input_args_p);
149 static uint32_t set_acc_attr(pcitool_uiargs_t *input_args_p);
150 static int do_single_access(int fd, int cmd, pcitool_reg_t *prg_p,
151     pcitool_uiargs_t *input_args_p);
152 static int do_device_or_nexus(int fd, pcitool_uiargs_t *input_args_p);
153 static void print_intr_info(pcitool_intr_get_t *iget_p);
154 static int get_single_interrupt(int fd, pcitool_intr_get_t **iget_pp,
155     pcitool_uiargs_t *input_args_p);
156 static int get_interrupts(int fd, pcitool_uiargs_t *input_args_p);
157 static int set_interrupts(int fd, pcitool_uiargs_t *input_args_p);
158 static 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*/
167 static void
168 signal_handler(int dummy)
169 {
170 	keep_looping = B_FALSE;
171 }
172 
173 
174 /*
175  * Print string based on PCItool status returned from driver.
176  */
177 static char *
178 strstatus(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 
193 static int
194 open_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. */
260 static 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. */
275 static 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. */
287 static 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. */
295 static 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 
302 static void
303 print_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 
323 static void
324 print_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 
376 static void
377 print_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 
400 static void
401 print_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  */
435 static int
436 get_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 
464 static int
465 supports_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  */
582 static int
583 probe_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  */
740 static int
741 do_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*/
854 static int
855 process_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  */
928 static int
929 do_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 
970 static void
971 print_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  */
1007 static int
1008 bytedump_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  */
1230 static uint32_t
1231 set_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 
1257 static int
1258 do_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  */
1315 static int
1316 do_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  */
1401 static void
1402 print_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  */
1426 static int
1427 get_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 
1503 static int
1504 get_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 
1593 static int
1594 get_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  */
1653 static int
1654 set_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 
1703 static int
1704 do_interrupts(int fd, pcitool_uiargs_t *input_args_p)
1705 {
1706 	if (input_args_p->flags & READ_FLAG) {
1707 
1708 		int gic_rval = SUCCESS;
1709 		int gi_rval = SUCCESS;
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 
1727 int
1728 main(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