/*
* 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 <kstat.h>
#include <libintl.h>
#include <syslog.h>
#include <sys/sbd_ioctl.h>
#include <sys/sbdp_mem.h>
#include <sys/serengeti.h>
#include "pdevinfo.h"
#include "display.h"
#include "pdevinfo_sun4u.h"
#include "display_sun4u.h"
#include "libprtdiag.h"
#if !defined(TEXT_DOMAIN)
#endif
/*
* Global variables.
*/
/*
* Local functions.
*/
static void add_seg_node(void);
/*
* Used for US-I and US-II systems
*/
/*ARGSUSED0*/
void
{
else {
mem_size =
else
}
}
/*ARGSUSED0*/
void
{
/*
* This function is intentionally blank
*/
}
/*
* The following functions are for use by any US-III based systems.
* All they need to do is to call get_us3_mem_regs()
* and then display_us3_banks(). Each platform then needs to decide how
* to format this data by over-riding the generic function
* print_us3_memory_line().
*/
int
{
int portid;
void *bank_status_array;
char *bank_status;
int i, status_offset;
/* Get portid of this mc from libdevinfo. */
/* read the logical_bank_ma_regs property for this mc node. */
/*
* There are situations where a memory-controller node
* will not have the logical_bank_ma_regs property and
* we need to allow for these cases. They include:
* - Excalibur/Littleneck systems that only
* support memory on one of their CPUs.
* - Systems that support DR where a cpu board
* can be unconfigured but still connected.
* It is up to the caller of this function to ensure
* that the bank_head and seg_head pointers are not
* NULL after processing all memory-controllers in the
* system. This would indicate a situation where no
* memory-controllers in the system have a logical_bank_ma_regs
* property which should never happen.
*/
if (ma_reg_arr == NULL)
continue;
/*
* The first NUM_MBANKS_PER_MC of uint64_t's in the
* logical_bank_ma_regs property are the madr values.
*/
for (i = 0; i < NUM_MBANKS_PER_MC; i++) {
madr[i] = *ma_reg_arr++;
}
/*
* Get the bank_status property for this mem controller from
* OBP. This contains the bank-status for each logical bank.
*/
bank_status_array = (void *)get_prop_val(
status_offset = 0;
/*
* process each logical bank
*/
for (i = 0; i < NUM_MBANKS_PER_MC; i++) {
/*
* Get the bank-status string for this bank
* from the bank_status_array we just retrieved
* from OBP. If the prop was not found, we
* malloc a bank_status and set it to "no_status".
*/
if (bank_status_array) {
bank_status = ((char *)bank_status_array +
/* Move offset to next bank_status string */
} else {
}
/*
* create a bank_node for this bank
* and add it to the list.
*/
/*
* find the segment to which this bank
* belongs. If it doesn't already exist
* then create it. If it exists, add to it.
*/
add_seg_node();
}
}
return (0);
}
static void
{
static int id = 0;
perror("malloc");
exit(1);
}
/* Handle the first bank found */
return;
}
/* find last bank in list */
/* insert this bank into the list */
}
void
display_us3_banks(void)
{
int mcid;
log_printf("\nCannot find any memory bank/segment info.\n");
return;
}
/*
* Interleave factor is determined from the
* lk bits in the Mem Addr Decode register.
*
* The Base Address of the memory segment in which this
* bank belongs is determined from the um abd uk bits
* of the Mem Addr Decode register.
*
* See section 9.1.5 of Cheetah Programmer's reference
* manual.
*/
/* If bank is not valid, set size to zero incase it's garbage */
else
bank_size = 0;
/*
* Keep track of all banks found so we can check later
* that this value matches the total memory in the
* system using the pagesize and number of pages.
*/
/* Find the matching segment for this bank. */
/*
* Find the Dimm size by adding banks 0 + 2 and divide by 4
* and then adding banks 1 + 3 and divide by 4. We divide
* by 2 if one of the logical banks size is zero.
*/
case 0:
/* have bank0_size, need bank2_size */
bank2_size = 0;
while (tmp_bank) {
continue;
}
/* Is next bank on the same mc ? */
if (mcid != SG_PORTID_TO_SAFARI_ID(
break;
}
break;
}
}
if (bank2_size)
else
break;
case 1:
/* have bank1_size, need bank3_size */
bank3_size = 0;
while (tmp_bank) {
continue;
}
/* Is next bank on the same mc ? */
if (mcid != SG_PORTID_TO_SAFARI_ID(
break;
}
break;
}
}
if (bank3_size)
else
break;
case 2:
/* have bank0_size and bank2_size */
if (bank0_size)
else
break;
case 3:
/* have bank1_size and bank3_size */
if (bank1_size)
else
break;
}
continue;
/*
* Call platform specific code for formatting memory
* information.
*/
}
printf("\n");
/*
* Sanity check to ensure that the total amount of system
* memory matches the total number of memory banks that
* we find here. Scream if there is a mis-match.
*/
if (total_bank_size != total_sys_mem) {
"\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)
{
static int id = 0;
return;
/*
* This bank is part of a new segment, so create
* a struct for it and added to the list of segments
*/
perror("malloc");
exit(1);
}
/*
* add to the seg list
*/
}
/*
* add bank into segs bank list. Note we add at the head
*/
}
static memory_seg_t *
{
break;
}
return (cur_seg);
}
/*ARGSUSED0*/
void
{
"\n No print_us3_memory_line() function specified for"
" this platform\n"), 0);
}
int
{
int found_failed_bank = 0;
log_printf("\nCannot find any memory bank/segment info.\n");
return (1);
}
/*
* check to see if the bank is invalid and also
* check if the bank_status is unpopulated. Unpopulated
* means the bank is empty.
*/
if (!system_failed && !found_failed_bank) {
log_printf("\n", 0);
"Failed Field Replaceable Units (FRU) in "
"System:\n"), 0);
log_printf("=========================="
"====================\n", 0);
}
/*
* Call platform specific code for formatting memory
* information.
*/
bank->bank_status);
}
}
if (found_failed_bank)
return (1);
else
return (0);
}
/*ARGSUSED0*/
void
{
"\n No print_us3_failed_memory_line() function specified for"
" this platform\n"), 0);
}