/*
* 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 (c) 1999-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#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 <sys/systeminfo.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
{
/* find the first pci node */
int tmp_id;
int tmp_bus;
break;
}
}
return (pnode);
}
/*
* get_pci_bus
*
* Determines the PCI bus, either A (0) or B (1). If the function cannot
* find the bus-ranges property, it returns -1.
*/
int
{
int *value;
/* look up the bus-range property */
NULL) {
return (-1);
}
if (*value == 0) {
return (1); /* B bus has a bus-range value = 0 */
} else {
return (0);
}
}
/*
* Find the PCI device number of this PCI device. If no device number can
* be determined, then return -1.
*/
int
{
void *value;
NULL) {
return (PCI_DEVICE(*(int *)value));
} else {
return (-1);
}
}
/*
* Find the PCI device number of this PCI device. If no device number can
* be determined, then return -1.
*/
int
{
void *value;
NULL) {
return (PCI_DEVICE(*(int *)value));
} else {
return (-1);
}
}
/*
* free_io_cards
* Frees the memory allocated for an io card list.
*/
void
{
/* Free the list */
struct io_card *p, *q;
q = p->next;
free(p);
}
}
}
/*
* insert_io_card
* Inserts an io_card structure into the list. The list is maintained
* in order based on board number and slot number. Also, the storage
* for the "card" argument is assumed to be handled by the caller,
* so we won't touch it.
*/
struct io_card *
{
struct io_card *p, *q;
return (list);
/* Copy the card to be added into new storage */
perror("malloc");
exit(2);
}
return (newcard);
/* Find the proper place in the list for the new card */
break;
break;
}
/* Insert the new card into the list */
if (q == NULL) {
return (newcard);
} else {
return (list);
}
}
char *
{
/*
* Format the manufacturer's info. Note a small inconsistency we
* have to work around - Brooktree has it's part number in decimal,
* while Mitsubishi has it's part number in hex.
*/
case MANF_BROOKTREE:
break;
case MANF_MITSUBISHI:
break;
default:
}
return (outbuf);
}
/*
* Find the sbus slot number of this Sbus device. If no slot number can
* be determined, then return -1.
*/
int
{
void *value;
return (*(int *)value);
} else {
return (-1);
}
}
/*
* This routine is the generic link into displaying system IO
* configuration. It displays the table header, then displays
* all the SBus cards, then displays all fo the PCI IO cards.
*/
void
{
/*
* TRANSLATION_NOTE
* Following string is used as a table header.
* Please maintain the current alignment in
* translation.
*/
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf("=========================", 0);
log_printf("\n", 0);
log_printf("\n", 0);
}
}
void
{
#ifdef lint
#endif
/*
* This function is intentionally empty
*/
}
/*
* 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;
}
/*
* We check to see if it's an int or
* a char string to display for slot.
*/
if (p->slot == PCI_SLOT_IS_STRING)
else
log_printf("+ ", 0);
else
log_printf(" ", 0);
log_printf("+", 0);
log_printf("\n", 0);
}
}
/*
* Display all FFBs on this board. It can either be in tabular format,
* or a more verbose format.
*/
void
{
void *value;
char *type;
char *label;
return;
/* Fill in common information */
label = "FFB";
label = "AFB";
} else
continue;
} else
continue;
if (table == 1) {
/* Print out in table format */
/* XXX - Get the slot number (hack) */
/* Find out if it's single or double buffered */
if ((*(int *)value) & FFB_B_BUFF)
"%s, Double Buffered", label);
else
"%s, Single Buffered", label);
/*
* Print model number only if board_type bit 2
* is not set and it is not SUNW,XXX-XXXX.
*/
"model"));
"SUNW,XXX-XXXX") != 0)) {
(char *)value);
}
}
} else {
(char *)value);
}
} else {
/* print in long format */
/* Find the device node using upa-portid/portid */
continue;
*(int *)value);
continue;
break;
}
}
if (fd == -1)
continue;
continue;
log_printf("-----------------------------------\n", 0);
log_printf("\tBoard rev: %d\n",
log_printf("\tDAC: %s\n",
log_printf("\t3DRAM: %s\n",
log_printf("\n", 0);
}
}
}
/*
* Display all the SBus IO cards on this board.
*/
void
{
int freq;
int card_num;
void *value;
return;
/* Skip failed nodes for now */
if (node_failed(sbus))
continue;
/* Calculate SBus frequency in MHz */
else
freq = -1;
char *model;
char *name;
char *child_name;
if (card_num == -1)
continue;
/* Fill in card information */
/* Try and get card status */
/* XXX - For now, don't display failed cards */
continue;
/* Now gather all of the node names for that card */
"model"));
continue;
/* Figure out how we want to display the name */
(child_name != NULL)) {
"device_type"));
(char *)value);
else
} else {
}
}
}
/* We're all done gathering card info, now print it out */
}
/*
* Get slot-names properties from parent node and
* store them in an array.
*/
int
char **slot_name_arr, int num_slots)
{
int i, j, bit_mask;
char *value;
/* array starts after first int */
strings_arr[0] = value + sizeof (int);
/*
* break the array out into num_slots number of strings
*/
for (i = 1; i < num_slots; i++) {
}
/*
* process array of slot_names to remove blanks
*/
j = 0;
for (i = 0; i < num_slots; i++) {
if ((bit_mask >> i) & 0x1)
slot_name_arr[i] = strings_arr[j++];
else
slot_name_arr[i] = "";
D_PRINTF("\nslot_name_arr[%d] = [%s]", i,
slot_name_arr[i]);
}
return (0);
} else {
D_PRINTF("\n populate_slot_name_arr: - psycho with no "
"slot-names\n");
return (0);
}
}
int
{
return (-1);
else
}
void
{
} else {
*dev_no = -1;
*func_no = -1;
}
}
void
{
}
int
{
return (FALSE);
(class_code == PCI_BRIDGE_CLASS) &&
return (TRUE);
else
return (FALSE);
}
int
{
return (FALSE);
(class_code == PCI_BRIDGE_CLASS) &&
return (TRUE);
else
return (FALSE);
}
void
{
model[0] = '\0';
else
(char *)value);
if (pci_bridge) {
"%s", "pci-bridge");
else
"%s/pci-bridge", model);
}
}
void
{
char *child_name;
(char *)value);
} else
(child_name != NULL)) {
"device_type"));
(char *)value);
else
} else {
}
}
/*
* Desktop display_psycho_pci
* Display all the psycho based PCI IO cards on this board.
*/
/* ARGSUSED */
void
{
void *value;
char *name;
return;
/* Initialize all the common information */
/*
* 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;
}
}
D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n",
pci, "upa-portid"))),
/* Skip all failed nodes for now */
if (node_failed(pci))
continue;
/* Fill in frequency */
/*
* Each PSYCHO device has a slot-names property that can be
* used to determine the slot-name string for each IO
* device under this node. We get this array now and use
* it later when looking at the children of this PSYCHO.
*/
(char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0)
goto next_card;
/* Walk through the PSYCHO children */
/* If it doesn't have a name, skip it */
name = (char *)get_prop_val(
goto next_card;
/* get dev# and func# for this card. */
D_PRINTF("class_code [%d] subclass_code [%d] - ",
/*
* Weed out PCI Bridge, subclass 'other' and
* ebus nodes.
*/
if (((class_code == PCI_BRIDGE_CLASS) &&
(subclass_code == PCI_SUBCLASS_OTHER)) ||
D_PRINTF("\nSkip ebus/class-other nodes [%s]",
name);
goto next_card;
}
/*
* If this is a PCI bridge, then we store it's dev_no
* so that it's children can use it for getting at
* the slot_name.
*/
D_PRINTF("\nPCI Bridge detected\n");
}
/*
* 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.
*/
/* Get slot-names property from slot_names_arr. */
if (slot_name_bits)
D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr "
/* XXX - Don't know how to get status for PCI cards */
/* Get the model of this card */
/*
* If we haven't figured out the frequency yet,
* try and get it from the card.
*/
/ 1000000;
/* Figure out how we want to display the 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 - otherwise we move onto our
* own sibling.
*/
if (pci_pci_bridge) {
else
} else {
else
}
} /* end-while */
} /* end-for */
D_PRINTF("\n\n");
}
void
int slot_name_bits)
{
char *slot;
/*
* slot_name_bits is a mask of the plug-in slots so if our
* dev_no does not appear in this mask we must be an
* on_board device so set the slot to 'On-Board'
*/
/* we are a plug-in card */
slot);
} else
} else {
/* this is an on-board dev. */
}
} else {
}
/* Informs display_io_cards to print slot_str instead of slot */
}
/*
* The output of a number of I/O cards are identical so we need to
* differentiate between them.
*
* This function is called by the platform specific code and it decides
* if the card needs further processing.
*
* It can be extended in the future if card types other than QLC have
* the same problems.
*/
void
{
return;
}
/*
* identical (*), so we need to distinguish them using the subsystem-id
* and modify the model string to be more informative.
*
* (*) Currently the problem cards are:
* Amber
* Crystal+
*/
void
{
return;
switch (id) {
case AMBER_SUBSYSTEM_ID:
break;
case CRYSTAL_SUBSYSTEM_ID:
break;
default:
/*
* If information has been saved into the model field
* before this function was called we will keep it as
* it probably will be more meaningful that the
* subsystem-id, otherwise we save the subsystem-id in
* the hope that it will distinguish the cards.
*/
"0x%x", id);
}
break;
}
}
}