/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Starcat Platform specific functions.
*
* called when :
* machine_type == MTYPE_STARCAT
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <kvm.h>
#include <varargs.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/openpromio.h>
#include <libintl.h>
#include <syslog.h>
#include <pdevinfo.h>
#include <display.h>
#include <pdevinfo_sun4u.h>
#include <display_sun4u.h>
#include <libprtdiag.h>
#ifndef TEXT_DOMAIN
#endif /* TEXT_DOMAIN */
/*
* these functions will overlay the symbol table of libprtdiag
* at runtime (Starcat systems only)
*/
void display_pci(Board_node *);
void display_ffb(Board_node *, int);
struct system_kstat_data *kstats);
/* Local Functions */
static void display_io_max_bus_speed(struct io_card *p);
static void display_io_slot_info(struct io_card *p);
/* The bus max freq is determined based on board level in use */
/*
* display_pci
* Display all the PCI IO cards on this board.
*/
void
{
void *value;
int slot_name_bits;
int slot_name_offset = 0;
char *child_name;
int *int_val;
int pci_bus;
int pci_bridge = 0;
int pci_bridge_dev_no;
int child_dev_no;
int i;
int portid;
return;
/* Initialize all the common information */
/*
* each schizo node found. Since the model property "SUNW,schizo"
* is not supported on Starcat, we must match on the compatible
* property "pci108e,8001".
*/
/* set max freq for this board */
/*
* Find out if this is a PCI or cPCI IO Board.
* If "enum-impl" property exists in pci node => cPCI.
*/
} else {
}
if (strstr((char *)get_prop_val(
/*
* With XMITS 3.X and PCI-X mode, the bus speed
* can be higher than 66MHZ.
*/
value = (int *)get_prop_val
if (value) {
if (version >= 4)
}
} else if (strstr((char *)get_prop_val(
else
/*
* Get slot-names property from parent node and
* store the individual slot names in an array.
* This is more general than Starcat requires, but
* it is correct, according to the slot-names property.
*/
/*
* No slot_names property. This could be an Xmits
* card, so check the child node for slot-names property
*/
value = (char *)get_prop_val(
}
/* Get the 4 byte bitmask and pointer to first name */
slot_name_bits = *(int *)value;
if (slot_name_bits > 0)
for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) {
if (! (slot_name_bits & (1 << i))) {
slot_name_arr[i] = (char *)NULL;
continue;
}
/*
* Save the name pointer into the array
* and advance it past the end of this
* slot name
*/
slot_name_arr[i] = slot_name;
}
}
/*
* Search for Children of this node ie. Cards.
* Note: any of these cards can be a pci-bridge
* that itself has children. If we find a
* pci-bridge we need to handle it specially.
*/
pci_bridge = 0;
/* If it doesn't have a name, skip it */
name = (char *)get_prop_val(
continue;
}
/*
* get dev# and func# for this card from the
* 'reg' property.
*/
int_val = (int *)get_prop_val(
} else {
}
/*
* If this is a pci-bridge, then store it's dev#
* as its children nodes need this to get their slot#.
* We set the pci_bridge flag so that we know we are
* looking at a pci-bridge node. This flag gets reset
* every time we enter this while loop.
*/
/*
* Check for a PCI-PCI Bridge for PCI and cPCI
* IO Boards using the name and type properties.
*/
type = (char *)get_prop_val(
pci_bridge = TRUE;
}
/*
* Get slot-names property from slot_names_arr.
* If we are the child of a pci_bridge we use the
* dev# of the pci_bridge as an index to get
* the slot number. We know that we are a child of
* a pci-bridge if our parent is the same as the last
* pci_bridge node found above.
*/
/*
* We compare this card's parent node with the
* pci_bridge_node to see if it's a child.
*/
/* use dev_no of pci_bridge */
} else {
/* use card's own dev_no */
}
if (child_dev_no < MAX_SLOTS_PER_IO_BD &&
child_dev_no >= 0 &&
} else
} else {
}
} else {
}
/*
* Get the portid of the schizo that this card
* lives under.
*/
portid = -1;
}
#ifdef DEBUG
" dev_no [%d] slot_name[%s] name_bits[%#x]",
#endif /* DEBUG */
/*
* Find out whether this is PCI bus A or B
* using the 'reg' property.
*/
int_val = (int *)get_prop_val
int_val ++; /* skip over first integer */
if (pci_bus == 0x600000)
else if (pci_bus == 0x700000)
else
} else {
}
/*
* Check for failed status.
*/
if (node_failed(card_node))
else
/* Get the model of this card */
else {
/*
* If we wish to exclude onboard devices
* (such as SBBC) then this is the place
* and here is how to do it:
*
* if (strcmp(card.model, "SUNW,sbbc") == 0) {
* card_node = card_node->sibling;
* continue;
* }
*/
}
/*
* The card may have a "clock-frequency" but we
* are not interested in that. Instead we get the
* "clock-frequency" of the PCI Bus that the card
* resides on. PCI-A can operate at 33Mhz or 66Mhz
* depending on what card is plugged into the Bus.
* PCI-B always operates at 33Mhz.
*
*/
"clock-frequency"));
} else {
}
/*
* Figure out how we want to display the name
*/
"compatible"));
/* use 'name'-'compatible' */
(char *)value);
} else {
/* just use 'name' */
}
/*
* If this node has children, add the device_type
* of the child to the name value of this card.
*/
(child_name != NULL)) {
"device_type"));
/* add device_type of child to name */
(char *)value);
} else {
/* just add child's name */
name, child_name);
}
} else {
/* childless, just the card's name */
}
/*
* If this is a pci-bridge, then add the word
* 'pci-bridge' to its model.
*/
if (pci_bridge) {
"%s", "pci-bridge");
else
"/pci-bridge");
}
/* insert this card in the list to be displayed later */
/*
* If we are dealing with a pci-bridge, we need to move
* down to the children of this bridge, if there are
* any, otherwise its siblings.
*
* If not a bridge, we are either dealing with a regular
* card (in which case we move onto the sibling of this
* card) or we are dealing with a child of a pci-bridge
* (in which case we move onto the child's siblings or
* if there are no more siblings for this child, we
* move onto the parent's siblings). I hope you're
* getting all this, there will be an exam later.
*/
if (pci_bridge) {
else
} else {
/*
* If our parent is a pci-bridge but there
* are no more of its children to process we
* move back up to our parent's sibling,
* otherwise we move onto our own sibling.
*/
else
}
} /* end while (card_node ...) loop */
} /* end for (pci ...) loop */
}
/*
* display_ffb
*
* There are no FFB's on a Starcat, however in the generic library,
* the display_ffb() function is implemented so we have to define an
* empty function here.
*/
/*ARGSUSED0*/
void
{
}
/*
* add_node
*
* This function adds a board node to the board structure where that
* that node's physical component lives.
*/
void
{
void *value;
Prom_node *p;
char *type;
/* Get the board number of this board from the portid prop */
"portid"));
}
}
/* find the board node with the same board number */
}
/* now attach this prom node to the board list */
/* Insert this node at the end of the list */
else {
p = p->sibling;
}
}
/*
* Print out all the io cards in the list. Also print the column
* headers if told to do so.
*/
void
{
" %-4.4s %-5.5s %-32.32s %-22.22s"
#ifdef DEBUG
" %-22.22s"
#endif /* DEBUG */
"\n";
struct io_card *p;
return;
(void) textdomain(TEXT_DOMAIN);
"", "", "", "",
gettext("Bus"),
gettext("Max"),
"", "", "", "",
#ifdef DEBUG
"",
#endif /* DEBUG */
0);
"",
gettext("IO"),
gettext("Port"),
gettext("Bus"),
gettext("Freq"),
gettext("Bus"),
gettext("Dev,"),
"", "", "",
#ifdef DEBUG
"",
#endif /* DEBUG */
0);
gettext("Slot ID"),
gettext("Type"),
gettext(" ID"),
gettext("Side"),
gettext("MHz"),
gettext("Freq"),
gettext("Func"),
gettext("State"),
gettext("Name"),
gettext("Model"),
#ifdef DEBUG
gettext("Notes"),
#endif /* DEBUG */
0);
"----------", "----", "----", "----", "----", "----",
"----", "-----", "--------------------------------",
"----------------------",
#ifdef DEBUG
"----------------------",
#endif /* DEBUG */
0);
}
log_printf("\n", 0);
}
}
static void
{
/*
* Onboard devices are distinguished by Slot IDs that
* indicate only the I/O board. Plug-in cards indicate
* their leaf and Schizo.
*/
if (p->slot_str[0] == '-') {
log_printf("/%-2s%02d ",
SC_BOARD_TYPE(p->board),
PORTID_TO_EXPANDER(p->board), 0);
} else {
char c;
log_printf("/%-2s%02d/%s ",
SC_BOARD_TYPE(p->board),
PORTID_TO_EXPANDER(p->board),
p->slot_str, 0);
} else {
if (p->pci_bus == 'A')
c = '3';
else if (p->pci_bus == 'B') {
c = '5';
} else
c = '-';
log_printf("/%-2s%02d/C%cV%1d ",
SC_BOARD_TYPE(p->board),
PORTID_TO_EXPANDER(p->board), c,
0);
}
}
}
static void
{
switch (p->pci_bus) {
case 'A':
break;
case 'B':
if (PORTID_TO_INSTANCE(p->schizo_portid) == 0)
BUS_SPEED_PRINT(33);
else
} else
BUS_SPEED_PRINT(33);
break;
default:
log_printf(" - ", 0);
break;
}
#ifdef DEBUG
#endif /* DEBUG */
}
void
{
(void) textdomain(TEXT_DOMAIN);
/*
* Display the table header for CPUs . Then display the CPU
* frequency, cache size, and processor revision of all cpus.
*/
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n\n", 0);
"",
gettext("CPU "),
gettext("Run"),
gettext(" E$"),
gettext(" CPU"),
gettext("CPU"), 0);
gettext("Slot ID"),
gettext("ID "),
gettext("MHz"),
gettext(" MB"),
gettext("Impl."),
gettext("Mask"), 0);
"--------", "-------", "----", "----", "-------", "----", 0);
/* Now display all of the cpus on each board */
}
log_printf("\n", 0);
}
/*
* Display the CPUs present on this board.
*/
void
{
int *impl;
int *mask;
int decoded_mask;
int *cpuid;
int *coreid;
int ecache_size_prev = 0;
(void) textdomain(TEXT_DOMAIN);
/*
* display the CPUs' operating frequency, cache size, impl. field
* and mask revision.
*/
/* Do not display a failed CPU node */
continue;
if (CPU_IMPL_IS_CMP(*impl)) {
"reg"));
continue;
}
/*
* The assumption is made that 2 cores will always be
* listed together in the device tree. If either core
* is "bad" then the FRU will not be listed.
*/
if (cpuid_prev == -1) {
cpuid_prev = *cpuid;
continue;
} else {
/*
* Jaguar has a split E$, so the size for both
* cores must be added together to get the total
* size for the entire chip.
*
* Panther E$ (L3) is logically shared, so the
* total size is equal to the core size.
*/
}
ecache_size_prev = 0;
}
}
/*
* Print out cpu data.
*
* Slot ID
*/
log_printf("/%-2s%02d/P%1d ",
PORTID_TO_INSTANCE(*cpuid), 0);
/* CPU ID */
if (CPU_IMPL_IS_CMP(*impl)) {
*cpuid, 0);
cpuid_prev = -1;
} else
/* Running frequency */
/* Ecache size */
if (ecache_size == 0)
else
log_printf("%4.1f ",
0);
/* Implementation */
switch (*impl) {
case CHEETAH_IMPL:
log_printf("%-7.7s ",
gettext("US-III"), 0);
break;
case CHEETAH_PLUS_IMPL:
log_printf("%-7.7s ",
gettext("US-III+"), 0);
break;
case JAGUAR_IMPL:
log_printf("%-7.7s ",
gettext("US-IV"), 0);
break;
case PANTHER_IMPL:
log_printf("%-7.7s ",
gettext("US-IV+"), 0);
break;
default:
break;
}
/* CPU Mask */
} else {
if (IS_CHEETAH(*impl))
else
decoded_mask = *mask;
log_printf("%d.%d",
decoded_mask & 0xf, 0);
}
log_printf("\n", 0);
}
}
/*ARGSUSED1*/
void
{
" %-10.10s %-10.10s";
(void) textdomain(TEXT_DOMAIN);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n", 0);
"", "",
gettext("Logical"),
gettext("Logical"),
gettext("Logical"),
"", "", "", 0);
"",
gettext("Port"),
gettext("Bank"),
gettext("Bank"),
gettext("Bank"),
gettext(" DIMM"),
gettext("Interleave"),
gettext("Interleave"), 0);
gettext("Slot ID"),
gettext(" ID"),
gettext("Number"),
gettext("Size"),
gettext("Status"),
gettext(" Size"),
gettext("Factor"),
gettext("Segment"), 0);
"-----------", "----", "-------", "-------", "--------",
"------", "----------", "----------", 0);
if (get_us3_mem_regs(bnode)) {
"\nFailed to get memory information.\n"),
0);
return;
}
}
/* Display what we have found */
}
/*
* This function provides Starcat's formatting of the memory config
* information that get_us3_mem_regs() and display_us3_banks() code has
* gathered. It overrides the generic print_us3_memory_line() code
* which prints an error message.
*/
void
{
(void) textdomain(TEXT_DOMAIN);
/* Slot ID */
log_printf("\n/%-2s%02d/P%1d/B%1d ",
/* Port ID */
/* Logical Bank Number */
/* Logical Bank Size */
/* Logical Bank Status */
/* DIMM Size */
/* Interleave Factor */
/* Interleave Segment */
}
/*ARGSUSED2*/
void
struct system_kstat_data *kstats)
{
if (flag) {
/*
* display time of latest powerfail. Not all systems
* have this capability. For those that do not, this
* is just a no-op.
*/
(void) textdomain(TEXT_DOMAIN);
/* Print the header */
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n\n", 0);
log_printf("\n", 0);
0);
log_printf("\n", 0);
/* Print the PROM revisions here */
}
}
/*
* local functions - functions that are only needed inside this library
*/
static void
{
char *version;
(void) textdomain(TEXT_DOMAIN);
/* Print the header */
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n\n", 0);
/* Display Prom revision header */
log_printf("\n---------------------------\n", 0);
/*
* Display OBP version info
*/
}
}
/*
* We call do_devinfo() in order to use the libdevinfo device tree
* instead of OBP's device tree.
*/
int
{
}
/*
* return the property value for the Prop
* passed in. (When using libdevinfo)
*/
void *
{
return (NULL);
}
/*
* Search a Prom node and retrieve the property with the correct
* name. (When using libdevinfo)
*/
Prop *
{
return (NULL);
break;
}
return (prop);
}
/*
* This function searches through the properties of the node passed in
* and returns a pointer to the value of the name property.
* (When using libdevinfo)
*/
char *
{
return (NULL);
}
}
return (NULL);
}
/*
* This function searches through the properties of the node passed in
* and returns a pointer to the value of the device_type property.
* (When using libdevinfo)
*/
char *
{
return (NULL);
}
}
return (NULL);
}