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