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