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