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