#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 <kstat.h>
#include <libintl.h>
#include <syslog.h>
#include <sys/dkio.h>
#include <sys/sbd_ioctl.h>
#include <sys/sbdp_mem.h>
#include <sys/serengeti.h>
#include <sys/mc.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
#define KBYTE 1024
#define MBYTE (KBYTE * KBYTE)
#define MEM_UK_SIZE_MASK 0x3FF
static memory_bank_t *bank_head;
static memory_bank_t *bank_tail;
static memory_seg_t *seg_head;
static void add_bank_node(uint64_t mc_decode, int portid, char *bank_status);
static void add_seg_node(void);
static memory_seg_t *match_seg(uint64_t);
void
display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
struct mem_total *memory_total)
{
log_printf(dgettext(TEXT_DOMAIN, "Memory size: "), 0);
if (sysconf(_SC_PAGESIZE) == -1 || sysconf(_SC_PHYS_PAGES) == -1)
log_printf(dgettext(TEXT_DOMAIN, "unable to determine\n"), 0);
else {
uint64_t mem_size;
mem_size =
(uint64_t)sysconf(_SC_PAGESIZE) * \
(uint64_t)sysconf(_SC_PHYS_PAGES);
if (mem_size >= MBYTE)
log_printf(dgettext(TEXT_DOMAIN, "%d Megabytes\n"),
(int)((mem_size+MBYTE-1) / MBYTE), 0);
else
log_printf(dgettext(TEXT_DOMAIN, "%d Kilobytes\n"),
(int)((mem_size+KBYTE-1) / KBYTE), 0);
}
}
void
display_memoryconf(Sys_tree *tree)
{
}
int
get_us3_mem_regs(Board_node *bnode)
{
Prom_node *pnode;
int portid;
uint64_t *ma_reg_arr;
uint64_t madr[NUM_MBANKS_PER_MC];
void *bank_status_array;
char *bank_status;
int i, status_offset;
for (pnode = dev_find_node(bnode->nodes, "memory-controller");
pnode != NULL;
pnode = dev_next_node(pnode, "memory-controller")) {
portid = (*(int *)get_prop_val(find_prop(pnode, "portid")));
ma_reg_arr = (uint64_t *)get_prop_val(
find_prop(pnode, MEM_CFG_PROP_NAME));
if (ma_reg_arr == NULL)
continue;
for (i = 0; i < NUM_MBANKS_PER_MC; i++) {
madr[i] = *ma_reg_arr++;
}
bank_status_array = (void *)get_prop_val(
find_prop(pnode, "bank-status"));
status_offset = 0;
for (i = 0; i < NUM_MBANKS_PER_MC; i++) {
if (bank_status_array) {
bank_status = ((char *)bank_status_array +
status_offset);
status_offset += (strlen(bank_status) + 1);
} else {
bank_status = strdup("no_status");
}
add_bank_node(madr[i], portid, bank_status);
add_seg_node();
}
}
return (0);
}
static void
add_bank_node(uint64_t mc_decode, int portid, char *bank_status)
{
static int id = 0;
memory_bank_t *new, *bank;
uint32_t ifactor = MC_INTLV(mc_decode);
uint64_t seg_size;
if ((new = malloc(sizeof (memory_bank_t))) == NULL) {
perror("malloc");
exit(1);
}
new->portid = portid;
new->id = id++;
new->valid = (mc_decode >> 63);
new->uk = MC_UK(mc_decode);
new->um = MC_UM(mc_decode);
new->lk = MC_LK(mc_decode);
new->lm = MC_LM(mc_decode);
seg_size = ((((uint64_t)new->uk & MEM_UK_SIZE_MASK) + 1) << 26);
new->bank_size = seg_size / ifactor;
new->bank_status = bank_status;
new->next = NULL;
new->seg_next = NULL;
if (bank_head == NULL) {
bank_head = new;
bank_tail = new;
return;
}
bank = bank_head;
while (bank->next)
bank = bank->next;
bank->next = new;
bank_tail = new;
}
void
display_us3_banks(void)
{
uint64_t base, bank_size;
uint32_t intlv;
memory_bank_t *bank, *tmp_bank;
memory_seg_t *seg;
int mcid;
uint64_t dimm_size;
uint64_t total_bank_size = 0;
uint64_t total_sys_mem;
static uint64_t bank0_size, bank1_size, bank2_size, bank3_size;
if ((bank_head == NULL) || (seg_head == NULL)) {
log_printf("\nCannot find any memory bank/segment info.\n");
return;
}
for (bank = bank_head; bank; bank = bank->next) {
intlv = ((bank->lk ^ 0xF) + 1);
base = bank->um & ~(bank->uk);
mcid = SG_PORTID_TO_SAFARI_ID(bank->portid);
if (bank->valid)
bank_size = ((bank->bank_size) / MBYTE);
else
bank_size = 0;
total_bank_size += bank_size;
seg = match_seg(base);
switch ((bank->id) % 4) {
case 0:
bank0_size = bank_size;
bank2_size = 0;
tmp_bank = bank->next;
while (tmp_bank) {
if (tmp_bank->valid == 0) {
tmp_bank = tmp_bank->next;
continue;
}
if (mcid != SG_PORTID_TO_SAFARI_ID(
tmp_bank->portid)) {
break;
}
if ((tmp_bank->id) % 4 == 2) {
bank2_size =
(tmp_bank->bank_size / MBYTE);
break;
}
tmp_bank = tmp_bank->next;
}
if (bank2_size)
dimm_size = (bank0_size + bank2_size) / 4;
else
dimm_size = bank0_size / 2;
break;
case 1:
bank1_size = bank_size;
bank3_size = 0;
tmp_bank = bank->next;
while (tmp_bank) {
if (tmp_bank->valid == 0) {
tmp_bank = tmp_bank->next;
continue;
}
if (mcid != SG_PORTID_TO_SAFARI_ID(
tmp_bank->portid)) {
break;
}
if ((tmp_bank->id) % 4 == 3) {
bank3_size =
(tmp_bank->bank_size / MBYTE);
break;
}
tmp_bank = tmp_bank->next;
}
if (bank3_size)
dimm_size = (bank1_size + bank3_size) / 4;
else
dimm_size = bank1_size / 2;
break;
case 2:
bank2_size = bank_size;
if (bank0_size)
dimm_size = (bank0_size + bank2_size) / 4;
else
dimm_size = bank2_size / 2;
break;
case 3:
bank3_size = bank_size;
if (bank1_size)
dimm_size = (bank1_size + bank3_size) / 4;
else
dimm_size = bank3_size / 4;
break;
}
if (bank->valid == 0)
continue;
print_us3_memory_line(bank->portid, bank->id, bank_size,
bank->bank_status, dimm_size, intlv, seg->id);
}
printf("\n");
total_sys_mem = (((uint64_t)sysconf(_SC_PAGESIZE) * \
(uint64_t)sysconf(_SC_PHYS_PAGES)) / MBYTE);
if (total_bank_size != total_sys_mem) {
log_printf(dgettext(TEXT_DOMAIN,
"\nError: total bank size [%lldMB] does not match total "
"system memory [%lldMB]\n"), total_bank_size,
total_sys_mem, 0);
}
}
static void
add_seg_node(void)
{
uint64_t base;
memory_seg_t *new;
static int id = 0;
memory_bank_t *bank = bank_tail;
if (bank->valid != 1)
return;
base = bank->um & ~(bank->uk);
if ((new = match_seg(base)) == NULL) {
if ((new = malloc(sizeof (memory_seg_t))) == NULL) {
perror("malloc");
exit(1);
}
new->id = id++;
new->base = base;
new->size = (((uint64_t)bank->uk +1) << 26);
new->intlv = ((bank->lk ^ 0xF) + 1);
new->next = seg_head;
seg_head = new;
}
new->nbanks++;
bank->seg_next = new->banks;
new->banks = bank;
}
static memory_seg_t *
match_seg(uint64_t base)
{
memory_seg_t *cur_seg;
for (cur_seg = seg_head; cur_seg; cur_seg = cur_seg->next) {
if (cur_seg-> base == base)
break;
}
return (cur_seg);
}
void
print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
{
log_printf(dgettext(TEXT_DOMAIN,
"\n No print_us3_memory_line() function specified for"
" this platform\n"), 0);
}
int
display_us3_failed_banks(int system_failed)
{
memory_bank_t *bank;
int found_failed_bank = 0;
if ((bank_head == NULL) || (seg_head == NULL)) {
log_printf("\nCannot find any memory bank/segment info.\n");
return (1);
}
for (bank = bank_head; bank; bank = bank->next) {
if ((bank->valid == 0) &&
(strcmp(bank->bank_status, "unpopulated"))) {
if (!system_failed && !found_failed_bank) {
found_failed_bank = TRUE;
log_printf("\n", 0);
log_printf(dgettext(TEXT_DOMAIN,
"Failed Field Replaceable Units (FRU) in "
"System:\n"), 0);
log_printf("=========================="
"====================\n", 0);
}
print_us3_failed_memory_line(bank->portid, bank->id,
bank->bank_status);
}
}
if (found_failed_bank)
return (1);
else
return (0);
}
void
print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
{
log_printf(dgettext(TEXT_DOMAIN,
"\n No print_us3_failed_memory_line() function specified for"
" this platform\n"), 0);
}