2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <alloca.h>
2N/A#include <unistd.h>
2N/A#include <ctype.h>
2N/A#include <string.h>
2N/A#include <kvm.h>
2N/A#include <varargs.h>
2N/A#include <time.h>
2N/A#include <dirent.h>
2N/A#include <fcntl.h>
2N/A#include <sys/param.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/types.h>
2N/A#include <sys/utsname.h>
2N/A#include <sys/openpromio.h>
2N/A#include <libintl.h>
2N/A#include <syslog.h>
2N/A#include <sys/dkio.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <picldefs.h>
2N/A#include <math.h>
2N/A#include <errno.h>
2N/A#include "pdevinfo.h"
2N/A#include "display.h"
2N/A#include "display_sun4v.h"
2N/A#include "libprtdiag.h"
2N/A#include <sys/pci_tools.h>
2N/A#include <sys/pci.h>
2N/A
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A#define MOTHERBOARD "MB"
2N/A#define NETWORK "network"
2N/A#define SUN4V_MACHINE "sun4v"
2N/A#define PARENT_NAMES 10
2N/A
2N/A/*
2N/A * Additional OBP properties
2N/A */
2N/A#define OBP_PROP_COMPATIBLE "compatible"
2N/A#define OBP_PROP_MODEL "model"
2N/A#define OBP_PROP_SLOT_NAMES "slot-names"
2N/A#define OBP_PROP_VERSION "version"
2N/A
2N/A#define PICL_NODE_PHYSICAL_PLATFORM "physical-platform"
2N/A#define PICL_NODE_CHASSIS "chassis"
2N/A#define MEMORY_SIZE_FIELD 11
2N/A#define INVALID_THRESHOLD 1000000
2N/A
2N/A/*
2N/A * Additional picl classes
2N/A */
2N/A#ifndef PICL_CLASS_SUN4V
2N/A#define PICL_CLASS_SUN4V "sun4v"
2N/A#endif
2N/A
2N/A#ifndef PICL_PROP_NAC
2N/A#define PICL_PROP_NAC "nac"
2N/A#endif
2N/A
2N/A#define PRINT_FMT(arg_1, arg_2) \
2N/A if (((arg_1) != PROP_INVALID) && \
2N/A ((arg_2) != PROP_INVALID)) \
2N/A log_printf("%-1.1fGTx%d", (arg_1), (arg_2)); \
2N/A else if ((arg_2) != PROP_INVALID) \
2N/A log_printf("--x%d", (arg_2)); \
2N/A else if ((arg_1) != PROP_INVALID) \
2N/A log_printf("%-1.1f", (arg_1)); \
2N/A else \
2N/A log_printf("--");
2N/A
2N/A#define PRINT_FREQ_FMT(arg_1) \
2N/A if ((arg_1) != 0) \
2N/A log_printf("%3d", (arg_1)); \
2N/A else \
2N/A log_printf("--");
2N/A
2N/A#define PROP_INVALID -1
2N/A#define PICL_PROP_MIRROR_MODE "mirror-mode"
2N/A#define OBP_PROP_REG "reg"
2N/A
2N/A/* PCI BUS types */
2N/A
2N/A#define PCI_UNKN -1
2N/A#define PCI_BUSTYPE 10
2N/A#define PCIX_BUSTYPE 20
2N/A#define PCIE_BUSTYPE 30
2N/A
2N/A/* PCI device defines */
2N/A
2N/A#define PCI_CONF_CAP_PTR 0x34 /* 1 byte capability pointer */
2N/A#define PCI_CAP_ID_PCI_E 0x10 /* PCI Express supported */
2N/A#define PCIE_LINKCAP 0x0C /* Link Capability */
2N/A#define PCIE_LINKSTS 0x12 /* Link Status */
2N/A#define PCI_CAP_MASK 0xff /* CAP Mask */
2N/A#define PCI_DEV_MASK 0xF800 /* Dev# Mask */
2N/A#define PCI_FUNC_MASK 0x700 /* Func# Mask */
2N/A#define PCI_BUS_MASK 0x1ff0000 /* Bus# Mask */
2N/A#define PCI_LINK_MASK 0x1f /* Link Mask */
2N/A#define PCI_SPEED_MASK 0xf /* Speed Mask */
2N/A
2N/A#define PCI_LINK_SHIFT 4 /* Link shift Bits */
2N/A#define PCI_FREQ_33 33 /* legacy PCI default freq */
2N/A#define PCI_FREQ_66 66 /* PCI default freq */
2N/A#define PCI_FREQ_100 100
2N/A
2N/A/* PCI frequencies */
2N/A
2N/A#define PCI_FREQ_133 133
2N/A#define PCI_FREQ_266 266
2N/A#define PCI_FREQ_533 533
2N/A
2N/A/* PCI frequency shift bits */
2N/A
2N/A#define PCI_SHIFT_133 17
2N/A#define PCI_SHIFT_266 30
2N/A#define PCI_SHIFT_533 31
2N/A
2N/A/* PCI frequency modes */
2N/A
2N/A#define PCI_MODE_66 1
2N/A#define PCI_MODE_100 2
2N/A#define PCI_MODE_133 3
2N/A
2N/A/* PCI frequency SEC status masks */
2N/A
2N/A#define PCI_SEC_133 0x2
2N/A#define PCI_SEC_266 0x4000
2N/A#define PCI_SEC_533 0x8000
2N/A#define PCI_LEAF_ULONG 1UL
2N/A
2N/A/* PCIE Speeds */
2N/A#define PCIE_SPEED_2_5GT 25
2N/A#define PCIE_SPEED_5_0GT 50
2N/A#define PCIE_SPEED_8_0GT 80
2N/A
2N/A
2N/Aextern int sys_clk;
2N/Aextern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
2N/A picl_nodehdl_t *);
2N/A
2N/Astatic picl_nodehdl_t rooth = 0, phyplatformh = 0;
2N/Astatic picl_nodehdl_t chassish = 0;
2N/Astatic int class_node_found;
2N/Astatic int syserrlog;
2N/Astatic int all_status_ok;
2N/A
2N/A/* local functions */
2N/Astatic int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
2N/Astatic void sun4v_display_memory_conf(picl_nodehdl_t);
2N/Astatic int sun4v_disp_env_status();
2N/Astatic void sun4v_env_print_fan_sensors();
2N/Astatic void sun4v_env_print_fan_indicators();
2N/Astatic void sun4v_env_print_temp_sensors();
2N/Astatic void sun4v_env_print_temp_indicators();
2N/Astatic void sun4v_env_print_current_sensors();
2N/Astatic void sun4v_env_print_current_indicators();
2N/Astatic void sun4v_env_print_voltage_sensors();
2N/Astatic void sun4v_env_print_voltage_indicators();
2N/Astatic void sun4v_env_print_LEDs();
2N/Astatic void sun4v_print_fru_status();
2N/Astatic int is_fru_absent(picl_nodehdl_t);
2N/Astatic void sun4v_print_fw_rev();
2N/Astatic void sun4v_print_chassis_serial_no();
2N/Astatic int openprom_callback(picl_nodehdl_t openpromh, void *arg);
2N/Astatic void sun4v_print_openprom_rev();
2N/A
2N/Astatic uint32_t read_long(int fd, int bus, int dev, int func,
2N/A int offset, int *ret);
2N/Astatic uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
2N/A int *ret);
2N/Astatic uint16_t read_word(int fd, int bus, int dev, int func, int offset,
2N/A int *ret);
2N/Astatic int open_root_complex(char *root_complex);
2N/Astatic picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
2N/A int dev_no, int *cur_link_width, int *cur_speed, uint32_t *speed_max,
2N/A uint32_t *speed_at, int *type);
2N/A
2N/Aint
2N/Asun4v_display(Sys_tree *tree, Prom_node *root, int log,
2N/A picl_nodehdl_t plafh)
2N/A{
2N/A void *value; /* used for opaque PROM data */
2N/A struct mem_total memory_total; /* Total memory in system */
2N/A struct grp_info grps; /* Info on all groups in system */
2N/A char machine[MAXSTRLEN];
2N/A int exit_code = 0;
2N/A
2N/A if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
2N/A return (1);
2N/A if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
2N/A return (1);
2N/A
2N/A sys_clk = -1; /* System clock freq. (in MHz) */
2N/A
2N/A /*
2N/A * Now display the machine's configuration. We do this if we
2N/A * are not logging.
2N/A */
2N/A if (!logging) {
2N/A struct utsname uts_buf;
2N/A
2N/A /*
2N/A * Display system banner
2N/A */
2N/A (void) uname(&uts_buf);
2N/A
2N/A log_printf(dgettext(TEXT_DOMAIN, "System Configuration: "
2N/A "Oracle Corporation %s %s\n"), uts_buf.machine,
2N/A get_prop_val(find_prop(root, "banner-name")), 0);
2N/A
2N/A /* display system clock frequency */
2N/A value = get_prop_val(find_prop(root, "clock-frequency"));
2N/A if (value != NULL) {
2N/A sys_clk = ((*((int *)value)) + 500000) / 1000000;
2N/A log_printf(dgettext(TEXT_DOMAIN, "System clock "
2N/A "frequency: %d MHz\n"), sys_clk, 0);
2N/A }
2N/A
2N/A /* Display the Memory Size */
2N/A display_memorysize(tree, NULL, &grps, &memory_total);
2N/A
2N/A /* Display the CPU devices */
2N/A sun4v_display_cpu_devices(plafh);
2N/A
2N/A /* Display the Memory configuration */
2N/A class_node_found = 0;
2N/A sun4v_display_memory_conf(plafh);
2N/A
2N/A /* Display all the IO cards. */
2N/A (void) sun4v_display_pci(plafh);
2N/A sun4v_display_diaginfo((log || (logging)), root, plafh);
2N/A
2N/A if (picl_get_root(&rooth) != PICL_SUCCESS)
2N/A return (1);
2N/A
2N/A /*
2N/A * The physical-platform node may be missing on systems with
2N/A * older firmware so don't consider that an error.
2N/A */
2N/A if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
2N/A &phyplatformh) != PICL_SUCCESS)
2N/A return (0);
2N/A
2N/A if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
2N/A PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
2N/A strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
2N/A return (1);
2N/A
2N/A syserrlog = log;
2N/A exit_code = sun4v_disp_env_status();
2N/A }
2N/A return (exit_code);
2N/A}
2N/A
2N/A/*
2N/A * The binding-name property encodes the bus type.
2N/A */
2N/Astatic void
2N/Aget_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
2N/A{
2N/A char val[PICL_PROPNAMELEN_MAX], *p, *q;
2N/A
2N/A card->bus_type[0] = '\0';
2N/A
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, val,
2N/A sizeof (val)) == PICL_SUCCESS) {
2N/A if (strstr(val, PICL_CLASS_PCIEX))
2N/A (void) strlcpy(card->bus_type, "PCIE",
2N/A sizeof (card->bus_type));
2N/A else if (strstr(val, PICL_CLASS_PCI))
2N/A (void) strlcpy(card->bus_type, "PCIX",
2N/A sizeof (card->bus_type));
2N/A else {
2N/A /*
2N/A * Not perfect: process the binding-name until
2N/A * we encounter something that we don't think would
2N/A * be part of a bus type. This may get confused a bit
2N/A * if a device or vendor id is encoded right after
2N/A * the bus class since there's no delimiter. If the
2N/A * id number begins with a hex digit [abcdef] then
2N/A * this will become part of the bus type string
2N/A * reported by prtdiag. This is all an effort to
2N/A * print something potentially useful for bus types
2N/A * other than PCI/PCIe.
2N/A *
2N/A * We do this because this code will get called for
2N/A * non-PCI class devices like the xaui (class sun4v.)
2N/A */
2N/A if (strstr(val, "SUNW,") != NULL)
2N/A p = strchr(val, ',') + 1;
2N/A else
2N/A p = val;
2N/A q = p;
2N/A while (*p != '\0') {
2N/A if (isdigit((char)*p) || ispunct((char)*p)) {
2N/A *p = '\0';
2N/A break;
2N/A }
2N/A *p = (char)_toupper((int)*p);
2N/A ++p;
2N/A }
2N/A (void) strlcpy(card->bus_type, q,
2N/A sizeof (card->bus_type));
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Fetch the Label property for this device. If none is found then
2N/A * search all the siblings with the same device ID for a
2N/A * Label and return that Label. The plug-in can only match the canonical
2N/A * path from the PRI with a specific devfs path. So we take care of
2N/A * devices with multiple functions here. A leaf device downstream of
2N/A * a bridge should fall out of here with PICL_PROPNOTFOUND, and the
2N/A * caller can walk back up the tree in search of the slot's Label.
2N/A */
2N/Astatic picl_errno_t
2N/Aget_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
2N/A{
2N/A char val[PICL_PROPNAMELEN_MAX];
2N/A picl_errno_t err;
2N/A picl_nodehdl_t pnodeh;
2N/A uint32_t devid, sib_devid;
2N/A int32_t instance;
2N/A
2N/A /*
2N/A * If there's a Label at this node then return it - we're
2N/A * done.
2N/A */
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
2N/A sizeof (val));
2N/A if (err == PICL_SUCCESS) {
2N/A (void) strlcpy(card->slot_str, val, sizeof (card->slot_str));
2N/A return (err);
2N/A } else if (err != PICL_PROPNOTFOUND)
2N/A return (err);
2N/A
2N/A /*
2N/A * At this point we're starting to extrapolate what the Label
2N/A * should be since there is none at this specific node.
2N/A * Note that until the value of "err" is overwritten in the
2N/A * loop below, its value should be PICL_PROPNOTFOUND.
2N/A */
2N/A
2N/A /*
2N/A * The device must be attached, and we can figure that out if
2N/A * the instance number is present and is not equal to -1.
2N/A * This will prevent is from returning a Label for a sibling
2N/A * node when the node passed in would have a unique Label if the
2N/A * device were attached. But if the device is downstream of a
2N/A * node with a Label then pci_callback() will still find that
2N/A * and use it.
2N/A */
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_INSTANCE, &instance,
2N/A sizeof (instance)) != PICL_SUCCESS)
2N/A return (err);
2N/A if (instance == -1)
2N/A return (err);
2N/A
2N/A /*
2N/A * Narrow the search to just the one device ID.
2N/A */
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_DEVICE_ID, &devid,
2N/A sizeof (devid)) != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*
2N/A * Go find the first child of the parent so we can search
2N/A * all of the siblings.
2N/A */
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
2N/A sizeof (pnodeh)) != PICL_SUCCESS)
2N/A return (err);
2N/A if (picl_get_propval_by_name(pnodeh, PICL_PROP_CHILD, &pnodeh,
2N/A sizeof (pnodeh)) != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*
2N/A * If the child's device ID matches, then fetch the Label and
2N/A * return it. The first child/device ID should have a Label
2N/A * associated with it.
2N/A */
2N/A do {
2N/A if (picl_get_propval_by_name(pnodeh, PICL_PROP_DEVICE_ID,
2N/A &sib_devid, sizeof (sib_devid)) == PICL_SUCCESS) {
2N/A if (sib_devid == devid) {
2N/A if ((err = picl_get_propval_by_name(pnodeh,
2N/A PICL_PROP_LABEL, val, sizeof (val))) ==
2N/A PICL_SUCCESS) {
2N/A (void) strlcpy(card->slot_str, val,
2N/A sizeof (card->slot_str));
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A } while (picl_get_propval_by_name(pnodeh, PICL_PROP_PEER, &pnodeh,
2N/A sizeof (pnodeh)) == PICL_SUCCESS);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic void
2N/Aget_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
2N/A{
2N/A picl_errno_t err;
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A picl_nodehdl_t pnodeh;
2N/A uint8_t *pval;
2N/A uint32_t dev_mask;
2N/A char uaddr[MAXSTRLEN];
2N/A int i;
2N/A
2N/A err = PICL_SUCCESS;
2N/A while (err == PICL_SUCCESS) {
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
2N/A sizeof (pnodeh)) != PICL_SUCCESS) {
2N/A (void) strlcpy(card->slot_str, MOTHERBOARD,
2N/A sizeof (card->slot_str));
2N/A card->slot = -1;
2N/A return;
2N/A }
2N/A if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
2N/A &pinfo, &proph) == PICL_SUCCESS) {
2N/A break;
2N/A }
2N/A nodeh = pnodeh;
2N/A }
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
2N/A sizeof (uaddr)) != PICL_SUCCESS) {
2N/A (void) strlcpy(card->slot_str, MOTHERBOARD,
2N/A sizeof (card->slot_str));
2N/A card->slot = -1;
2N/A return;
2N/A }
2N/A pval = (uint8_t *)malloc(pinfo.size);
2N/A if (!pval) {
2N/A (void) strlcpy(card->slot_str, MOTHERBOARD,
2N/A sizeof (card->slot_str));
2N/A card->slot = -1;
2N/A return;
2N/A }
2N/A if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
2N/A (void) strlcpy(card->slot_str, MOTHERBOARD,
2N/A sizeof (card->slot_str));
2N/A card->slot = -1;
2N/A free(pval);
2N/A return;
2N/A }
2N/A
2N/A dev_mask = 0;
2N/A for (i = 0; i < sizeof (dev_mask); i++)
2N/A dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
2N/A for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
2N/A if (uaddr[i] == ',') {
2N/A uaddr[i] = '\0';
2N/A break;
2N/A }
2N/A }
2N/A card->slot = atol(uaddr);
2N/A if (((1 << card->slot) & dev_mask) == 0) {
2N/A (void) strlcpy(card->slot_str, MOTHERBOARD,
2N/A sizeof (card->slot_str));
2N/A card->slot = -1;
2N/A } else {
2N/A char *p = (char *)(pval+sizeof (dev_mask));
2N/A int shift = sizeof (uint32_t)*8-1-card->slot;
2N/A uint32_t x = (dev_mask << shift) >> shift;
2N/A int count = 0; /* count # of 1's in x */
2N/A int i = 0;
2N/A while (x != 0) {
2N/A count++;
2N/A x &= x-1;
2N/A }
2N/A while (count > 1) {
2N/A while (p[i++] != '\0')
2N/A ;
2N/A count--;
2N/A }
2N/A (void) strlcpy(card->slot_str, (char *)(p+i),
2N/A sizeof (card->slot_str));
2N/A }
2N/A free(pval);
2N/A}
2N/A
2N/Aint
2N/Aget_rc_path(picl_nodehdl_t pnodeh, char *root_path, int size)
2N/A{
2N/A picl_nodehdl_t ppnodeh, root_node;
2N/A picl_errno_t err;
2N/A char path[PICL_PROPNAMELEN_MAX];
2N/A root_node = pnodeh;
2N/A
2N/A do {
2N/A if ((err = picl_get_propval_by_name(root_node,
2N/A PICL_PROP_PARENT, &ppnodeh, sizeof (ppnodeh)))
2N/A == PICL_SUCCESS) {
2N/A if ((err = picl_get_propval_by_name(ppnodeh,
2N/A PICL_PROP_DEVFS_PATH, path, size))
2N/A == PICL_SUCCESS) {
2N/A if (strcmp(path, "/") != 0)
2N/A root_node = ppnodeh;
2N/A else
2N/A break;
2N/A } else
2N/A return (err);
2N/A } else
2N/A return (err);
2N/A } while (err == PICL_SUCCESS);
2N/A /* get path from root node */
2N/A err = picl_get_propval_by_name(root_node, PICL_PROP_DEVFS_PATH,
2N/A root_path, size);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * add all io devices under pci in io list
2N/A */
2N/A/* ARGSUSED */
2N/Astatic int
2N/Asun4v_pci_callback(picl_nodehdl_t pcih, void *args)
2N/A{
2N/A char path[PICL_PROPNAMELEN_MAX];
2N/A char class[PICL_CLASSNAMELEN_MAX];
2N/A char name[PICL_PROPNAMELEN_MAX];
2N/A char model[PICL_PROPNAMELEN_MAX];
2N/A char binding_name[PICL_PROPNAMELEN_MAX];
2N/A char val[PICL_PROPNAMELEN_MAX];
2N/A char *compatible;
2N/A picl_errno_t err;
2N/A picl_nodehdl_t nodeh, pnodeh;
2N/A struct io_card pci_card;
2N/A char root_path[PICL_PROPNAMELEN_MAX];
2N/A
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A int cur_link_width = PROP_INVALID, cur_speed = PROP_INVALID;
2N/A int bus_type;
2N/A uint32_t freq_max = 0, freq_at = 0;
2N/A int *reg_val;
2N/A float fspeed;
2N/A
2N/A /* Walk through the children */
2N/A
2N/A err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A
2N/A while (err == PICL_SUCCESS) {
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2N/A class, sizeof (class));
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (args) {
2N/A char *val = args;
2N/A if (strcmp(class, val) == 0) {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_PEER, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A continue;
2N/A } else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
2N/A strcmp(class, PICL_CLASS_PCI) == 0) {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_PEER, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A continue;
2N/A } else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
2N/A strcmp(class, PICL_CLASS_PCIEX) == 0) {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_PEER, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A continue;
2N/A }
2N/A }
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
2N/A path, sizeof (path));
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
2N/A
2N/A pnodeh = nodeh;
2N/A err = get_slot_label(nodeh, &pci_card);
2N/A
2N/A /*
2N/A * No Label at this node, maybe we're looking at a device
2N/A * downstream of a bridge. Walk back up and find a Label and
2N/A * record that node in "pnodeh".
2N/A */
2N/A while (err != PICL_SUCCESS) {
2N/A if (err != PICL_PROPNOTFOUND)
2N/A break;
2N/A else if (picl_get_propval_by_name(pnodeh,
2N/A PICL_PROP_PARENT, &pnodeh, sizeof (pnodeh)) ==
2N/A PICL_SUCCESS)
2N/A err = get_slot_label(pnodeh, &pci_card);
2N/A else
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Can't find a Label for this device in the PCI hierarchy.
2N/A * Try to synthesize a slot name from atoms. This depends
2N/A * on the OBP slot_names property being implemented, and this
2N/A * so far doesn't seem to be on sun4v. But just in case that
2N/A * is resurrected, the code is here.
2N/A */
2N/A if (err != PICL_SUCCESS) {
2N/A pnodeh = nodeh;
2N/A get_slot_number(nodeh, &pci_card);
2N/A }
2N/A
2N/A /*
2N/A * Passing in pnodeh instead of nodeh will cause prtdiag
2N/A * to display the type of IO slot for the leaf node. For
2N/A * built-in devices and a lot of IO cards these will be
2N/A * the same thing. But for IO cards with bridge chips or
2N/A * for things like expansion chassis, prtdiag will report
2N/A * the bus type of the IO slot and not the leaf, which
2N/A * could be different things.
2N/A */
2N/A get_bus_type(pnodeh, &pci_card);
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
2N/A sizeof (name));
2N/A if (err == PICL_PROPNOTFOUND)
2N/A (void) strlcpy(name, "", sizeof (name));
2N/A else if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
2N/A sizeof (val));
2N/A if (err == PICL_PROPNOTFOUND)
2N/A (void) strlcpy(val, "", sizeof (val));
2N/A else if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A (void) snprintf(pci_card.status, sizeof (pci_card.status),
2N/A "%s", pci_card.slot_str);
2N/A
2N/A /*
2N/A * Get the name of this card. If binding_name is found,
2N/A * name will be <nodename>-<binding_name>.
2N/A */
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
2N/A binding_name, sizeof (binding_name));
2N/A if (err == PICL_SUCCESS) {
2N/A if (strcmp(name, binding_name) != 0) {
2N/A (void) strlcat(name, "-", sizeof (name));
2N/A (void) strlcat(name, binding_name,
2N/A sizeof (name));
2N/A }
2N/A } else if (err == PICL_PROPNOTFOUND) {
2N/A /*
2N/A * if compatible prop is not found, name will be
2N/A * <nodename>-<compatible>
2N/A */
2N/A err = sun4v_get_first_compatible_value(nodeh,
2N/A &compatible);
2N/A if (err == PICL_SUCCESS) {
2N/A (void) strlcat(name, "-", sizeof (name));
2N/A (void) strlcat(name, compatible,
2N/A sizeof (name));
2N/A free(compatible);
2N/A }
2N/A } else
2N/A return (err);
2N/A
2N/A (void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
2N/A
2N/A /* Get the model of this card */
2N/A
2N/A err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
2N/A model, sizeof (model));
2N/A if (err == PICL_PROPNOTFOUND)
2N/A (void) strlcpy(model, "", sizeof (model));
2N/A else if (err != PICL_SUCCESS)
2N/A return (err);
2N/A (void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
2N/A
2N/A /*
2N/A * Fetch values for current lane and speed properties
2N/A */
2N/A err = picl_get_propinfo_by_name(nodeh, OBP_PROP_REG,
2N/A &pinfo, &proph);
2N/A if (err == PICL_SUCCESS) {
2N/A /* All of the array of bytes of "reg" have to be read */
2N/A
2N/A reg_val = (int *)malloc(pinfo.size);
2N/A if (reg_val == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A err = picl_get_propval_by_name(nodeh,
2N/A OBP_PROP_REG, reg_val, pinfo.size);
2N/A
2N/A if ((err == PICL_SUCCESS) &&
2N/A (reg_val[0] != 0)) {
2N/A pci_card.dev_no = (((reg_val[0]) &
2N/A PCI_DEV_MASK) >> 11);
2N/A pci_card.func_no = (((reg_val[0]) &
2N/A PCI_FUNC_MASK) >> 8);
2N/A pci_card.slot = (((reg_val[0]) &
2N/A PCI_BUS_MASK) >> 16);
2N/A
2N/A if ((get_rc_path(pnodeh, root_path,
2N/A sizeof (root_path)) == -1) ||
2N/A
2N/A (get_lane_width(root_path,
2N/A pci_card.slot, pci_card.dev_no,
2N/A pci_card.func_no,
2N/A &cur_link_width, &cur_speed,
2N/A &freq_max, &freq_at, &bus_type)
2N/A != PICL_SUCCESS)) {
2N/A err = PICL_FAILURE;
2N/A }
2N/A } else {
2N/A err = PICL_FAILURE;
2N/A }
2N/A free(reg_val);
2N/A }
2N/A if (err != PICL_SUCCESS) {
2N/A /*
2N/A * get_lane_width will fail when run as
2N/A * non-root. Set bus_type to PCI_UNKN
2N/A * so that bus frequency, bus type and
2N/A * lane width will print as "--" or UNKN.
2N/A */
2N/A bus_type = PCI_UNKN;
2N/A }
2N/A
2N/A /* Print NAC name */
2N/A log_printf("%-18s", pci_card.status);
2N/A /* Print IO Type */
2N/A log_printf("%-6s", pci_card.bus_type);
2N/A /* Printf Card Name */
2N/A log_printf("%-34s", pci_card.name);
2N/A /* Print Card Model */
2N/A log_printf("%-11s", pci_card.model);
2N/A /* Print Card Act Lane/Freq (Uplink Speed) */
2N/A fspeed = ((float)(cur_speed))/10;
2N/A if (bus_type == PCIE_BUSTYPE) {
2N/A PRINT_FMT(fspeed, cur_link_width);
2N/A } else if (bus_type == PCIX_BUSTYPE) {
2N/A PRINT_FREQ_FMT(freq_at);
2N/A } else
2N/A log_printf("--");
2N/A
2N/A log_printf("\n");
2N/A /* Print Status */
2N/A log_printf("%-18s", val);
2N/A /* Print IO Type */
2N/A log_printf("%-6s", "");
2N/A /* Print Parent Path */
2N/A log_printf("%-44s", pci_card.notes);
2N/A log_printf("\n");
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A }
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*
2N/A * display_pci
2N/A * Display all the PCI IO cards on this board.
2N/A */
2N/Avoid
2N/Asun4v_display_pci(picl_nodehdl_t plafh)
2N/A{
2N/A const char *fmt = "%-17s %-5s %-33s %-10s %-8s";
2N/A /* Have we printed the column headings? */
2N/A static int banner = FALSE;
2N/A
2N/A if (banner == FALSE) {
2N/A log_printf("\n");
2N/A log_printf("================================");
2N/A log_printf(" IO Devices ");
2N/A log_printf("================================");
2N/A log_printf("\n");
2N/A log_printf(fmt, "Slot +", "Bus", "Name +", "Model",
2N/A "Speed", 0);
2N/A log_printf("\n");
2N/A log_printf(fmt, "Status", "Type", "Path", "", "", 0);
2N/A log_printf("\n");
2N/A log_printf("---------------------------------"
2N/A "------------------------------------"
2N/A "-------\n");
2N/A banner = TRUE;
2N/A }
2N/A
2N/A (void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
2N/A PICL_CLASS_PCIEX, sun4v_pci_callback);
2N/A (void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
2N/A PICL_CLASS_PCI, sun4v_pci_callback);
2N/A (void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
2N/A PICL_CLASS_SUN4V, sun4v_pci_callback);
2N/A}
2N/A
2N/A/*
2N/A * return the first compatible value
2N/A */
2N/Astatic int
2N/Asun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
2N/A{
2N/A picl_errno_t err;
2N/A picl_prophdl_t proph;
2N/A picl_propinfo_t pinfo;
2N/A picl_prophdl_t tblh;
2N/A picl_prophdl_t rowproph;
2N/A char *pval;
2N/A
2N/A err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
2N/A &pinfo, &proph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A if (pinfo.type == PICL_PTYPE_CHARSTRING) {
2N/A pval = malloc(pinfo.size);
2N/A if (pval == NULL)
2N/A return (PICL_FAILURE);
2N/A err = picl_get_propval(proph, pval, pinfo.size);
2N/A if (err != PICL_SUCCESS) {
2N/A free(pval);
2N/A return (err);
2N/A }
2N/A *outbuf = pval;
2N/A return (PICL_SUCCESS);
2N/A }
2N/A
2N/A if (pinfo.type != PICL_PTYPE_TABLE)
2N/A return (PICL_FAILURE);
2N/A
2N/A /* get first string from table */
2N/A err = picl_get_propval(proph, &tblh, pinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_next_by_row(tblh, &rowproph);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_propinfo(rowproph, &pinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A pval = malloc(pinfo.size);
2N/A if (pval == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A err = picl_get_propval(rowproph, pval, pinfo.size);
2N/A if (err != PICL_SUCCESS) {
2N/A free(pval);
2N/A return (err);
2N/A }
2N/A
2N/A *outbuf = pval;
2N/A return (PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * print size of a memory segment
2N/A */
2N/Astatic void
2N/Aprint_memory_segment_size(uint64_t size)
2N/A{
2N/A uint64_t kbyte = 1024;
2N/A uint64_t mbyte = kbyte * kbyte;
2N/A uint64_t gbyte = kbyte * mbyte;
2N/A uint64_t tbyte = kbyte * gbyte;
2N/A char buf[MEMORY_SIZE_FIELD];
2N/A
2N/A if (size >= tbyte) {
2N/A if (size % tbyte == 0)
2N/A (void) snprintf(buf, sizeof (buf), "%d TB",
2N/A (int)(size / tbyte));
2N/A else
2N/A (void) snprintf(buf, sizeof (buf), "%.2f TB",
2N/A (float)size / tbyte);
2N/A } else if (size >= gbyte) {
2N/A if (size % gbyte == 0)
2N/A (void) snprintf(buf, sizeof (buf), "%d GB",
2N/A (int)(size / gbyte));
2N/A else
2N/A (void) snprintf(buf, sizeof (buf), "%.2f GB",
2N/A (float)size / gbyte);
2N/A } else if (size >= mbyte) {
2N/A if (size % mbyte == 0)
2N/A (void) snprintf(buf, sizeof (buf), "%d MB",
2N/A (int)(size / mbyte));
2N/A else
2N/A (void) snprintf(buf, sizeof (buf), "%.2f MB",
2N/A (float)size / mbyte);
2N/A } else {
2N/A if (size % kbyte == 0)
2N/A (void) snprintf(buf, sizeof (buf), "%d KB",
2N/A (int)(size / kbyte));
2N/A else
2N/A (void) snprintf(buf, sizeof (buf), "%.2f KB",
2N/A (float)size / kbyte);
2N/A }
2N/A log_printf("%-9s", buf);
2N/A}
2N/A
2N/A/*
2N/A * Enumerate banks and dimms within a memory segment. We're handed
2N/A * the first bank within the segment - we assume there are dimms
2N/A * (memory-module) nodes underneath.
2N/A */
2N/Astatic void
2N/Aprint_memory_segment_contain(picl_nodehdl_t bank_nodeh)
2N/A{
2N/A char val[PICL_PROPNAMELEN_MAX];
2N/A picl_nodehdl_t module_nodeh;
2N/A int flag = 0;
2N/A uint64_t size;
2N/A
2N/A do {
2N/A if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD,
2N/A &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
2N/A continue;
2N/A if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_SIZE,
2N/A &size, sizeof (size)) == PICL_SUCCESS) {
2N/A if (!flag) {
2N/A print_memory_segment_size(size);
2N/A } else {
2N/A log_printf(" "
2N/A " ");
2N/A print_memory_segment_size(size);
2N/A flag = 0;
2N/A }
2N/A }
2N/A do {
2N/A if (picl_get_propval_by_name(module_nodeh,
2N/A PICL_PROP_NAC, val, sizeof (val)) !=
2N/A PICL_SUCCESS)
2N/A continue;
2N/A else {
2N/A if (!flag) {
2N/A log_printf("%s\n", val);
2N/A flag = 1;
2N/A } else {
2N/A log_printf("%s%s\n",
2N/A " "
2N/A " ",
2N/A val);
2N/A }
2N/A }
2N/A } while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER,
2N/A &module_nodeh, sizeof (picl_nodehdl_t)) ==
2N/A PICL_SUCCESS);
2N/A } while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER,
2N/A &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Search node where _class=="memory-segment"
2N/A * print "Base Address", "Size", etc
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
2N/A{
2N/A uint64_t base;
2N/A uint64_t size;
2N/A uint64_t ifactor;
2N/A uint64_t mirror_mode = 0;
2N/A
2N/A picl_errno_t err = PICL_SUCCESS;
2N/A
2N/A if (class_node_found == 0) {
2N/A class_node_found = 1;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A while (err == PICL_SUCCESS) {
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
2N/A &base, sizeof (base));
2N/A if (err != PICL_SUCCESS)
2N/A break;
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
2N/A &size, sizeof (size));
2N/A if (err != PICL_SUCCESS)
2N/A break;
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
2N/A sizeof (ifactor));
2N/A if (err != PICL_SUCCESS)
2N/A break;
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_MIRROR_MODE, &mirror_mode,
2N/A sizeof (mirror_mode));
2N/A if (err != PICL_SUCCESS)
2N/A mirror_mode = 0;
2N/A log_printf("0x%-13llx", base);
2N/A print_memory_segment_size(size);
2N/A
2N/A if (!mirror_mode) {
2N/A log_printf("%-13lld", ifactor);
2N/A } else {
2N/A log_printf("%-2lld(Mirrored) ", ifactor);
2N/A }
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
2N/A &nodeh, sizeof (nodeh));
2N/A if (err == PICL_SUCCESS)
2N/A print_memory_segment_contain(nodeh);
2N/A log_printf("\n");
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A }
2N/A
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Asun4v_display_memory_conf(picl_nodehdl_t plafh)
2N/A{
2N/A const char *fmt = "%-14s %-8s %-12s %-8s %-s";
2N/A (void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
2N/A NULL, sun4v_memory_conf_callback);
2N/A if (class_node_found == 0)
2N/A return;
2N/A log_printf("\n");
2N/A log_printf("=======================");
2N/A log_printf(" Physical Memory Configuration ");
2N/A log_printf("========================");
2N/A log_printf("\n");
2N/A log_printf("Segment Table:\n");
2N/A log_printf(
2N/A "--------------------------------------------------------------\n");
2N/A log_printf(fmt, "Base", "Segment", "Interleave", "Bank", "Contains", 0);
2N/A log_printf("\n");
2N/A log_printf(fmt, "Address", "Size", "Factor", "Size", "Modules", 0);
2N/A log_printf("\n");
2N/A log_printf(
2N/A "--------------------------------------------------------------\n");
2N/A (void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
2N/A NULL, sun4v_memory_conf_callback);
2N/A}
2N/A
2N/Avoid
2N/Asun4v_display_cpu_devices(picl_nodehdl_t plafh)
2N/A{
2N/A const char *fmt = "%-6s %-9s %-22s %-6s";
2N/A
2N/A /*
2N/A * Display the table header for CPUs . Then display the CPU
2N/A * frequency, cache size, and processor revision of all cpus.
2N/A */
2N/A log_printf(dgettext(TEXT_DOMAIN,
2N/A "\n"
2N/A "================================"
2N/A " Virtual CPUs "
2N/A "================================"
2N/A "\n"
2N/A "\n"));
2N/A log_printf("\n");
2N/A log_printf(fmt, "CPU ID", "Frequency", "Implementation",
2N/A "Status", 0);
2N/A log_printf("\n");
2N/A log_printf(fmt, "------", "---------",
2N/A "----------------------", "-------", 0);
2N/A log_printf("\n");
2N/A
2N/A (void) picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
2N/A sun4v_display_cpus);
2N/A}
2N/A
2N/A/*
2N/A * Display the CPUs present on this board.
2N/A */
2N/A/*ARGSUSED*/
2N/Aint
2N/Asun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
2N/A{
2N/A int status;
2N/A picl_prophdl_t proph;
2N/A picl_prophdl_t tblh;
2N/A picl_prophdl_t rowproph;
2N/A picl_propinfo_t propinfo;
2N/A uint32_t *int_value;
2N/A int cpuid;
2N/A char *comp_value;
2N/A const char *no_prop_value = " ";
2N/A char freq_str[MAXSTRLEN];
2N/A char state[MAXSTRLEN];
2N/A
2N/A /*
2N/A * Get cpuid property and print it and the NAC name
2N/A */
2N/A status = picl_get_propinfo_by_name(cpuh, OBP_PROP_CPUID, &propinfo,
2N/A &proph);
2N/A if (status == PICL_SUCCESS) {
2N/A status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
2N/A if (status != PICL_SUCCESS) {
2N/A log_printf("%-7s", no_prop_value);
2N/A } else {
2N/A log_printf("%-7d", cpuid);
2N/A }
2N/A } else {
2N/A log_printf("%-7s", no_prop_value);
2N/A }
2N/A
2N/Aclock_freq:
2N/A status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
2N/A &proph);
2N/A if (status == PICL_SUCCESS) {
2N/A int_value = malloc(propinfo.size);
2N/A if (int_value == NULL) {
2N/A log_printf("%-10s", no_prop_value);
2N/A goto compatible;
2N/A }
2N/A status = picl_get_propval(proph, int_value, propinfo.size);
2N/A if (status != PICL_SUCCESS) {
2N/A log_printf("%-10s", no_prop_value);
2N/A } else {
2N/A /* Running frequency */
2N/A (void) snprintf(freq_str, sizeof (freq_str), "%u MHz",
2N/A CLK_FREQ_TO_MHZ(*int_value));
2N/A log_printf("%-10s", freq_str);
2N/A }
2N/A free(int_value);
2N/A } else
2N/A log_printf("%-10s", no_prop_value);
2N/A
2N/Acompatible:
2N/A status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
2N/A &proph);
2N/A if (status == PICL_SUCCESS) {
2N/A if (propinfo.type == PICL_PTYPE_CHARSTRING) {
2N/A /*
2N/A * Compatible Property only has 1 value
2N/A */
2N/A comp_value = malloc(propinfo.size);
2N/A if (comp_value == NULL) {
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A goto state;
2N/A }
2N/A status = picl_get_propval(proph, comp_value,
2N/A propinfo.size);
2N/A if (status != PICL_SUCCESS)
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A else
2N/A log_printf("%-23s", comp_value, 0);
2N/A free(comp_value);
2N/A } else if (propinfo.type == PICL_PTYPE_TABLE) {
2N/A /*
2N/A * Compatible Property has multiple values
2N/A */
2N/A status = picl_get_propval(proph, &tblh, propinfo.size);
2N/A if (status != PICL_SUCCESS) {
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A goto state;
2N/A }
2N/A status = picl_get_next_by_row(tblh, &rowproph);
2N/A if (status != PICL_SUCCESS) {
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A goto state;
2N/A }
2N/A
2N/A status = picl_get_propinfo(rowproph, &propinfo);
2N/A if (status != PICL_SUCCESS) {
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A goto state;
2N/A }
2N/A
2N/A comp_value = malloc(propinfo.size);
2N/A if (comp_value == NULL) {
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A goto state;
2N/A }
2N/A status = picl_get_propval(rowproph, comp_value,
2N/A propinfo.size);
2N/A if (status != PICL_SUCCESS)
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A else
2N/A log_printf("%-23s", comp_value, 0);
2N/A free(comp_value);
2N/A }
2N/A } else
2N/A log_printf("%-23s", no_prop_value, 0);
2N/A
2N/Astate:
2N/A status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE,
2N/A &propinfo, &proph);
2N/A if (status == PICL_SUCCESS) {
2N/A status = picl_get_propval(proph, state, sizeof (state));
2N/A if (status != PICL_SUCCESS) {
2N/A log_printf("%-9s", no_prop_value);
2N/A } else {
2N/A log_printf("%-9s", state);
2N/A }
2N/A } else
2N/A log_printf("%-9s", no_prop_value);
2N/A
2N/Adone:
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/Avoid
2N/Asun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
2N/A{
2N/A#ifdef lint
2N/A flag = flag;
2N/A root = root;
2N/A plafh = plafh;
2N/A#endif
2N/A /*
2N/A * This function is intentionally empty
2N/A */
2N/A}
2N/A
2N/Avoid
2N/Adisplay_boardnum(int num)
2N/A{
2N/A log_printf("%2d ", num, 0);
2N/A}
2N/A
2N/Astatic int
2N/Asun4v_disp_env_status()
2N/A{
2N/A int exit_code = 0;
2N/A
2N/A if (phyplatformh == 0)
2N/A return (0);
2N/A log_printf("\n");
2N/A log_printf("============================");
2N/A log_printf(" Environmental Status ");
2N/A log_printf("============================");
2N/A log_printf("\n");
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_fan_sensors();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_fan_indicators();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_temp_sensors();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_temp_indicators();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_current_sensors();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_current_indicators();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_voltage_sensors();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_voltage_indicators();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_env_print_LEDs();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A all_status_ok = 1;
2N/A sun4v_print_fru_status();
2N/A exit_code |= (!all_status_ok);
2N/A
2N/A class_node_found = 0;
2N/A sun4v_print_fw_rev();
2N/A
2N/A class_node_found = 0;
2N/A sun4v_print_openprom_rev();
2N/A
2N/A sun4v_print_chassis_serial_no();
2N/A
2N/A return (exit_code);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
2N/A{
2N/A char val[PICL_PROPNAMELEN_MAX];
2N/A picl_nodehdl_t parenth;
2N/A char *names[PARENT_NAMES];
2N/A char *base_units[PICL_PROPNAMELEN_MAX];
2N/A char *loc;
2N/A int i;
2N/A char *prop;
2N/A picl_errno_t err;
2N/A int32_t lo_warning, lo_shutdown, lo_poweroff;
2N/A int32_t hi_warning, hi_shutdown, hi_poweroff;
2N/A int32_t current_val;
2N/A int32_t exponent;
2N/A double display_val;
2N/A typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
2N/A SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
2N/A sensor_status_t sensor_status = SENSOR_OK;
2N/A
2N/A if (class_node_found == 0) {
2N/A class_node_found = 1;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A
2N/A prop = (char *)args;
2N/A if (!prop) {
2N/A sensor_status = SENSOR_UNKNOWN;
2N/A all_status_ok = 0;
2N/A } else {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_OPERATIONAL_STATUS, val,
2N/A sizeof (val));
2N/A if (err == PICL_SUCCESS) {
2N/A if (strcmp(val, "disabled") == 0) {
2N/A sensor_status = SENSOR_DISABLED;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (sensor_status != SENSOR_DISABLED &&
2N/A sensor_status != SENSOR_UNKNOWN) {
2N/A if (picl_get_propval_by_name(nodeh, prop, &current_val,
2N/A sizeof (current_val)) != PICL_SUCCESS) {
2N/A sensor_status = SENSOR_UNKNOWN;
2N/A } else {
2N/A if (picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_LOW_WARNING,
2N/A &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
2N/A lo_warning = INVALID_THRESHOLD;
2N/A if (picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_LOW_SHUTDOWN,
2N/A &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
2N/A lo_shutdown = INVALID_THRESHOLD;
2N/A if (picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_LOW_POWER_OFF,
2N/A &lo_poweroff, sizeof (lo_poweroff)) != PICL_SUCCESS)
2N/A lo_poweroff = INVALID_THRESHOLD;
2N/A if (picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_HIGH_WARNING,
2N/A &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
2N/A hi_warning = INVALID_THRESHOLD;
2N/A if (picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_HIGH_SHUTDOWN,
2N/A &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
2N/A hi_shutdown = INVALID_THRESHOLD;
2N/A if (picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_HIGH_POWER_OFF,
2N/A &hi_poweroff, sizeof (hi_poweroff)) != PICL_SUCCESS)
2N/A hi_poweroff = INVALID_THRESHOLD;
2N/A
2N/A if ((lo_poweroff != INVALID_THRESHOLD &&
2N/A current_val <= lo_poweroff) ||
2N/A (hi_poweroff != INVALID_THRESHOLD &&
2N/A current_val >= hi_poweroff)) {
2N/A sensor_status = SENSOR_FAILED;
2N/A } else if ((lo_shutdown != INVALID_THRESHOLD &&
2N/A current_val <= lo_shutdown) ||
2N/A (hi_shutdown != INVALID_THRESHOLD &&
2N/A current_val >= hi_shutdown)) {
2N/A sensor_status = SENSOR_FAILED;
2N/A } else if ((lo_warning != INVALID_THRESHOLD &&
2N/A current_val <= lo_warning) ||
2N/A (hi_warning != INVALID_THRESHOLD &&
2N/A current_val >= hi_warning)) {
2N/A sensor_status = SENSOR_WARN;
2N/A } else {
2N/A sensor_status = SENSOR_OK;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (syserrlog == 0) {
2N/A if (sensor_status != SENSOR_OK && all_status_ok == 1) {
2N/A all_status_ok = 0;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A if (sensor_status == SENSOR_OK) {
2N/A return (PICL_WALK_CONTINUE);
2N/A }
2N/A } else {
2N/A if (sensor_status != SENSOR_OK && all_status_ok == 1) {
2N/A all_status_ok = 0;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If we're here then prtdiag was invoked with "-v" or we have
2N/A * a sensor that is beyond a threshold, so give them a book to
2N/A * read instead of the Cliff Notes.
2N/A */
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
2N/A sizeof (parenth));
2N/A if (err != PICL_SUCCESS) {
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A }
2N/A
2N/A /* gather up the path name for the sensor */
2N/A if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
2N/A for (i = 0; i < PARENT_NAMES; i++) {
2N/A if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
2N/A NULL) {
2N/A while (--i > -1)
2N/A free(names[i]);
2N/A free(loc);
2N/A loc = NULL;
2N/A }
2N/A }
2N/A }
2N/A i = 0;
2N/A if (loc != 0) {
2N/A while (err == PICL_SUCCESS) {
2N/A if (parenth == phyplatformh)
2N/A break;
2N/A err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
2N/A names[i++], PICL_PROPNAMELEN_MAX);
2N/A if (err != PICL_SUCCESS) {
2N/A i--;
2N/A break;
2N/A }
2N/A if (i == PARENT_NAMES)
2N/A break;
2N/A err = picl_get_propval_by_name(parenth,
2N/A PICL_PROP_PARENT, &parenth, sizeof (parenth));
2N/A }
2N/A loc[0] = '\0';
2N/A if (--i > -1) {
2N/A (void) strlcat(loc, names[i],
2N/A PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A }
2N/A while (--i > -1) {
2N/A (void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
2N/A PARENT_NAMES);
2N/A (void) strlcat(loc, names[i],
2N/A PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A }
2N/A log_printf("%-35s", loc);
2N/A for (i = 0; i < PARENT_NAMES; i++)
2N/A free(names[i]);
2N/A free(loc);
2N/A } else {
2N/A log_printf("%-35s", " ");
2N/A }
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
2N/A sizeof (val));
2N/A if (err == PICL_SUCCESS)
2N/A log_printf("%-19s", val);
2N/A
2N/A /*
2N/A * Get the exponent if present, and do a little math so that
2N/A * if we need to we can print a normalized value for the
2N/A * sensor reading.
2N/A */
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT,
2N/A &exponent, sizeof (exponent)) != PICL_SUCCESS)
2N/A exponent = 0;
2N/A if (exponent == 0)
2N/A display_val = (double)current_val;
2N/A else {
2N/A display_val = (double)current_val *
2N/A pow((double)10, (double)exponent);
2N/A
2N/A /*
2N/A * Sometimes ILOM will scale a sensor reading but
2N/A * there will be nothing to the right of the decimal
2N/A * once that value is normalized. Setting the
2N/A * exponent to zero will prevent the printf below
2N/A * from printing extraneous zeros. Otherwise a
2N/A * negative exponent is used to set the precision
2N/A * for the printf.
2N/A */
2N/A if ((int)display_val == display_val || exponent > 0)
2N/A exponent = 0;
2N/A }
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS,
2N/A base_units, sizeof (base_units));
2N/A if (err != PICL_SUCCESS)
2N/A base_units[0] = '\0';
2N/A
2N/A switch (sensor_status) {
2N/A case SENSOR_FAILED:
2N/A log_printf("%-s", "failed (");
2N/A log_printf("%-.*f", abs(exponent), display_val);
2N/A log_printf("%-s %s", base_units, ")");
2N/A break;
2N/A case SENSOR_WARN:
2N/A log_printf("%-s", "warning (");
2N/A log_printf("%-.*f", abs(exponent), display_val);
2N/A log_printf("%-s %s", base_units, ")");
2N/A break;
2N/A case SENSOR_DISABLED:
2N/A log_printf("%-s", "disabled");
2N/A break;
2N/A case SENSOR_OK:
2N/A log_printf("%-s", "ok");
2N/A break;
2N/A default:
2N/A log_printf("%-s", "unknown");
2N/A break;
2N/A }
2N/A
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
2N/A{
2N/A char current_val[PICL_PROPNAMELEN_MAX];
2N/A char expected_val[PICL_PROPNAMELEN_MAX];
2N/A char label[PICL_PROPNAMELEN_MAX];
2N/A picl_nodehdl_t parenth;
2N/A char *names[PARENT_NAMES];
2N/A char *loc;
2N/A int i = 0;
2N/A char *prop = (char *)args;
2N/A picl_errno_t err = PICL_SUCCESS;
2N/A typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
2N/A SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
2N/A sensor_status_t sensor_status = SENSOR_OK;
2N/A
2N/A if (class_node_found == 0) {
2N/A class_node_found = 1;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A
2N/A prop = (char *)args;
2N/A if (!prop) {
2N/A sensor_status = SENSOR_UNKNOWN;
2N/A all_status_ok = 0;
2N/A } else {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_OPERATIONAL_STATUS, current_val,
2N/A sizeof (current_val));
2N/A if (err == PICL_SUCCESS) {
2N/A if (strcmp(current_val, "disabled") == 0) {
2N/A sensor_status = SENSOR_DISABLED;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (sensor_status != SENSOR_DISABLED &&
2N/A sensor_status != SENSOR_UNKNOWN) {
2N/A if (picl_get_propval_by_name(nodeh, prop, &current_val,
2N/A sizeof (current_val)) != PICL_SUCCESS) {
2N/A (void) strlcpy(current_val, "unknown",
2N/A sizeof (current_val));
2N/A sensor_status = SENSOR_UNKNOWN;
2N/A } else {
2N/A if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED,
2N/A &expected_val, sizeof (expected_val)) ==
2N/A PICL_SUCCESS) {
2N/A if (strncmp(current_val, expected_val,
2N/A sizeof (current_val)) == 0) {
2N/A sensor_status = SENSOR_OK;
2N/A } else {
2N/A sensor_status = SENSOR_FAILED;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (syserrlog == 0) {
2N/A if (sensor_status != SENSOR_OK && all_status_ok == 1) {
2N/A all_status_ok = 0;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A if (sensor_status == SENSOR_OK) {
2N/A return (PICL_WALK_CONTINUE);
2N/A }
2N/A } else {
2N/A if (sensor_status != SENSOR_OK && all_status_ok == 1) {
2N/A all_status_ok = 0;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If we're here then prtdiag was invoked with "-v" or we have
2N/A * a sensor that is beyond a threshold, so give them a book to
2N/A * read instead of the Cliff Notes.
2N/A */
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
2N/A sizeof (parenth));
2N/A if (err != PICL_SUCCESS) {
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A }
2N/A if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
2N/A for (i = 0; i < PARENT_NAMES; i++) {
2N/A if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
2N/A NULL) {
2N/A while (--i > -1)
2N/A free(names[i]);
2N/A free(loc);
2N/A loc = NULL;
2N/A }
2N/A }
2N/A }
2N/A i = 0;
2N/A if (loc) {
2N/A while (err == PICL_SUCCESS) {
2N/A if (parenth == phyplatformh)
2N/A break;
2N/A err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
2N/A names[i++], PICL_PROPNAMELEN_MAX);
2N/A if (err != PICL_SUCCESS) {
2N/A i--;
2N/A break;
2N/A }
2N/A if (i == PARENT_NAMES)
2N/A break;
2N/A err = picl_get_propval_by_name(parenth,
2N/A PICL_PROP_PARENT, &parenth, sizeof (parenth));
2N/A }
2N/A loc[0] = '\0';
2N/A if (--i > -1) {
2N/A (void) strlcat(loc, names[i],
2N/A PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A }
2N/A while (--i > -1) {
2N/A (void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
2N/A PARENT_NAMES);
2N/A (void) strlcat(loc, names[i],
2N/A PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A }
2N/A log_printf("%-35s", loc);
2N/A for (i = 0; i < PARENT_NAMES; i++)
2N/A free(names[i]);
2N/A free(loc);
2N/A } else {
2N/A log_printf("%-35s", "");
2N/A }
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
2N/A sizeof (label));
2N/A if (err != PICL_SUCCESS)
2N/A (void) strlcpy(label, "", sizeof (label));
2N/A log_printf("%-19s", label);
2N/A
2N/A log_printf("%-8s", current_val);
2N/A
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_fan_sensors()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-10s\n";
2N/A /*
2N/A * If there isn't any fan sensor node, return now.
2N/A */
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED,
2N/A sun4v_env_print_sensor_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("Fan sensors:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_RPM_SENSOR,
2N/A PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All fan sensors are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Sensor", "Status", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
2N/A PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_fan_indicators()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-10s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nFan indicators:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_RPM_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All fan indicators are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Sensor", "Condition", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_temp_sensors()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-10s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_TEMPERATURE_SENSOR,
2N/A (void *)PICL_PROP_TEMPERATURE,
2N/A sun4v_env_print_sensor_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A
2N/A log_printf("\nTemperature sensors:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_TEMPERATURE_SENSOR,
2N/A PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All temperature sensors are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Sensor", "Status", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_TEMPERATURE_SENSOR,
2N/A (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_temp_indicators()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-8s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nTemperature indicators:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_TEMPERATURE_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All temperature indicators are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Indicator", "Condition", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_TEMPERATURE_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_current_sensors()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-10s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
2N/A (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nCurrent sensors:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_CURRENT_SENSOR,
2N/A PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All current sensors are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Sensor", "Status", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
2N/A sun4v_env_print_sensor_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_current_indicators()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-8s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_CURRENT_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nCurrent indicators:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All current indicators are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Indicator", "Condition", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_CURRENT_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_voltage_sensors()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-10s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_VOLTAGE_SENSOR,
2N/A PICL_PROP_VOLTAGE,
2N/A sun4v_env_print_sensor_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nVoltage sensors:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_VOLTAGE_SENSOR,
2N/A PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All voltage sensors are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Sensor", "Status", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_VOLTAGE_SENSOR,
2N/A (void *)PICL_PROP_VOLTAGE,
2N/A sun4v_env_print_sensor_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_voltage_indicators()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-8s\n";
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_VOLTAGE_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nVoltage indicators:\n");
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All voltage indicators are OK.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "Indicator", "Condition", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A PICL_CLASS_VOLTAGE_INDICATOR,
2N/A (void *)PICL_PROP_CONDITION,
2N/A sun4v_env_print_indicator_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_env_print_LEDs()
2N/A{
2N/A const char *fmt = "%-34s %-18s %-8s\n";
2N/A if (syserrlog == 0)
2N/A return;
2N/A (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
2N/A (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A log_printf("\nLEDs:\n");
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A log_printf(fmt, "Location", "LED", "State", 0);
2N/A log_printf("-------------------------------------------------"
2N/A "---------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
2N/A (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
2N/A{
2N/A char label[PICL_PROPNAMELEN_MAX];
2N/A char status[PICL_PROPNAMELEN_MAX];
2N/A picl_errno_t err;
2N/A picl_prophdl_t proph;
2N/A picl_nodehdl_t parenth;
2N/A char *names[PARENT_NAMES];
2N/A char *loc;
2N/A int i;
2N/A
2N/A if (!class_node_found) {
2N/A class_node_found = 1;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
2N/A if (err != PICL_SUCCESS)
2N/A return (PICL_WALK_CONTINUE);
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
2N/A sizeof (label));
2N/A if (err != PICL_SUCCESS)
2N/A return (PICL_WALK_CONTINUE);
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
2N/A status, sizeof (status));
2N/A if (err != PICL_SUCCESS)
2N/A return (PICL_WALK_CONTINUE);
2N/A if (syserrlog == 0) {
2N/A if (strcmp(status, "disabled") == 0) {
2N/A if (all_status_ok) {
2N/A all_status_ok = 0;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A } else
2N/A return (PICL_WALK_CONTINUE);
2N/A } else {
2N/A if (all_status_ok && (strcmp(status, "disabled") == 0)) {
2N/A all_status_ok = 0;
2N/A }
2N/A }
2N/A
2N/A if (is_fru_absent(nodeh))
2N/A strcpy(status, "Not present");
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
2N/A sizeof (parenth));
2N/A if (err != PICL_SUCCESS) {
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A }
2N/A if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
2N/A return (PICL_WALK_TERMINATE);
2N/A for (i = 0; i < PARENT_NAMES; i++)
2N/A if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
2N/A while (--i > -1)
2N/A free(names[i]);
2N/A free(loc);
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A i = 0;
2N/A while (err == PICL_SUCCESS) {
2N/A if (parenth == phyplatformh)
2N/A break;
2N/A err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
2N/A names[i++], PICL_PROPNAMELEN_MAX);
2N/A if (err != PICL_SUCCESS) {
2N/A i--;
2N/A break;
2N/A }
2N/A if (i == PARENT_NAMES)
2N/A break;
2N/A err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
2N/A &parenth, sizeof (parenth));
2N/A }
2N/A loc[0] = '\0';
2N/A if (--i > -1) {
2N/A (void) strlcat(loc, names[i],
2N/A PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A }
2N/A while (--i > -1) {
2N/A (void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A (void) strlcat(loc, names[i],
2N/A PICL_PROPNAMELEN_MAX * PARENT_NAMES);
2N/A }
2N/A log_printf("%-35s", loc);
2N/A for (i = 0; i < PARENT_NAMES; i++)
2N/A free(names[i]);
2N/A free(loc);
2N/A log_printf("%-10s", label);
2N/A log_printf("%-9s", status);
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_print_fru_status()
2N/A{
2N/A const char *fmt = "%-34s %-9s %-8s\n";
2N/A
2N/A (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
2N/A sun4v_print_fru_status_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A
2N/A log_printf("\n");
2N/A log_printf("============================");
2N/A log_printf(" FRU Status ");
2N/A log_printf("============================");
2N/A log_printf("\n");
2N/A
2N/A if (syserrlog == 0) {
2N/A (void) picl_walk_tree_by_class(phyplatformh,
2N/A NULL, NULL,
2N/A sun4v_print_fru_status_callback);
2N/A if (all_status_ok) {
2N/A log_printf("All FRUs are enabled.\n");
2N/A return;
2N/A }
2N/A }
2N/A log_printf(fmt, "Location", "Name", "Status", 0);
2N/A log_printf("------------------------------------------------------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
2N/A sun4v_print_fru_status_callback);
2N/A}
2N/A
2N/A/* Check the children of the FRU node for a presence indicator */
2N/Astatic int
2N/Ais_fru_absent(picl_nodehdl_t fruh)
2N/A{
2N/A char class [PICL_CLASSNAMELEN_MAX];
2N/A char condition [PICL_PROPNAMELEN_MAX];
2N/A picl_errno_t err;
2N/A picl_nodehdl_t nodeh;
2N/A
2N/A err = picl_get_propval_by_name(fruh, PICL_PROP_CHILD, &nodeh,
2N/A sizeof (picl_nodehdl_t));
2N/A while (err == PICL_SUCCESS) {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_CLASSNAME, class, sizeof (class));
2N/A if (err == PICL_SUCCESS &&
2N/A strcmp(class, "presence-indicator") == 0) {
2N/A err = picl_get_propval_by_name(nodeh,
2N/A PICL_PROP_CONDITION, condition,
2N/A sizeof (condition));
2N/A if (err == PICL_SUCCESS) {
2N/A if (strcmp(condition, "Absent") == 0) {
2N/A return (1);
2N/A } else {
2N/A return (0);
2N/A }
2N/A }
2N/A }
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
2N/A &nodeh, sizeof (picl_nodehdl_t));
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Asun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
2N/A{
2N/A char rev[PICL_PROPNAMELEN_MAX];
2N/A picl_errno_t err;
2N/A
2N/A if (!class_node_found) {
2N/A class_node_found = 1;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A
2N/A err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
2N/A sizeof (rev));
2N/A if (err != PICL_SUCCESS)
2N/A return (PICL_WALK_CONTINUE);
2N/A if (strlen(rev) == 0)
2N/A return (PICL_WALK_CONTINUE);
2N/A log_printf("%s", rev);
2N/A log_printf("\n");
2N/A return (PICL_WALK_CONTINUE);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_print_fw_rev()
2N/A{
2N/A if (syserrlog == 0)
2N/A return;
2N/A
2N/A (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
2N/A sun4v_print_fw_rev_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A
2N/A log_printf("\n");
2N/A log_printf("============================");
2N/A log_printf(" FW Version ");
2N/A log_printf("============================");
2N/A log_printf("\n");
2N/A log_printf("Version\n");
2N/A log_printf("-------------------------------------------------"
2N/A "-----------\n");
2N/A (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
2N/A sun4v_print_fw_rev_callback);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_print_openprom_rev()
2N/A{
2N/A if (syserrlog == 0)
2N/A return;
2N/A
2N/A (void) picl_walk_tree_by_class(rooth, "openprom", NULL,
2N/A openprom_callback);
2N/A if (!class_node_found)
2N/A return;
2N/A
2N/A log_printf("\n");
2N/A log_printf("======================");
2N/A log_printf(" System PROM revisions ");
2N/A log_printf("=======================");
2N/A log_printf("\n");
2N/A log_printf("Version\n");
2N/A log_printf("-------------------------------------------------"
2N/A "-----------\n");
2N/A (void) picl_walk_tree_by_class(rooth, "openprom", NULL,
2N/A openprom_callback);
2N/A}
2N/A
2N/A/*
2N/A * display the OBP and POST prom revisions (if present)
2N/A */
2N/A/* ARGSUSED */
2N/Astatic int
2N/Aopenprom_callback(picl_nodehdl_t openpromh, void *arg)
2N/A{
2N/A picl_prophdl_t proph;
2N/A picl_prophdl_t tblh;
2N/A picl_prophdl_t rowproph;
2N/A picl_propinfo_t pinfo;
2N/A char *prom_version = NULL;
2N/A char *obp_version = NULL;
2N/A int err;
2N/A
2N/A if (!class_node_found) {
2N/A class_node_found = 1;
2N/A return (PICL_WALK_TERMINATE);
2N/A }
2N/A
2N/A err = picl_get_propinfo_by_name(openpromh, OBP_PROP_VERSION,
2N/A &pinfo, &proph);
2N/A if (err == PICL_PROPNOTFOUND)
2N/A return (PICL_WALK_TERMINATE);
2N/A else if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A /*
2N/A * If it's a table prop, the first element is OBP revision
2N/A * The second one is POST revision.
2N/A * If it's a charstring prop, the value will be only OBP revision
2N/A */
2N/A if (pinfo.type == PICL_PTYPE_CHARSTRING) {
2N/A prom_version = (char *)alloca(pinfo.size);
2N/A if (prom_version == NULL)
2N/A return (PICL_FAILURE);
2N/A err = picl_get_propval(proph, prom_version, pinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A log_printf("%s\n", prom_version);
2N/A }
2N/A
2N/A if (pinfo.type != PICL_PTYPE_TABLE) /* not supported type */
2N/A return (PICL_WALK_TERMINATE);
2N/A
2N/A err = picl_get_propval(proph, &tblh, pinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A err = picl_get_next_by_row(tblh, &rowproph);
2N/A if (err == PICL_SUCCESS) {
2N/A /* get first row */
2N/A err = picl_get_propinfo(rowproph, &pinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A prom_version = (char *)alloca(pinfo.size);
2N/A if (prom_version == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A err = picl_get_propval(rowproph, prom_version, pinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A log_printf("%s\n", prom_version);
2N/A
2N/A /* get second row */
2N/A err = picl_get_next_by_col(rowproph, &rowproph);
2N/A if (err == PICL_SUCCESS) {
2N/A err = picl_get_propinfo(rowproph, &pinfo);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A
2N/A obp_version = (char *)alloca(pinfo.size);
2N/A if (obp_version == NULL)
2N/A return (PICL_FAILURE);
2N/A err = picl_get_propval(rowproph, obp_version,
2N/A pinfo.size);
2N/A if (err != PICL_SUCCESS)
2N/A return (err);
2N/A log_printf("%s\n", obp_version);
2N/A }
2N/A }
2N/A
2N/A return (PICL_WALK_TERMINATE);
2N/A}
2N/A
2N/Astatic void
2N/Asun4v_print_chassis_serial_no()
2N/A{
2N/A char val[PICL_PROPNAMELEN_MAX];
2N/A picl_errno_t err;
2N/A if (syserrlog == 0 || chassish == 0)
2N/A return;
2N/A
2N/A log_printf("\n");
2N/A log_printf("Chassis Serial Number");
2N/A log_printf("\n");
2N/A log_printf("---------------------\n");
2N/A err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
2N/A val, sizeof (val));
2N/A if (err == PICL_SUCCESS)
2N/A log_printf("%s", val);
2N/A log_printf("\n");
2N/A}
2N/A
2N/Astatic int
2N/Aopen_root_complex(char *root_complex)
2N/A{
2N/A char *path;
2N/A static char device_str[] = {"/devices"};
2N/A static char devctl_str[] = {":reg"};
2N/A int path_size, fd;
2N/A
2N/A path_size = strlen(root_complex) + sizeof (device_str)
2N/A + sizeof (devctl_str);
2N/A path = (char *)malloc(path_size);
2N/A if (path == NULL)
2N/A return (-1);
2N/A if (snprintf(path, path_size, "%s%s%s", device_str, root_complex,
2N/A devctl_str) <= 0) {
2N/A free(path);
2N/A return (-1);
2N/A }
2N/A fd = open(path, O_RDWR);
2N/A free(path);
2N/A return (fd);
2N/A}
2N/A
2N/Astatic uint32_t
2N/Aread_long(int fd, int bus, int dev, int func, int offset, int *ret)
2N/A{
2N/A int rval;
2N/A pcitool_reg_t prg;
2N/A
2N/A prg.user_version = PCITOOL_VERSION;
2N/A prg.barnum = 0;
2N/A prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
2N/A PCITOOL_ACC_ATTR_ENDN_LTL;
2N/A prg.bus_no = bus;
2N/A prg.dev_no = dev;
2N/A prg.func_no = func;
2N/A prg.offset = offset;
2N/A rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
2N/A if (rval != 0) {
2N/A log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
2N/A log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
2N/A }
2N/A *ret = rval;
2N/A return ((uint32_t)prg.data);
2N/A}
2N/A
2N/Astatic uint16_t
2N/Aread_word(int fd, int bus, int dev, int func, int offset, int *ret)
2N/A{
2N/A int rval;
2N/A pcitool_reg_t prg;
2N/A
2N/A prg.user_version = PCITOOL_VERSION;
2N/A prg.barnum = 0;
2N/A prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
2N/A PCITOOL_ACC_ATTR_ENDN_LTL;
2N/A prg.bus_no = bus;
2N/A prg.dev_no = dev;
2N/A prg.func_no = func;
2N/A prg.offset = offset;
2N/A rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
2N/A if (rval != 0) {
2N/A log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
2N/A log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
2N/A }
2N/A *ret = rval;
2N/A return ((uint16_t)prg.data);
2N/A}
2N/A
2N/Astatic uint8_t
2N/Aread_byte(int fd, int bus, int dev, int func, int offset, int *ret)
2N/A{
2N/A int rval;
2N/A pcitool_reg_t prg;
2N/A
2N/A prg.user_version = PCITOOL_VERSION;
2N/A prg.barnum = 0;
2N/A prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
2N/A PCITOOL_ACC_ATTR_ENDN_LTL;
2N/A prg.bus_no = bus;
2N/A prg.dev_no = dev;
2N/A prg.func_no = func;
2N/A prg.offset = offset;
2N/A rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
2N/A if (rval != 0) {
2N/A log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
2N/A log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
2N/A }
2N/A *ret = rval;
2N/A return ((uint8_t)prg.data);
2N/A}
2N/A
2N/A
2N/Astatic picl_errno_t
2N/Aget_lane_width
2N/A (char *device_path, int bus, int dev, int func, int *cur_link_width,
2N/A int *cur_speed, uint32_t *speed_max, uint32_t *speed_at, int *type)
2N/A{
2N/A uint_t cap_ptr, cap_reg, link_status, capid;
2N/A int fd, ret;
2N/A
2N/A if (device_path == NULL)
2N/A return (PICL_FAILURE);
2N/A
2N/A fd = open_root_complex(device_path);
2N/A if (fd == -1) {
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A /*
2N/A * Link Capabilities and Link Status registers are in the
2N/A * PCI-E capabilities register. They are at offset
2N/A * 0xc and 0x12 respectively. They are documented in section
2N/A * 7.8 of the PCI Express Base Specification. The address of
2N/A * that structure is not fixed, it's kind of a linked list.
2N/A * The Capabilities Pointer reg (8 bits) is always at 0x34.
2N/A * It contains a pointer to the first capabilities structure.
2N/A * For each capability structure, the first 8 bits is the capability
2N/A * ID. The next 8 bits is the pointer to the next structure.
2N/A * If the Next Cap register is zero, it's the end of the list.
2N/A * The capability ID for the PCI-E strucutre is 0x10. The idea
2N/A * is to follow the links until you find a Cap ID of 0x10, then
2N/A * read the registers at 0xc and 0x12 from there.
2N/A * If there's no Cap ID 0x10, then it's not a PCI-E device.
2N/A */
2N/A
2N/A cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A *type = PCI_BUSTYPE;
2N/A capid = cap_reg & PCI_CAP_MASK;
2N/A while (cap_ptr != 0) {
2N/A if (capid == PCI_CAP_ID_PCI_E) {
2N/A link_status = read_word(fd, bus, dev, func,
2N/A cap_ptr + PCIE_LINKSTS, &ret);
2N/A if (ret != 0) {
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A *cur_link_width = ((link_status >> PCI_LINK_SHIFT) &
2N/A PCI_LINK_MASK);
2N/A *cur_speed = ((link_status) &
2N/A PCI_SPEED_MASK);
2N/A
2N/A /* PCIE 3 Speed decoding */
2N/A if (*cur_speed == 1)
2N/A *cur_speed = PCIE_SPEED_2_5GT;
2N/A else if (*cur_speed == 2)
2N/A *cur_speed = PCIE_SPEED_5_0GT;
2N/A else
2N/A *cur_speed = PCIE_SPEED_8_0GT;
2N/A *type = PCIE_BUSTYPE;
2N/A } else if (capid == PCI_CAP_ID_PCIX) {
2N/A uint32_t pcix_status;
2N/A uint8_t hdr_type;
2N/A int max_speed = PCI_FREQ_66;
2N/A
2N/A hdr_type = read_byte
2N/A (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A *type = PCIX_BUSTYPE;
2N/A if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
2N/A /* This is a PCI-X bridge */
2N/A uint16_t sec_status, mode;
2N/A sec_status = read_word(fd, bus, dev, func,
2N/A cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A if (sec_status & PCI_SEC_133)
2N/A max_speed = PCI_FREQ_133;
2N/A if (sec_status & PCI_SEC_266)
2N/A max_speed = PCI_FREQ_266;
2N/A if (sec_status & PCI_SEC_533)
2N/A max_speed = PCI_FREQ_533;
2N/A *speed_max = max_speed;
2N/A mode = (sec_status >> PCI_CLASS_BRIDGE) &
2N/A PCI_BRIDGE_MC;
2N/A if (mode) {
2N/A int speed;
2N/A if (mode == PCI_MODE_66)
2N/A speed = PCI_FREQ_66;
2N/A else if (mode == PCI_MODE_100)
2N/A speed = PCI_FREQ_100;
2N/A else if (mode == PCI_MODE_133)
2N/A speed = PCI_FREQ_133;
2N/A *speed_at = speed;
2N/A }
2N/A
2N/A } else { /* Leaf device */
2N/A pcix_status = read_long(fd, bus, dev, func,
2N/A cap_ptr + PCI_PCIX_STATUS, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A if (pcix_status &
2N/A (PCI_LEAF_ULONG << PCI_SHIFT_133))
2N/A max_speed = PCI_FREQ_133;
2N/A if (pcix_status &
2N/A (PCI_LEAF_ULONG << PCI_SHIFT_266))
2N/A max_speed = PCI_FREQ_266;
2N/A if (pcix_status &
2N/A (PCI_LEAF_ULONG << PCI_SHIFT_533))
2N/A max_speed = PCI_FREQ_533;
2N/A *speed_max = max_speed;
2N/A }
2N/A }
2N/A cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
2N/A cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
2N/A if (ret != 0) {
2N/A /* ioctl failure */
2N/A (void) close(fd);
2N/A return (PICL_FAILURE);
2N/A }
2N/A capid = cap_reg & PCI_CAP_MASK;
2N/A }
2N/A
2N/A if (close(fd) == -1) {
2N/A return (PICL_FAILURE);
2N/A }
2N/A
2N/A return (PICL_SUCCESS);
2N/A}