#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/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/openpromio.h>
#include <sys/systeminfo.h>
#include <kstat.h>
#include <libintl.h>
#include <syslog.h>
#include <sys/dkio.h>
#include "pdevinfo.h"
#include "display.h"
#include "pdevinfo_sun4u.h"
#include "display_sun4u.h"
#include "libprtdiag.h"
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
Prom_node *
find_pci_bus(Prom_node *node, int id, int bus)
{
Prom_node *pnode;
pnode = dev_find_node(node, "pci");
while (pnode != NULL) {
int tmp_id;
int tmp_bus;
tmp_id = get_id(pnode);
tmp_bus = get_pci_bus(pnode);
if ((tmp_id == id) &&
(tmp_bus == bus)) {
break;
}
pnode = dev_next_node(pnode, "pci");
}
return (pnode);
}
int
get_pci_bus(Prom_node *pnode)
{
int *value;
if ((value = (int *)get_prop_val(find_prop(pnode, "bus-range"))) ==
NULL) {
return (-1);
}
if (*value == 0) {
return (1);
} else {
return (0);
}
}
int
get_pci_device(Prom_node *pnode)
{
void *value;
value = get_prop_val(find_prop(pnode, "assigned-addresses"));
if (value != NULL) {
return (PCI_DEVICE(*(int *)value));
} else {
return (-1);
}
}
int
get_pci_to_pci_device(Prom_node *pnode)
{
void *value;
value = get_prop_val(find_prop(pnode, "reg"));
if (value != NULL) {
return (PCI_DEVICE(*(int *)value));
} else {
return (-1);
}
}
void
free_io_cards(struct io_card *card_list)
{
if (card_list != NULL) {
struct io_card *p, *q;
for (p = card_list, q = NULL; p != NULL; p = q) {
q = p->next;
free(p);
}
}
}
struct io_card *
insert_io_card(struct io_card *list, struct io_card *card)
{
struct io_card *newcard;
struct io_card *p, *q;
if (card == NULL)
return (list);
newcard = (struct io_card *)malloc(sizeof (struct io_card));
if (newcard == NULL) {
perror("malloc");
exit(2);
}
(void) memcpy(newcard, card, sizeof (struct io_card));
newcard->next = NULL;
if (list == NULL)
return (newcard);
for (p = list, q = NULL; p != NULL; q = p, p = p->next) {
if (newcard->board < p->board)
break;
if ((newcard->board == p->board) && (newcard->slot < p->slot))
break;
}
if (q == NULL) {
newcard->next = p;
return (newcard);
} else {
newcard->next = p;
q->next = newcard;
return (list);
}
}
char *
fmt_manf_id(unsigned int encoded_id, char *outbuf)
{
union manuf manuf;
manuf.encoded_id = encoded_id;
switch (manuf.fld.manf) {
case MANF_BROOKTREE:
(void) sprintf(outbuf, "%s %d, version %d", "Brooktree",
manuf.fld.partno, manuf.fld.version);
break;
case MANF_MITSUBISHI:
(void) sprintf(outbuf, "%s %x, version %d", "Mitsubishi",
manuf.fld.partno, manuf.fld.version);
break;
default:
(void) sprintf(outbuf, "JED code %d, Part num 0x%x, version %d",
manuf.fld.manf, manuf.fld.partno, manuf.fld.version);
}
return (outbuf);
}
int
get_sbus_slot(Prom_node *pnode)
{
void *value;
if ((value = get_prop_val(find_prop(pnode, "reg"))) != NULL) {
return (*(int *)value);
} else {
return (-1);
}
}
void
display_io_devices(Sys_tree *tree)
{
Board_node *bnode;
log_printf("\n", 0);
log_printf("=========================", 0);
log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
log_printf("=========================", 0);
log_printf("\n", 0);
log_printf("\n", 0);
bnode = tree->bd_list;
while (bnode != NULL) {
display_sbus(bnode);
display_pci(bnode);
display_ffb(bnode, 1);
bnode = bnode->next;
}
}
void
display_pci(Board_node *bnode)
{
#ifdef lint
bnode = bnode;
#endif
}
void
display_io_cards(struct io_card *list)
{
static int banner = 0;
struct io_card *p;
if (list == NULL)
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;
}
for (p = list; p != NULL; p = p -> next) {
log_printf("%2d ", p->board, 0);
log_printf("%-4s ", p->bus_type, 0);
log_printf("%3d ", p->freq, 0);
if (p->slot == PCI_SLOT_IS_STRING)
log_printf("%10s ", p->slot_str, 0);
else
log_printf("%10d ", p->slot, 0);
log_printf("%-28.28s", p->name, 0);
if (strlen(p->name) > 28)
log_printf("+ ", 0);
else
log_printf(" ", 0);
log_printf("%-19.19s", p->model, 0);
if (strlen(p->model) > 19)
log_printf("+", 0);
log_printf("\n", 0);
}
}
void
display_ffb(Board_node *board, int table)
{
Prom_node *fb;
void *value;
struct io_card *card_list = NULL;
struct io_card card;
char *type;
char *label;
if (board == NULL)
return;
card.display = 1;
card.board = board->board_num;
(void) sprintf(card.bus_type, BUS_TYPE);
card.freq = sys_clk;
for (fb = dev_find_node_by_type(board->nodes, "device_type", "display");
fb != NULL;
fb = dev_next_node_by_type(fb, "device_type", "display")) {
value = get_prop_val(find_prop(fb, "name"));
if (value != NULL) {
if ((strcmp(FFB_NAME, value)) == 0) {
type = FFB_NAME;
label = "FFB";
} else if ((strcmp(AFB_NAME, value)) == 0) {
type = AFB_NAME;
label = "AFB";
} else
continue;
} else
continue;
if (table == 1) {
card.slot = get_id(fb);
(void) sprintf(card.name, "%s", label);
value = get_prop_val(find_prop(fb, "board_type"));
if (value != NULL)
if ((*(int *)value) & FFB_B_BUFF)
(void) sprintf(card.name,
"%s, Double Buffered", label);
else
(void) sprintf(card.name,
"%s, Single Buffered", label);
card.model[0] = '\0';
if (strcmp(type, AFB_NAME) == 0) {
if (((*(int *)value) & 0x4) != 0x4) {
value = get_prop_val(find_prop(fb,
"model"));
if ((value != NULL) &&
(strcmp(value,
"SUNW,XXX-XXXX") != 0)) {
(void) sprintf(card.model, "%s",
(char *)value);
}
}
} else {
value = get_prop_val(find_prop(fb, "model"));
if (value != NULL)
(void) sprintf(card.model, "%s",
(char *)value);
}
card_list = insert_io_card(card_list, &card);
} else {
char device[MAXSTRLEN];
int fd = -1;
struct dirent *direntp;
DIR *dirp;
union strap_un strap;
struct ffb_sys_info fsi;
value = get_prop_val(find_prop(fb, "upa-portid"));
if (value == NULL)
value = get_prop_val(find_prop(fb, "portid"));
if (value == NULL)
continue;
(void) sprintf(device, "%s@%x", type,
*(int *)value);
if ((dirp = opendir("/devices")) == NULL)
continue;
while ((direntp = readdir(dirp)) != NULL) {
if (strstr(direntp->d_name, device) != NULL) {
(void) sprintf(device, "/devices/%s",
direntp->d_name);
fd = open(device, O_RDWR, 0666);
break;
}
}
(void) closedir(dirp);
if (fd == -1)
continue;
if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
continue;
log_printf("%s Hardware Configuration:\n", label, 0);
log_printf("-----------------------------------\n", 0);
strap.ffb_strap_bits = fsi.ffb_strap_bits;
log_printf("\tBoard rev: %d\n",
(int)strap.fld.board_rev, 0);
log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
log_printf("\tDAC: %s\n",
fmt_manf_id(fsi.dac_version, device), 0);
log_printf("\t3DRAM: %s\n",
fmt_manf_id(fsi.fbram_version, device), 0);
log_printf("\n", 0);
}
}
display_io_cards(card_list);
free_io_cards(card_list);
}
void
display_sbus(Board_node *board)
{
struct io_card card;
struct io_card *card_list = NULL;
int freq;
int card_num;
void *value;
Prom_node *sbus;
Prom_node *card_node;
if (board == NULL)
return;
for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
sbus = dev_next_node(sbus, SBUS_NAME)) {
if (node_failed(sbus))
continue;
value = get_prop_val(find_prop(sbus, "clock-frequency"));
if (value != NULL)
freq = ((*(int *)value) + 500000) / 1000000;
else
freq = -1;
for (card_node = sbus->child; card_node != NULL;
card_node = card_node->sibling) {
char *model;
char *name;
char *child_name;
card_num = get_sbus_slot(card_node);
if (card_num == -1)
continue;
card.display = 1;
card.freq = freq;
card.board = board->board_num;
(void) sprintf(card.bus_type, "SBus");
card.slot = card_num;
card.status[0] = '\0';
value = get_prop_val(find_prop(card_node, "status"));
if (value != NULL)
(void) strncpy(card.status, (char *)value,
MAXSTRLEN);
if (strstr(card.status, "fail") != NULL)
continue;
model = (char *)get_prop_val(find_prop(card_node,
"model"));
name = get_node_name(card_node);
if (name == NULL)
continue;
card.name[0] = '\0';
card.model[0] = '\0';
child_name = get_node_name(card_node->child);
if ((card_node->child != NULL) &&
(child_name != NULL)) {
value = get_prop_val(find_prop(card_node->child,
"device_type"));
if (value != NULL)
(void) sprintf(card.name, "%s/%s (%s)",
name, child_name,
(char *)value);
else
(void) sprintf(card.name, "%s/%s", name,
child_name);
} else {
(void) strncpy(card.name, name, MAXSTRLEN);
}
if (model != NULL)
(void) strncpy(card.model, model, MAXSTRLEN);
card_list = insert_io_card(card_list, &card);
}
}
display_io_cards(card_list);
free_io_cards(card_list);
}
int
populate_slot_name_arr(Prom_node *pci, int *slot_name_bits,
char **slot_name_arr, int num_slots)
{
int i, j, bit_mask;
char *value;
value = (char *)get_prop_val(find_prop(pci, "slot-names"));
D_PRINTF("\n populate_slot_name_arr: value = [0x%x]\n", value);
if (value != NULL) {
char *strings_arr[MAX_SLOTS_PER_IO_BD];
bit_mask = *slot_name_bits = *(int *)value;
D_PRINTF("\nslot_names 1st integer = [0x%x]", *slot_name_bits);
strings_arr[0] = value + sizeof (int);
for (i = 1; i < num_slots; i++) {
strings_arr[i] = (char *)strings_arr[i - 1]
+ strlen(strings_arr[i - 1]) + 1;
}
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
get_card_frequency(Prom_node *pci)
{
char *value = get_prop_val(find_prop(pci, "clock-frequency"));
if (value == NULL)
return (-1);
else
return (int)(((*(int *)value) + 500000) / 1000000);
}
void
get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no)
{
void *value = get_prop_val(find_prop(card_node, "reg"));
if (value != NULL) {
int int_val = *(int *)value;
*dev_no = PCI_REG_TO_DEV(int_val);
*func_no = PCI_REG_TO_FUNC(int_val);
} else {
*dev_no = -1;
*func_no = -1;
}
}
void
get_pci_class_codes(Prom_node *card_node, int *class_code, int *subclass_code)
{
int class_code_reg = get_pci_class_code_reg(card_node);
*class_code = CLASS_REG_TO_CLASS(class_code_reg);
*subclass_code = CLASS_REG_TO_SUBCLASS(class_code_reg);
}
int
is_pci_bridge(Prom_node *card_node, char *name)
{
int class_code, subclass_code;
if (card_node == NULL)
return (FALSE);
get_pci_class_codes(card_node, &class_code, &subclass_code);
if ((strncmp(name, "pci", 3) == 0) &&
(class_code == PCI_BRIDGE_CLASS) &&
(subclass_code == PCI_PCI_BRIDGE_SUBCLASS))
return (TRUE);
else
return (FALSE);
}
int
is_pci_bridge_other(Prom_node *card_node, char *name)
{
int class_code, subclass_code;
if (card_node == NULL)
return (FALSE);
get_pci_class_codes(card_node, &class_code, &subclass_code);
if ((strncmp(name, "pci", 3) == 0) &&
(class_code == PCI_BRIDGE_CLASS) &&
(subclass_code == PCI_SUBCLASS_OTHER))
return (TRUE);
else
return (FALSE);
}
void
get_pci_card_model(Prom_node *card_node, char *model)
{
char *name = get_prop_val(find_prop(card_node, "name"));
char *value = get_prop_val(find_prop(card_node, "model"));
int pci_bridge = is_pci_bridge(card_node, name);
if (value == NULL)
model[0] = '\0';
else
(void) sprintf(model, "%s", value);
if (pci_bridge) {
if (strlen(model) == 0)
(void) sprintf(model, "%s", "pci-bridge");
else
(void) sprintf(model, "%s/pci-bridge", model);
}
}
void
create_io_card_name(Prom_node *card_node, char *name, char *card_name)
{
char *value = get_prop_val(find_prop(card_node, "compatible"));
char *child_name;
char buf[MAXSTRLEN];
if (value != NULL) {
(void) sprintf(buf, "%s-%s", name, value);
} else
(void) sprintf(buf, "%s", name);
name = buf;
child_name = (char *)get_node_name(card_node->child);
if ((card_node->child != NULL) &&
(child_name != NULL)) {
value = get_prop_val(find_prop(card_node->child,
"device_type"));
if (value != NULL)
(void) sprintf(card_name, "%s/%s (%s)",
name, child_name, value);
else
(void) sprintf(card_name, "%s/%s", name,
child_name);
} else {
(void) sprintf(card_name, "%s", name);
}
}
void
display_psycho_pci(Board_node *board)
{
struct io_card *card_list = NULL;
struct io_card card;
void *value;
Prom_node *pci, *card_node, *pci_bridge_node = NULL;
char *name;
int slot_name_bits, pci_bridge_dev_no, class_code,
subclass_code, pci_pci_bridge;
char *slot_name_arr[MAX_SLOTS_PER_IO_BD];
if (board == NULL)
return;
card.display = 1;
card.board = board->board_num;
(void) sprintf(card.bus_type, "PCI");
for (pci = dev_find_node_by_type(board->nodes, "model", "SUNW,psycho");
pci != NULL;
pci = dev_next_node_by_type(pci, "model", "SUNW,psycho")) {
if (find_prop(pci, "upa-portid") == NULL) {
if ((pci->parent->sibling != NULL) &&
(strcmp(get_prop_val(
find_prop(pci->parent->sibling,
"name")), PCI_NAME) == 0)) {
pci = pci->parent->sibling;
} else {
pci = pci->parent->sibling;
continue;
}
}
D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n",
PCI_NAME, *((int *)get_prop_val(find_prop(
pci, "upa-portid"))),
get_prop_val(find_prop(pci, "model")));
if (node_failed(pci))
continue;
card.freq = get_card_frequency(pci);
if ((populate_slot_name_arr(pci, &slot_name_bits,
(char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0)
goto next_card;
card_node = pci->child;
while (card_node != NULL) {
pci_pci_bridge = FALSE;
name = (char *)get_prop_val(
find_prop(card_node, "name"));
if (name == NULL)
goto next_card;
get_dev_func_num(card_node, &card.dev_no,
&card.func_no);
get_pci_class_codes(card_node, &class_code,
&subclass_code);
D_PRINTF("\nName [%s] - ", name);
D_PRINTF("device no [%d] - ", card.dev_no);
D_PRINTF("class_code [%d] subclass_code [%d] - ",
class_code, subclass_code);
if (((class_code == PCI_BRIDGE_CLASS) &&
(subclass_code == PCI_SUBCLASS_OTHER)) ||
(strstr(name, "ebus"))) {
D_PRINTF("\nSkip ebus/class-other nodes [%s]",
name);
goto next_card;
}
if (is_pci_bridge(card_node, name)) {
pci_bridge_dev_no = card.dev_no;
pci_bridge_node = card_node;
pci_pci_bridge = TRUE;
D_PRINTF("\nPCI Bridge detected\n");
}
if (card_node->parent == pci_bridge_node)
card.dev_no = pci_bridge_dev_no;
get_slot_number_str(&card, (char **)slot_name_arr,
slot_name_bits);
if (slot_name_bits) {
D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr "
"[%s] slot [%s]", name, card.dev_no,
slot_name_arr[card.dev_no],
card.slot_str);
}
card.status[0] = '\0';
get_pci_card_model(card_node, (char *)&card.model);
value = get_prop_val(find_prop(pci, "clock-frequency"));
if (value != NULL && card.freq == -1)
card.freq = ((*(int *)value) + 500000)
/ 1000000;
create_io_card_name(card_node, name,
(char *)&card.name);
if (card.freq != -1)
card_list = insert_io_card(card_list, &card);
next_card:
if (pci_pci_bridge) {
if (card_node->child != NULL)
card_node = card_node->child;
else
card_node = card_node->sibling;
} else {
if ((card_node->parent == pci_bridge_node) &&
(card_node->sibling == NULL))
card_node = pci_bridge_node->sibling;
else
card_node = card_node->sibling;
}
}
}
D_PRINTF("\n\n");
display_io_cards(card_list);
free_io_cards(card_list);
}
void
get_slot_number_str(struct io_card *card, char **slot_name_arr,
int slot_name_bits)
{
if (card->dev_no != -1) {
char *slot;
if (slot_name_bits & (1 << card->dev_no)) {
slot = slot_name_arr[card->dev_no];
if (strlen(slot) != 0) {
(void) sprintf(card->slot_str, "%s",
slot);
} else
(void) sprintf(card->slot_str, "-");
} else {
(void) sprintf(card->slot_str, "On-Board");
}
} else {
(void) sprintf(card->slot_str, "%c", '-');
}
card->slot = PCI_SLOT_IS_STRING;
}
void
distinguish_identical_io_cards(char *name, Prom_node *node,
struct io_card *card)
{
if ((name == NULL) || (node == NULL))
return;
if (strcmp(name, "SUNW,qlc") == 0)
decode_qlc_card_model_prop(node, card);
}
void
decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card)
{
void *value = NULL;
if (card_node == NULL)
return;
value = get_prop_val(find_prop(card_node, "subsystem-id"));
if (value != NULL) {
int id = *(int *)value;
switch (id) {
case AMBER_SUBSYSTEM_ID:
(void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
AMBER_CARD_NAME);
break;
case CRYSTAL_SUBSYSTEM_ID:
(void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
CRYSTAL_CARD_NAME);
break;
default:
if (strcmp(card->model, "") == 0) {
(void) snprintf(card->model, MAX_QLC_MODEL_LEN,
"0x%x", id);
}
break;
}
}
}