/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 1999-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Javelin Platform specific functions.
*
* called when :
* machine_type == MTYPE_JAVELIN
*
*/
#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 <errno.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/openpromio.h>
#include <kstat.h>
#include <libintl.h>
#include <syslog.h>
#include "pdevinfo.h"
#include "display.h"
#include "pdevinfo_sun4u.h"
#include "display_sun4u.h"
#include "libprtdiag.h"
#if !defined(TEXT_DOMAIN)
#endif
extern int print_flag;
/*
* these functions will overlay the symbol table of libprtdiag
* at runtime (workgroup server systems only)
*/
struct system_kstat_data *kstats);
void display_boardnum(int num);
void display_pci(Board_node *);
void display_ffb(Board_node *, int);
struct system_kstat_data *sys_kstat,
/* local functions */
static int disp_envc_status(struct system_kstat_data *);
static void tazjav_disp_asic_revs(Sys_tree *);
int
{
#ifdef lint
#endif
/*
* silently check for any types of machine errors
*/
print_flag = 0;
/* set exit_code to show failures */
exit_code = 1;
}
print_flag = 1;
return (exit_code);
}
/* Search for and return the node's sibling */
static Prom_node *
{
return (NULL);
/* look at your siblings */
return (NULL); /* not found */
}
/*
* The PROM device tree is read to obtain this information.
* Some of the information obtained is memory interleave factor,
* DIMM sizes, DIMM socket names.
*/
void
{
unsigned long size = 0;
int bank_count = 0;
char *sock_name;
char *status;
int total_size = 0;
#ifdef lint
#endif
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n", 0);
log_printf("\n", 0);
if (preg) {
}
log_printf(" Interlv. Socket Size\n", 0);
log_printf("Bank Group Name (MB) Status\n", 0);
log_printf("---- ----- ------ ---- ------\n", 0);
int bank_size = 0;
/*
* Skip empty banks
*/
bank_count++;
continue;
}
if (preg) {
} else {
if (preg) {
}
}
sock_name = (char *)(get_prop_val(
} else {
}
log_printf("%3d %5s %6s %4d %6s\n",
size, dimm_status, 0);
}
total_size += bank_size;
bank_count++;
}
log_printf("\n", 0);
}
/*
* disp_fail_parts
*
* Display the failed parts in the system. This function looks for
* the status property in all PROM nodes. On systems where
* the PROM does not supports passing diagnostic information
* thruogh the device tree, this routine will be silent.
*/
int
{
int exit_code;
int system_failed = 0;
char *fru;
char *sock_name;
exit_code = 0;
/* go through all of the boards looking for failed units. */
/* find failed chips */
system_failed = 1;
exit_code = 1;
if (print_flag == 0) {
return (exit_code);
}
log_printf("\n", 0);
"Replaceable Units (FRU) in System:\n"), 0);
log_printf("=========================="
"====================\n", 0);
}
void *value;
/* sanity check of data retreived from PROM */
continue;
}
name, 0);
"string: %s\n"), value, 0);
"Replaceable Unit is "), 0);
/*
* Determine whether FRU is CPU module, system
* board, or SBus card.
*/
"board\n"), 0);
"Card %d\n"), tazmo_physical_slot(
(void) tazmo_physical_slot(
NULL,
slot_str);
"in %s\n"), slot_str, 0);
"module Module %d\n"),
fru = (char *)(get_prop_val(
sock_name = (char *)(get_prop_val(
"socket %s\n"), fru,
sock_name, 0);
}
}
}
if (!system_failed) {
log_printf("\n", 0);
"in System\n"), 0);
log_printf("===========================\n", 0);
}
if (system_failed)
return (1);
else
return (0);
}
void
{
#ifdef lint
#endif
/* Display failed units */
(void) disp_fail_parts(tree);
}
void
struct system_kstat_data *kstats)
{
/*
* Now display the last powerfail time and the fatal hardware
* reset information. We do this under a couple of conditions.
* First if the user asks for it. The second is iof the user
* told us to do logging, and we found a system failure.
*/
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) disp_envc_status(kstats);
}
return;
}
/* ARGSUSED */
void
{
log_printf("SYS ", 0);
}
/*
* display_pci
* Display all the PCI IO cards on this board.
*/
/* ARGSUSED */
void
{
void *value;
return;
/* Initialize all the common information */
char *name;
int pci_pci_bridge = 0;
/*
* If we have reached a pci-to-pci bridge node,
* we are one level below the 'pci' nodes level
* in the device tree. To get back to that level,
* the search should continue with the sibling of
* the parent or else the remaining 'pci' cards
* will not show up in the output.
*/
"name")), PCI_NAME) == 0))
else {
continue;
}
}
/* Skip all failed nodes for now */
if (node_failed(pci))
continue;
/* Fill in frequency */
else
/* Walk through the PSYCHO children */
/* If it doesn't have a name, skip it */
name = (char *)get_prop_val(
continue;
}
/*
* If this is a PCI bridge, then display its
* children.
*/
pci_pci_bridge = 1;
continue;
}
/* Get the slot number for this card */
if (pci_pci_bridge) {
pci,
} else
"slot2dev"),
pci,
/*
* Check that duplicate devices are not reported
* on Tazmo.
*/
(pci_pci_bridge == 0))
continue;
}
/* XXX - Don't know how to get status for PCI cards */
/* Get the model of this card */
else
(char *)value);
/*
* Check if further processing is necessary to display
* this card uniquely.
*/
/*
* If we haven't figured out the frequency yet,
* try and get it from the card.
*/
/ 1000000;
"compatible"));
/*
* On Tazmo, we would like to print out the last
* string of the "compatible" property if it exists.
* The IEEE 1275 spec. states that this last string
* will be the classcode name.
*/
char *tval;
int index;
index = 0;
while (always) {
break;
}
}
else
(char *)name);
/*
* If we are done with the children of the pci bridge,
* we must continue with the remaining siblings of
* the pci-to-pci bridge.
*/
pci_pci_bridge = 0;
} else
}
}
}
/*
* Print out all the io cards in the list. Also print the column
* headers if told to do so.
*/
void
{
struct io_card *p;
return;
if (banner == 0) {
log_printf(" Bus Freq\n", 0);
log_printf("Brd Type MHz Slot "
"Name "
"Model", 0);
log_printf("\n", 0);
log_printf("--- ---- ---- ---- "
"-------------------------------- "
"----------------------", 0);
log_printf("\n", 0);
banner = 1;
}
log_printf("+ ", 0);
else
log_printf(" ", 0);
log_printf("+", 0);
log_printf("\n", 0);
}
}
/*
* display_ffb
* Display all FFBs on this board. It can either be in tabular format,
* or a more verbose format.
*/
void
{
void *value;
return;
/* Fill in common information */
if (table == 1) {
/* Print out in table format */
/* XXX - Get the slot number (hack) */
ffb,
-1,
/* Find out if it's single or double buffered */
if ((*(int *)value) & FFB_B_BUFF)
"FFB, Double Buffered");
else
"FFB, Single Buffered");
/* Print model number */
(char *)value);
} else {
/* print in long format */
/* Find the device node using upa address */
continue;
*(int *)value);
continue;
break;
}
}
if (fd == -1)
continue;
continue;
log_printf("FFB Hardware Configuration:\n", 0);
log_printf("-----------------------------------\n", 0);
log_printf("\tBoard rev: %d\n",
log_printf("\tFBC version: "
log_printf("\tDAC: %s\n",
log_printf("\t3DRAM: %s\n",
log_printf("\n", 0);
}
}
}
/*
* This module does the reading and interpreting of javelin system
* kstats. These kstats are created by the environ drivers.
*/
void
{
return;
}
#ifdef lint
#endif
/* read the envctrltwo kstats */
/* Read the power supply kstats */
} else {
return;
}
/* Read the fan status kstats */
} else {
return;
}
/* Read the enclosure kstats */
} else {
return;
}
/* Read the temperature kstats */
} else {
return;
}
/* Read the disk kstats */
} else {
return;
}
return;
}
/*
* Walk the PROM device tree and build the system tree and root tree.
* Nodes that have a board number property are placed in the board
* structures for easier processing later. Child nodes are placed
* under their parents. ffb (Fusion Frame Buffer) nodes are handled
* specially, because they do not contain board number properties.
* This was requested from OBP, but was not granted. So this code
* must parse the MID of the FFB to find the board#.
*/
{
register int curnode;
char *name;
char *type;
char *model;
int board_node = 0;
/* allocate a node for this level */
NULL) {
perror("malloc");
}
/* assign parent Prom_node */
/* read properties for this node */
/*
* Place a node in a 'board' if it has 'board'-ness. The definition
* is that all nodes that are children of root should have a
* board# property. But the PROM tree does not exactly follow
* this. This is where we start hacking. The name 'ffb' can
* change, so watch out for this.
*
* The UltraSPARC, sbus, pci and ffb nodes will exit in
* the desktops and will not have board# properties. These
* cases must be handled here.
*
* PCI to PCI bridges also have the name "pci", but with different
* model property values. They should not be put under 'board'.
*/
#ifdef DEBUG
printf("\n");
model = "";
#endif
type = "";
if (has_board_num(pnode)) {
board_node = 1;
#ifdef DEBUG
printf("ADDED BOARD name=%s type=%s model=%s\n",
#endif
board_node = 1;
#ifdef DEBUG
printf("ADDED BOARD name=%s type=%s model=%s\n",
#endif
}
#ifdef DEBUG
else
#endif
}
}
if (board_node) {
} else {
}
}
if (board_node) {
return (NULL);
} else {
return (pnode);
}
}
/*
* local functions
*/
/*
* disp_envc_status
*
* This routine displays the environmental status passed up from
* device drivers via kstats. The kstat names are defined in
* kernel header files included by this module.
* This is a Javelin specific environmental information display routine.
*/
static int
{
int i;
int exit_code = 0;
if (sys_kstats->envctrltwo_kstat_ok == 0) {
log_printf("\n", 0);
"is not available\n"), 0);
"not be installed\n"), 0);
log_printf("\n", 0);
return (1);
}
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n", 0);
log_printf("\n", 0);
log_printf("System Temperatures (Celsius):\n", 0);
log_printf("------------------------------\n", 0);
for (i = 0; i < ecp->num_temp_kstats; i++) {
log_printf(" CRITICAL\n", 0);
exit_code = 1;
log_printf(" WARNING\n", 0);
exit_code = 1;
log_printf(" WARNING\n", 0);
exit_code = 1;
} else
log_printf("\n", 0);
}
log_printf("\n", 0);
log_printf("=================================\n", 0);
log_printf("\n", 0);
switch (val) {
case ENVCTRL_UE250_FSP_KEYOFF:
break;
case ENVCTRL_UE250_FSP_KEYON:
break;
break;
break;
default:
exit_code = 1;
break;
}
log_printf("Front Status Panel:\n", 0);
log_printf("-------------------\n", 0);
log_printf("\n", 0);
log_printf("System LED Status: DISK ERROR POWER \n", 0);
log_printf(" [%3s] [ ON] \n",
log_printf(" POWER SUPPLY ERROR ACTIVITY \n", 0);
log_printf(" [%3s] [%3s] \n",
log_printf(" GENERAL ERROR THERMAL ERROR \n", 0);
log_printf(" [%3s] [%3s] \n",
exit_code = 1;
}
log_printf("\n", 0);
log_printf("=================================\n", 0);
log_printf("\n", 0);
for (i = 0; i < ecp->num_disk_kstats; i++) {
continue;
}
log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0);
log_printf(" DISK 5: %7s DISK 3: %7s DISK 1: %7s\n",
log_printf(" DISK 4: %7s DISK 2: %7s DISK 0: %7s\n",
log_printf("\n", 0);
log_printf("=================================\n", 0);
log_printf("\n", 0);
log_printf("Fan Bank :\n", 0);
log_printf("----------\n", 0);
log_printf("\n", 0);
log_printf("Bank Speed Status\n", 0);
log_printf(" (0-255) \n", 0);
log_printf("---- ----- ------\n", 0);
exit_code = 1;
}
log_printf("\n", 0);
log_printf("=================================\n", 0);
log_printf("\n", 0);
log_printf("Power Supplies:\n", 0);
log_printf("---------------\n", 0);
log_printf("\n", 0);
log_printf("Supply Status\n", 0);
log_printf("------ ------\n", 0);
for (i = 0; i < ecp->num_ps_kstats; i++) {
"Power Failure");
exit_code = 1;
}
}
return (exit_code);
}
void
{
char *name;
int *version;
char *model;
/* Print the header */
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf(" HW Revisions ", 0);
log_printf("=========================", 0);
log_printf("\n", 0);
log_printf("\n", 0);
log_printf("ASIC Revisions:\n", 0);
log_printf("---------------\n", 0);
/* Find sysio and print rev */
}
}
/* Find Psycho and print rev */
PCI_NAME) == 0))
else {
continue;
}
}
if (get_pci_bus(pnode) == 0)
}
/* Find Cheerio and print rev */
}
/* Find System Controller and print rev */
}
}
/* Find the FEPS and print rev */
if (*version == 0xa0) {
log_printf("2.0\n", 0);
} else if (*version == 0x20) {
log_printf("2.1\n", 0);
} else {
}
}
}
log_printf("\n", 0);
display_ffb(bnode, 0);
}
}
/*
* Determine the physical PCI slot based on which Psycho is the parent
* of the PCI card.
*/
static int
{
int offset;
char *name;
char *devpath_p;
int *slot_names_mask;
char *slot_names;
int shift = 0;
int slot;
/*
* If slotd != NULL, then we must return the physical PCI slot
* number based on the information in the slot2dev associations
* node. This routine is called from display_pci() with slotd
* != NULL. If so, we return without obtaining the slot name.
* If slotd == NULL, we look for the slot name through the
* slot-names property in the bus node.
*/
return (-1);
}
slots = 20;
slots = 2;
}
/*
* Javelin and future projects will use 0 based
* numbering for slots.
*/
start_slot = 0;
if ((devpath_p = (char *)(get_prop_val
NULL)
return (slot);
}
return (-1);
}
/*
* Get slot-names property from parent node.
* This property consists of a 32 bit mask indicating which
* devices are relevant to this bus node. Following are a
* number of strings depending on how many bits are set in the
* bit mask; the first string gives the label that is printed
* on the chassis for the smallest device number, and so on.
*/
return (-1);
}
slot_names = (char *)slot_names_mask;
slot = 1;
while (shift < 32) {
/*
* Shift through the bitmask looking to see if the
* bit corresponding to "device" is set. If so, copy
* the correcsponding string to the provided pointer.
*/
if (*slot_names_mask & slot) {
return (0);
}
}
shift++;
}
return (-1);
}