1*03831d35Sstevel /* 2*03831d35Sstevel * CDDL HEADER START 3*03831d35Sstevel * 4*03831d35Sstevel * The contents of this file are subject to the terms of the 5*03831d35Sstevel * Common Development and Distribution License, Version 1.0 only 6*03831d35Sstevel * (the "License"). You may not use this file except in compliance 7*03831d35Sstevel * with the License. 8*03831d35Sstevel * 9*03831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*03831d35Sstevel * or http://www.opensolaris.org/os/licensing. 11*03831d35Sstevel * See the License for the specific language governing permissions 12*03831d35Sstevel * and limitations under the License. 13*03831d35Sstevel * 14*03831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 15*03831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*03831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 17*03831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 18*03831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 19*03831d35Sstevel * 20*03831d35Sstevel * CDDL HEADER END 21*03831d35Sstevel */ 22*03831d35Sstevel /* 23*03831d35Sstevel * Copyright (c) 1999-2001 by Sun Microsystems, Inc. 24*03831d35Sstevel * All rights reserved. 25*03831d35Sstevel */ 26*03831d35Sstevel 27*03831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*03831d35Sstevel 29*03831d35Sstevel #include <stdio.h> 30*03831d35Sstevel #include <stdlib.h> 31*03831d35Sstevel #include <unistd.h> 32*03831d35Sstevel #include <ctype.h> 33*03831d35Sstevel #include <string.h> 34*03831d35Sstevel #include <kvm.h> 35*03831d35Sstevel #include <varargs.h> 36*03831d35Sstevel #include <errno.h> 37*03831d35Sstevel #include <time.h> 38*03831d35Sstevel #include <dirent.h> 39*03831d35Sstevel #include <fcntl.h> 40*03831d35Sstevel #include <sys/param.h> 41*03831d35Sstevel #include <sys/stat.h> 42*03831d35Sstevel #include <sys/types.h> 43*03831d35Sstevel #include <sys/utsname.h> 44*03831d35Sstevel #include <sys/openpromio.h> 45*03831d35Sstevel #include <kstat.h> 46*03831d35Sstevel #include <libintl.h> 47*03831d35Sstevel #include <syslog.h> 48*03831d35Sstevel #include <sys/dkio.h> 49*03831d35Sstevel #include <sys/sbd_ioctl.h> 50*03831d35Sstevel #include <sys/sbdp_mem.h> 51*03831d35Sstevel #include <sys/serengeti.h> 52*03831d35Sstevel #include <sys/mc.h> 53*03831d35Sstevel #include "pdevinfo.h" 54*03831d35Sstevel #include "display.h" 55*03831d35Sstevel #include "pdevinfo_sun4u.h" 56*03831d35Sstevel #include "display_sun4u.h" 57*03831d35Sstevel #include "libprtdiag.h" 58*03831d35Sstevel 59*03831d35Sstevel #if !defined(TEXT_DOMAIN) 60*03831d35Sstevel #define TEXT_DOMAIN "SYS_TEST" 61*03831d35Sstevel #endif 62*03831d35Sstevel 63*03831d35Sstevel #define KBYTE 1024 64*03831d35Sstevel #define MBYTE (KBYTE * KBYTE) 65*03831d35Sstevel 66*03831d35Sstevel #define MEM_UK_SIZE_MASK 0x3FF 67*03831d35Sstevel 68*03831d35Sstevel /* 69*03831d35Sstevel * Global variables. 70*03831d35Sstevel */ 71*03831d35Sstevel static memory_bank_t *bank_head; 72*03831d35Sstevel static memory_bank_t *bank_tail; 73*03831d35Sstevel static memory_seg_t *seg_head; 74*03831d35Sstevel 75*03831d35Sstevel /* 76*03831d35Sstevel * Local functions. 77*03831d35Sstevel */ 78*03831d35Sstevel static void add_bank_node(uint64_t mc_decode, int portid, char *bank_status); 79*03831d35Sstevel static void add_seg_node(void); 80*03831d35Sstevel static memory_seg_t *match_seg(uint64_t); 81*03831d35Sstevel 82*03831d35Sstevel 83*03831d35Sstevel /* 84*03831d35Sstevel * Used for US-I and US-II systems 85*03831d35Sstevel */ 86*03831d35Sstevel /*ARGSUSED0*/ 87*03831d35Sstevel void 88*03831d35Sstevel display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats, 89*03831d35Sstevel struct grp_info *grps, struct mem_total *memory_total) 90*03831d35Sstevel { 91*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, "Memory size: "), 0); 92*03831d35Sstevel 93*03831d35Sstevel if (sysconf(_SC_PAGESIZE) == -1 || sysconf(_SC_PHYS_PAGES) == -1) 94*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, "unable to determine\n"), 0); 95*03831d35Sstevel else { 96*03831d35Sstevel uint64_t mem_size; 97*03831d35Sstevel 98*03831d35Sstevel mem_size = 99*03831d35Sstevel (uint64_t)sysconf(_SC_PAGESIZE) * \ 100*03831d35Sstevel (uint64_t)sysconf(_SC_PHYS_PAGES); 101*03831d35Sstevel 102*03831d35Sstevel if (mem_size >= MBYTE) 103*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, "%d Megabytes\n"), 104*03831d35Sstevel (int)((mem_size+MBYTE-1) / MBYTE), 0); 105*03831d35Sstevel else 106*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, "%d Kilobytes\n"), 107*03831d35Sstevel (int)((mem_size+KBYTE-1) / KBYTE), 0); 108*03831d35Sstevel } 109*03831d35Sstevel } 110*03831d35Sstevel 111*03831d35Sstevel /*ARGSUSED0*/ 112*03831d35Sstevel void 113*03831d35Sstevel display_memoryconf(Sys_tree *tree, struct grp_info *grps) 114*03831d35Sstevel { 115*03831d35Sstevel /* 116*03831d35Sstevel * This function is intentionally blank 117*03831d35Sstevel */ 118*03831d35Sstevel } 119*03831d35Sstevel 120*03831d35Sstevel /* 121*03831d35Sstevel * The following functions are for use by any US-III based systems. 122*03831d35Sstevel * All they need to do is to call get_us3_mem_regs() 123*03831d35Sstevel * and then display_us3_banks(). Each platform then needs to decide how 124*03831d35Sstevel * to format this data by over-riding the generic function 125*03831d35Sstevel * print_us3_memory_line(). 126*03831d35Sstevel */ 127*03831d35Sstevel int 128*03831d35Sstevel get_us3_mem_regs(Board_node *bnode) 129*03831d35Sstevel { 130*03831d35Sstevel Prom_node *pnode; 131*03831d35Sstevel int portid; 132*03831d35Sstevel uint64_t *ma_reg_arr; 133*03831d35Sstevel uint64_t madr[NUM_MBANKS_PER_MC]; 134*03831d35Sstevel void *bank_status_array; 135*03831d35Sstevel char *bank_status; 136*03831d35Sstevel int i, status_offset; 137*03831d35Sstevel 138*03831d35Sstevel for (pnode = dev_find_node(bnode->nodes, "memory-controller"); 139*03831d35Sstevel pnode != NULL; 140*03831d35Sstevel pnode = dev_next_node(pnode, "memory-controller")) { 141*03831d35Sstevel 142*03831d35Sstevel /* Get portid of this mc from libdevinfo. */ 143*03831d35Sstevel portid = (*(int *)get_prop_val(find_prop(pnode, "portid"))); 144*03831d35Sstevel 145*03831d35Sstevel /* read the logical_bank_ma_regs property for this mc node. */ 146*03831d35Sstevel ma_reg_arr = (uint64_t *)get_prop_val( 147*03831d35Sstevel find_prop(pnode, MEM_CFG_PROP_NAME)); 148*03831d35Sstevel 149*03831d35Sstevel /* 150*03831d35Sstevel * There are situations where a memory-controller node 151*03831d35Sstevel * will not have the logical_bank_ma_regs property and 152*03831d35Sstevel * we need to allow for these cases. They include: 153*03831d35Sstevel * - Excalibur/Littleneck systems that only 154*03831d35Sstevel * support memory on one of their CPUs. 155*03831d35Sstevel * - Systems that support DR where a cpu board 156*03831d35Sstevel * can be unconfigured but still connected. 157*03831d35Sstevel * It is up to the caller of this function to ensure 158*03831d35Sstevel * that the bank_head and seg_head pointers are not 159*03831d35Sstevel * NULL after processing all memory-controllers in the 160*03831d35Sstevel * system. This would indicate a situation where no 161*03831d35Sstevel * memory-controllers in the system have a logical_bank_ma_regs 162*03831d35Sstevel * property which should never happen. 163*03831d35Sstevel */ 164*03831d35Sstevel if (ma_reg_arr == NULL) 165*03831d35Sstevel continue; 166*03831d35Sstevel 167*03831d35Sstevel /* 168*03831d35Sstevel * The first NUM_MBANKS_PER_MC of uint64_t's in the 169*03831d35Sstevel * logical_bank_ma_regs property are the madr values. 170*03831d35Sstevel */ 171*03831d35Sstevel for (i = 0; i < NUM_MBANKS_PER_MC; i++) { 172*03831d35Sstevel madr[i] = *ma_reg_arr++; 173*03831d35Sstevel } 174*03831d35Sstevel 175*03831d35Sstevel /* 176*03831d35Sstevel * Get the bank_status property for this mem controller from 177*03831d35Sstevel * OBP. This contains the bank-status for each logical bank. 178*03831d35Sstevel */ 179*03831d35Sstevel bank_status_array = (void *)get_prop_val( 180*03831d35Sstevel find_prop(pnode, "bank-status")); 181*03831d35Sstevel status_offset = 0; 182*03831d35Sstevel 183*03831d35Sstevel /* 184*03831d35Sstevel * process each logical bank 185*03831d35Sstevel */ 186*03831d35Sstevel for (i = 0; i < NUM_MBANKS_PER_MC; i++) { 187*03831d35Sstevel /* 188*03831d35Sstevel * Get the bank-status string for this bank 189*03831d35Sstevel * from the bank_status_array we just retrieved 190*03831d35Sstevel * from OBP. If the prop was not found, we 191*03831d35Sstevel * malloc a bank_status and set it to "no_status". 192*03831d35Sstevel */ 193*03831d35Sstevel if (bank_status_array) { 194*03831d35Sstevel bank_status = ((char *)bank_status_array + 195*03831d35Sstevel status_offset); 196*03831d35Sstevel 197*03831d35Sstevel /* Move offset to next bank_status string */ 198*03831d35Sstevel status_offset += (strlen(bank_status) + 1); 199*03831d35Sstevel } else { 200*03831d35Sstevel bank_status = malloc(strlen("no_status")); 201*03831d35Sstevel strcpy(bank_status, "no_status"); 202*03831d35Sstevel } 203*03831d35Sstevel 204*03831d35Sstevel /* 205*03831d35Sstevel * create a bank_node for this bank 206*03831d35Sstevel * and add it to the list. 207*03831d35Sstevel */ 208*03831d35Sstevel add_bank_node(madr[i], portid, bank_status); 209*03831d35Sstevel 210*03831d35Sstevel /* 211*03831d35Sstevel * find the segment to which this bank 212*03831d35Sstevel * belongs. If it doesn't already exist 213*03831d35Sstevel * then create it. If it exists, add to it. 214*03831d35Sstevel */ 215*03831d35Sstevel add_seg_node(); 216*03831d35Sstevel } 217*03831d35Sstevel } 218*03831d35Sstevel return (0); 219*03831d35Sstevel } 220*03831d35Sstevel 221*03831d35Sstevel static void 222*03831d35Sstevel add_bank_node(uint64_t mc_decode, int portid, char *bank_status) 223*03831d35Sstevel { 224*03831d35Sstevel static int id = 0; 225*03831d35Sstevel memory_bank_t *new, *bank; 226*03831d35Sstevel uint32_t ifactor = MC_INTLV(mc_decode); 227*03831d35Sstevel uint64_t seg_size; 228*03831d35Sstevel 229*03831d35Sstevel if ((new = malloc(sizeof (memory_bank_t))) == NULL) { 230*03831d35Sstevel perror("malloc"); 231*03831d35Sstevel exit(1); 232*03831d35Sstevel } 233*03831d35Sstevel 234*03831d35Sstevel new->portid = portid; 235*03831d35Sstevel new->id = id++; 236*03831d35Sstevel new->valid = (mc_decode >> 63); 237*03831d35Sstevel new->uk = MC_UK(mc_decode); 238*03831d35Sstevel new->um = MC_UM(mc_decode); 239*03831d35Sstevel new->lk = MC_LK(mc_decode); 240*03831d35Sstevel new->lm = MC_LM(mc_decode); 241*03831d35Sstevel 242*03831d35Sstevel seg_size = ((((uint64_t)new->uk & MEM_UK_SIZE_MASK) + 1) << 26); 243*03831d35Sstevel new->bank_size = seg_size / ifactor; 244*03831d35Sstevel new->bank_status = bank_status; 245*03831d35Sstevel 246*03831d35Sstevel new->next = NULL; 247*03831d35Sstevel new->seg_next = NULL; 248*03831d35Sstevel 249*03831d35Sstevel /* Handle the first bank found */ 250*03831d35Sstevel if (bank_head == NULL) { 251*03831d35Sstevel bank_head = new; 252*03831d35Sstevel bank_tail = new; 253*03831d35Sstevel return; 254*03831d35Sstevel } 255*03831d35Sstevel 256*03831d35Sstevel /* find last bank in list */ 257*03831d35Sstevel bank = bank_head; 258*03831d35Sstevel while (bank->next) 259*03831d35Sstevel bank = bank->next; 260*03831d35Sstevel 261*03831d35Sstevel /* insert this bank into the list */ 262*03831d35Sstevel bank->next = new; 263*03831d35Sstevel bank_tail = new; 264*03831d35Sstevel } 265*03831d35Sstevel 266*03831d35Sstevel void 267*03831d35Sstevel display_us3_banks(void) 268*03831d35Sstevel { 269*03831d35Sstevel uint64_t base, bank_size; 270*03831d35Sstevel uint32_t intlv; 271*03831d35Sstevel memory_bank_t *bank, *tmp_bank; 272*03831d35Sstevel memory_seg_t *seg; 273*03831d35Sstevel int mcid; 274*03831d35Sstevel uint64_t dimm_size; 275*03831d35Sstevel uint64_t total_bank_size = 0; 276*03831d35Sstevel uint64_t total_sys_mem; 277*03831d35Sstevel static uint64_t bank0_size, bank1_size, bank2_size, bank3_size; 278*03831d35Sstevel 279*03831d35Sstevel if ((bank_head == NULL) || (seg_head == NULL)) { 280*03831d35Sstevel log_printf("\nCannot find any memory bank/segment info.\n"); 281*03831d35Sstevel return; 282*03831d35Sstevel } 283*03831d35Sstevel 284*03831d35Sstevel for (bank = bank_head; bank; bank = bank->next) { 285*03831d35Sstevel /* 286*03831d35Sstevel * Interleave factor is determined from the 287*03831d35Sstevel * lk bits in the Mem Addr Decode register. 288*03831d35Sstevel * 289*03831d35Sstevel * The Base Address of the memory segment in which this 290*03831d35Sstevel * bank belongs is determined from the um abd uk bits 291*03831d35Sstevel * of the Mem Addr Decode register. 292*03831d35Sstevel * 293*03831d35Sstevel * See section 9.1.5 of Cheetah Programmer's reference 294*03831d35Sstevel * manual. 295*03831d35Sstevel */ 296*03831d35Sstevel intlv = ((bank->lk ^ 0xF) + 1); 297*03831d35Sstevel base = bank->um & ~(bank->uk); 298*03831d35Sstevel 299*03831d35Sstevel mcid = SG_PORTID_TO_SAFARI_ID(bank->portid); 300*03831d35Sstevel 301*03831d35Sstevel /* If bank is not valid, set size to zero incase it's garbage */ 302*03831d35Sstevel if (bank->valid) 303*03831d35Sstevel bank_size = ((bank->bank_size) / MBYTE); 304*03831d35Sstevel else 305*03831d35Sstevel bank_size = 0; 306*03831d35Sstevel 307*03831d35Sstevel /* 308*03831d35Sstevel * Keep track of all banks found so we can check later 309*03831d35Sstevel * that this value matches the total memory in the 310*03831d35Sstevel * system using the pagesize and number of pages. 311*03831d35Sstevel */ 312*03831d35Sstevel total_bank_size += bank_size; 313*03831d35Sstevel 314*03831d35Sstevel /* Find the matching segment for this bank. */ 315*03831d35Sstevel seg = match_seg(base); 316*03831d35Sstevel 317*03831d35Sstevel /* 318*03831d35Sstevel * Find the Dimm size by adding banks 0 + 2 and divide by 4 319*03831d35Sstevel * and then adding banks 1 + 3 and divide by 4. We divide 320*03831d35Sstevel * by 2 if one of the logical banks size is zero. 321*03831d35Sstevel */ 322*03831d35Sstevel switch ((bank->id) % 4) { 323*03831d35Sstevel case 0: 324*03831d35Sstevel /* have bank0_size, need bank2_size */ 325*03831d35Sstevel bank0_size = bank_size; 326*03831d35Sstevel bank2_size = 0; 327*03831d35Sstevel 328*03831d35Sstevel tmp_bank = bank->next; 329*03831d35Sstevel while (tmp_bank) { 330*03831d35Sstevel if (tmp_bank->valid == 0) { 331*03831d35Sstevel tmp_bank = tmp_bank->next; 332*03831d35Sstevel continue; 333*03831d35Sstevel } 334*03831d35Sstevel /* Is next bank on the same mc ? */ 335*03831d35Sstevel if (mcid != SG_PORTID_TO_SAFARI_ID( 336*03831d35Sstevel tmp_bank->portid)) { 337*03831d35Sstevel break; 338*03831d35Sstevel } 339*03831d35Sstevel if ((tmp_bank->id) % 4 == 2) { 340*03831d35Sstevel bank2_size = 341*03831d35Sstevel (tmp_bank->bank_size / MBYTE); 342*03831d35Sstevel break; 343*03831d35Sstevel } 344*03831d35Sstevel tmp_bank = tmp_bank->next; 345*03831d35Sstevel } 346*03831d35Sstevel if (bank2_size) 347*03831d35Sstevel dimm_size = (bank0_size + bank2_size) / 4; 348*03831d35Sstevel else 349*03831d35Sstevel dimm_size = bank0_size / 2; 350*03831d35Sstevel break; 351*03831d35Sstevel case 1: 352*03831d35Sstevel /* have bank1_size, need bank3_size */ 353*03831d35Sstevel bank1_size = bank_size; 354*03831d35Sstevel bank3_size = 0; 355*03831d35Sstevel 356*03831d35Sstevel tmp_bank = bank->next; 357*03831d35Sstevel while (tmp_bank) { 358*03831d35Sstevel if (tmp_bank->valid == 0) { 359*03831d35Sstevel tmp_bank = tmp_bank->next; 360*03831d35Sstevel continue; 361*03831d35Sstevel } 362*03831d35Sstevel /* Is next bank on the same mc ? */ 363*03831d35Sstevel if (mcid != SG_PORTID_TO_SAFARI_ID( 364*03831d35Sstevel tmp_bank->portid)) { 365*03831d35Sstevel break; 366*03831d35Sstevel } 367*03831d35Sstevel if ((tmp_bank->id) % 4 == 3) { 368*03831d35Sstevel bank3_size = 369*03831d35Sstevel (tmp_bank->bank_size / MBYTE); 370*03831d35Sstevel break; 371*03831d35Sstevel } 372*03831d35Sstevel tmp_bank = tmp_bank->next; 373*03831d35Sstevel } 374*03831d35Sstevel if (bank3_size) 375*03831d35Sstevel dimm_size = (bank1_size + bank3_size) / 4; 376*03831d35Sstevel else 377*03831d35Sstevel dimm_size = bank1_size / 2; 378*03831d35Sstevel break; 379*03831d35Sstevel case 2: 380*03831d35Sstevel /* have bank0_size and bank2_size */ 381*03831d35Sstevel bank2_size = bank_size; 382*03831d35Sstevel if (bank0_size) 383*03831d35Sstevel dimm_size = (bank0_size + bank2_size) / 4; 384*03831d35Sstevel else 385*03831d35Sstevel dimm_size = bank2_size / 2; 386*03831d35Sstevel break; 387*03831d35Sstevel case 3: 388*03831d35Sstevel /* have bank1_size and bank3_size */ 389*03831d35Sstevel bank3_size = bank_size; 390*03831d35Sstevel if (bank1_size) 391*03831d35Sstevel dimm_size = (bank1_size + bank3_size) / 4; 392*03831d35Sstevel else 393*03831d35Sstevel dimm_size = bank3_size / 4; 394*03831d35Sstevel break; 395*03831d35Sstevel } 396*03831d35Sstevel 397*03831d35Sstevel if (bank->valid == 0) 398*03831d35Sstevel continue; 399*03831d35Sstevel 400*03831d35Sstevel /* 401*03831d35Sstevel * Call platform specific code for formatting memory 402*03831d35Sstevel * information. 403*03831d35Sstevel */ 404*03831d35Sstevel print_us3_memory_line(bank->portid, bank->id, bank_size, 405*03831d35Sstevel bank->bank_status, dimm_size, intlv, seg->id); 406*03831d35Sstevel } 407*03831d35Sstevel 408*03831d35Sstevel printf("\n"); 409*03831d35Sstevel 410*03831d35Sstevel /* 411*03831d35Sstevel * Sanity check to ensure that the total amount of system 412*03831d35Sstevel * memory matches the total number of memory banks that 413*03831d35Sstevel * we find here. Scream if there is a mis-match. 414*03831d35Sstevel */ 415*03831d35Sstevel total_sys_mem = (((uint64_t)sysconf(_SC_PAGESIZE) * \ 416*03831d35Sstevel (uint64_t)sysconf(_SC_PHYS_PAGES)) / MBYTE); 417*03831d35Sstevel 418*03831d35Sstevel if (total_bank_size != total_sys_mem) { 419*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, 420*03831d35Sstevel "\nError: total bank size [%lldMB] does not match total " 421*03831d35Sstevel "system memory [%lldMB]\n"), total_bank_size, 422*03831d35Sstevel total_sys_mem, 0); 423*03831d35Sstevel } 424*03831d35Sstevel 425*03831d35Sstevel } 426*03831d35Sstevel 427*03831d35Sstevel static void 428*03831d35Sstevel add_seg_node(void) 429*03831d35Sstevel { 430*03831d35Sstevel uint64_t base; 431*03831d35Sstevel memory_seg_t *new; 432*03831d35Sstevel static int id = 0; 433*03831d35Sstevel memory_bank_t *bank = bank_tail; 434*03831d35Sstevel 435*03831d35Sstevel if (bank->valid != 1) 436*03831d35Sstevel return; 437*03831d35Sstevel 438*03831d35Sstevel base = bank->um & ~(bank->uk); 439*03831d35Sstevel 440*03831d35Sstevel if ((new = match_seg(base)) == NULL) { 441*03831d35Sstevel /* 442*03831d35Sstevel * This bank is part of a new segment, so create 443*03831d35Sstevel * a struct for it and added to the list of segments 444*03831d35Sstevel */ 445*03831d35Sstevel if ((new = malloc(sizeof (memory_seg_t))) == NULL) { 446*03831d35Sstevel perror("malloc"); 447*03831d35Sstevel exit(1); 448*03831d35Sstevel } 449*03831d35Sstevel new->id = id++; 450*03831d35Sstevel new->base = base; 451*03831d35Sstevel new->size = (((uint64_t)bank->uk +1) << 26); 452*03831d35Sstevel new->intlv = ((bank->lk ^ 0xF) + 1); 453*03831d35Sstevel 454*03831d35Sstevel /* 455*03831d35Sstevel * add to the seg list 456*03831d35Sstevel */ 457*03831d35Sstevel new->next = seg_head; 458*03831d35Sstevel seg_head = new; 459*03831d35Sstevel } 460*03831d35Sstevel 461*03831d35Sstevel new->nbanks++; 462*03831d35Sstevel /* 463*03831d35Sstevel * add bank into segs bank list. Note we add at the head 464*03831d35Sstevel */ 465*03831d35Sstevel bank->seg_next = new->banks; 466*03831d35Sstevel new->banks = bank; 467*03831d35Sstevel } 468*03831d35Sstevel 469*03831d35Sstevel static memory_seg_t * 470*03831d35Sstevel match_seg(uint64_t base) 471*03831d35Sstevel { 472*03831d35Sstevel memory_seg_t *cur_seg; 473*03831d35Sstevel 474*03831d35Sstevel for (cur_seg = seg_head; cur_seg; cur_seg = cur_seg->next) { 475*03831d35Sstevel if (cur_seg-> base == base) 476*03831d35Sstevel break; 477*03831d35Sstevel } 478*03831d35Sstevel return (cur_seg); 479*03831d35Sstevel } 480*03831d35Sstevel 481*03831d35Sstevel /*ARGSUSED0*/ 482*03831d35Sstevel void 483*03831d35Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 484*03831d35Sstevel char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) 485*03831d35Sstevel { 486*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, 487*03831d35Sstevel "\n No print_us3_memory_line() function specified for" 488*03831d35Sstevel " this platform\n"), 0); 489*03831d35Sstevel } 490*03831d35Sstevel 491*03831d35Sstevel int 492*03831d35Sstevel display_us3_failed_banks(int system_failed) 493*03831d35Sstevel { 494*03831d35Sstevel memory_bank_t *bank; 495*03831d35Sstevel int found_failed_bank = 0; 496*03831d35Sstevel 497*03831d35Sstevel if ((bank_head == NULL) || (seg_head == NULL)) { 498*03831d35Sstevel log_printf("\nCannot find any memory bank/segment info.\n"); 499*03831d35Sstevel return (1); 500*03831d35Sstevel } 501*03831d35Sstevel 502*03831d35Sstevel for (bank = bank_head; bank; bank = bank->next) { 503*03831d35Sstevel /* 504*03831d35Sstevel * check to see if the bank is invalid and also 505*03831d35Sstevel * check if the bank_status is unpopulated. Unpopulated 506*03831d35Sstevel * means the bank is empty. 507*03831d35Sstevel */ 508*03831d35Sstevel 509*03831d35Sstevel if ((bank->valid == 0) && 510*03831d35Sstevel (strcmp(bank->bank_status, "unpopulated"))) { 511*03831d35Sstevel if (!system_failed && !found_failed_bank) { 512*03831d35Sstevel found_failed_bank = TRUE; 513*03831d35Sstevel log_printf("\n", 0); 514*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, 515*03831d35Sstevel "Failed Field Replaceable Units (FRU) in " 516*03831d35Sstevel "System:\n"), 0); 517*03831d35Sstevel log_printf("==========================" 518*03831d35Sstevel "====================\n", 0); 519*03831d35Sstevel } 520*03831d35Sstevel /* 521*03831d35Sstevel * Call platform specific code for formatting memory 522*03831d35Sstevel * information. 523*03831d35Sstevel */ 524*03831d35Sstevel print_us3_failed_memory_line(bank->portid, bank->id, 525*03831d35Sstevel bank->bank_status); 526*03831d35Sstevel } 527*03831d35Sstevel } 528*03831d35Sstevel if (found_failed_bank) 529*03831d35Sstevel return (1); 530*03831d35Sstevel else 531*03831d35Sstevel return (0); 532*03831d35Sstevel } 533*03831d35Sstevel 534*03831d35Sstevel /*ARGSUSED0*/ 535*03831d35Sstevel void 536*03831d35Sstevel print_us3_failed_memory_line(int portid, int bank_id, char *bank_status) 537*03831d35Sstevel { 538*03831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, 539*03831d35Sstevel "\n No print_us3_failed_memory_line() function specified for" 540*03831d35Sstevel " this platform\n"), 0); 541*03831d35Sstevel } 542