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
display_memorysize(Sys_tree * tree,struct system_kstat_data * kstats,struct grp_info * grps,struct mem_total * memory_total)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
display_memoryconf(Sys_tree * tree,struct grp_info * grps)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
get_us3_mem_regs(Board_node * bnode)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
add_bank_node(uint64_t mc_decode,int portid,char * bank_status)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
display_us3_banks(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
add_seg_node(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 *
match_seg(uint64_t base)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
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)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
display_us3_failed_banks(int system_failed)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
print_us3_failed_memory_line(int portid,int bank_id,char * bank_status)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