xref: /titanic_52/usr/src/cmd/mdb/sun4u/modules/opl/oplhwd/oplhwd.c (revision b0b09e93d0f18a419f77ec47f70539d245832ee7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/mdb_modapi.h>
29 #include <sys/types.h>
30 #include <sys/dditypes.h>
31 #include <sys/fcode.h>
32 #include <sys/machcpuvar.h>
33 #include <sys/opl.h>
34 #include <sys/opl_cfg.h>
35 
36 static uintptr_t tmptr;
37 
38 /*
39  * print hardware descriptor
40  */
41 
42 /* Verbosity bits */
43 #define	DUMP_HDR	0x00001		/* Header */
44 #define	DUMP_SB_STAT	0x00002		/* System Board Status */
45 #define	DUMP_DINFO	0x00004		/* Domain Information */
46 #define	DUMP_SB_INFO	0x00008		/* System Board Information */
47 #define	DUMP_CMU_CHAN	0x00010		/* CPU/Memory Channel */
48 #define	DUMP_CHIPS	0x00020		/* Phyiscal CPUs */
49 #define	DUMP_MEM	0x00040		/* Memory Information */
50 #define	DUMP_PCI_CH	0x00080		/* PCI Channel */
51 #define	DUMP_MEM_BANKS	0x00100		/* Memory Banks */
52 #define	DUMP_MEM_CHUNKS	0x00200		/* Memory Chunks */
53 #define	DUMP_MEM_DIMMS	0x00400		/* Memory DIMMS */
54 #define	DUMP_MEM_CS	0x00800		/* Memory CS */
55 #define	DUMP_CORES	0x01000		/* CPU Cores Information */
56 #define	DUMP_SCS	0x02000		/* SC Information */
57 #define	DUMP_MISSING	0x10000		/* Miscellenous Information */
58 #define	DUMP_COMP_NAME	0x20000		/* Component Name */
59 
60 
61 /* A nice mix of most of what you want */
62 #define	DUMP_ALL	(DUMP_HDR | DUMP_SB_STAT | DUMP_DINFO |		\
63 			DUMP_SB_INFO | DUMP_CMU_CHAN | DUMP_CHIPS |	\
64 			DUMP_MEM | DUMP_PCI_CH | DUMP_MEM_BANKS |	\
65 			DUMP_CORES | DUMP_SCS)
66 
67 
68 #define	DUMP_VERBOSE	(DUMP_ALL | DUMP_MEM_CHUNKS | DUMP_MEM_CS)
69 #define	DUMP_FULL	(DUMP_VERBOSE | DUMP_MISSING | DUMP_COMP_NAME)
70 
71 
72 #define	MIA(stat)		((stat) == HWD_STAT_MISS)
73 #define	DONT_BOTHER(stat, v)	(MIA(stat) && (v != HWD_STAT_PRESENT))
74 
75 static char *hwd_stat_decode(int stat)
76 {
77 	switch (stat) {
78 	case HWD_STAT_UNKNOWN:
79 		return ("UNKNOWN");
80 	case HWD_STAT_PRESENT:
81 		return ("PRESENT");
82 	case HWD_STAT_MISS:
83 		return ("MISS");
84 	case HWD_STAT_MISCONFIG:
85 		return ("MISCONFIG");
86 	case HWD_STAT_PASS:
87 		return ("PASS");
88 	case HWD_STAT_FAIL:
89 		return ("FAIL_XSCF");
90 	case HWD_STAT_FAIL_OBP:
91 		return ("FAIL_OBP");
92 	case HWD_STAT_FAIL_OS:
93 		return ("FAIL_OS");
94 	default:
95 		return ("?");
96 	}
97 }
98 
99 static void
100 dumpmemhwd(hwd_memory_t *memp, int v, int mv)
101 {
102 	int i, j;
103 
104 	mdb_printf("\nMemory:\tstart\t0x%llx\tsize\t0x%llx\tmirror mode %d\n",
105 	    memp->mem_start_address, memp->mem_size, memp->mem_mirror_mode);
106 	mdb_printf("\tdivision mode\t0x%x\tpiece number\t0x%llx",
107 	    memp->mem_division_mode, memp->mem_piece_number);
108 	mdb_printf("\tcs interleave %d\n", memp->mem_cs_interleave);
109 
110 	/* banks */
111 	for (i = 0; i < HWD_BANKS_PER_CMU; i++) {
112 		if (DONT_BOTHER(memp->mem_banks[i].bank_status, mv)) {
113 			mdb_printf("\tBank %d\tstatus\t0x%x (%s)\n",
114 			    i, memp->mem_banks[i].bank_status,
115 			    hwd_stat_decode(memp->mem_banks[i].bank_status));
116 			continue;
117 		}
118 		mdb_printf("\tBank %d\tstatus\t0x%x (%s)\treg addr\t0x%llx\n",
119 		    i, memp->mem_banks[i].bank_status,
120 		    hwd_stat_decode(memp->mem_banks[i].bank_status),
121 		    memp->mem_banks[i].bank_register_address);
122 		if (v & DUMP_MEM_BANKS) {
123 			mdb_printf("\t\tcs status\t0x%x 0x%x\n",
124 			    memp->mem_banks[i].bank_cs_status[0],
125 			    memp->mem_banks[i].bank_cs_status[1]);
126 			mdb_printf("\t\tMAC OCD\tDIMM OCDs\n");
127 			mdb_printf("\t\t%x\t%x %x  %x %x  %x %x  %x %x\n",
128 			    memp->mem_banks[i].bank_mac_ocd,
129 			    memp->mem_banks[i].bank_dimm_ocd[0][0],
130 			    memp->mem_banks[i].bank_dimm_ocd[0][1],
131 			    memp->mem_banks[i].bank_dimm_ocd[1][0],
132 			    memp->mem_banks[i].bank_dimm_ocd[1][1],
133 			    memp->mem_banks[i].bank_dimm_ocd[2][0],
134 			    memp->mem_banks[i].bank_dimm_ocd[2][1],
135 			    memp->mem_banks[i].bank_dimm_ocd[3][0],
136 			    memp->mem_banks[i].bank_dimm_ocd[3][1]);
137 		}
138 	}
139 	/* chunks */
140 	for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) {
141 		if ((memp->mem_chunks[i].chnk_start_address == 0) && (mv != 1))
142 			continue;
143 		mdb_printf("\tchunk %d\tstart\t0x%llx\tsize\t0x%llx\n",
144 		    i, memp->mem_chunks[i].chnk_start_address,
145 		    memp->mem_chunks[i].chnk_size);
146 	}
147 	/* dimms */
148 	for (i = 0; i < HWD_DIMMS_PER_CMU; i++) {
149 		if (DONT_BOTHER(memp->mem_dimms[i].dimm_status, mv)) {
150 			if (v & DUMP_MEM_DIMMS)
151 				mdb_printf("\tDIMM %d\tstatus\t0x%x (%s)\n",
152 				    i, memp->mem_dimms[i].dimm_status,
153 				    hwd_stat_decode(
154 					    memp->mem_dimms[i].dimm_status));
155 			continue;
156 		}
157 		mdb_printf("\tDIMM %d\tstatus\t0x%x (%s)\tcapacity\t0x%llx\n",
158 		    i, memp->mem_dimms[i].dimm_status,
159 		    hwd_stat_decode(memp->mem_dimms[i].dimm_status),
160 		    memp->mem_dimms[i].dimm_capacity);
161 		mdb_printf("\t\trank\t%x\tavailable capacity\t0x%llx\n",
162 		    memp->mem_dimms[i].dimm_rank,
163 		    memp->mem_dimms[i].dimm_available_capacity);
164 	}
165 	/* cs */
166 	for (i = 0; i < 2; i++) {
167 		if (DONT_BOTHER(memp->mem_cs[i].cs_status, mv)) {
168 			mdb_printf("\tCS %d:\tstatus\t0x%x (%s)\n",
169 			    i, memp->mem_cs[i].cs_status,
170 			    hwd_stat_decode(memp->mem_cs[i].cs_status));
171 			continue;
172 		}
173 		mdb_printf("\tCS %d:\tstatus\t0x%x (%s)\tavailable\t0x%llx\n",
174 		    i, memp->mem_cs[i].cs_status,
175 		    hwd_stat_decode(memp->mem_cs[i].cs_status),
176 		    memp->mem_cs[i].cs_available_capacity);
177 		mdb_printf("\t\tno of dimms\t%x\tdimm capacity\t0x%llx\n",
178 		    memp->mem_cs[i].cs_number_of_dimms,
179 		    memp->mem_cs[i].cs_dimm_capacity);
180 		mdb_printf("\t\tPA <-> MAC conversion\n\t\t");
181 		for (j = 0; j < 20; j++)
182 			mdb_printf("%02x ", memp->mem_cs[i].cs_pa_mac_table[j]);
183 		mdb_printf("\n\t\t");
184 		for (j = 20; j < 40; j++)
185 			mdb_printf("%02x ", memp->mem_cs[i].cs_pa_mac_table[j]);
186 		mdb_printf("\n\t\t");
187 		for (j = 40; j < 60; j++)
188 			mdb_printf("%02x ", memp->mem_cs[i].cs_pa_mac_table[j]);
189 		mdb_printf("\n\t\t");
190 		for (j = 60; j < 64; j++)
191 			mdb_printf("%02x ", memp->mem_cs[i].cs_pa_mac_table[j]);
192 		mdb_printf("\n");
193 	}
194 }
195 
196 /* ARGSUSED */
197 static void
198 dumpchiphwd(hwd_cpu_chip_t *chipp, int ch, int v, int mv)
199 {
200 	int cp, co;
201 	hwd_cpu_t *cpup;
202 	hwd_core_t *corep;
203 
204 	mdb_printf("\nChip %d:\tstatus\t0x%x (%s)\tportid\t%x\n",
205 	    ch, chipp->chip_status, hwd_stat_decode(chipp->chip_status),
206 	    chipp->chip_portid);
207 
208 	if (MIA(chipp->chip_status))
209 		return;
210 
211 	for (co = 0; co < HWD_CORES_PER_CPU_CHIP; co++) {
212 		corep = &chipp->chip_cores[co];
213 
214 		mdb_printf("\tCore %d:\tstatus\t0x%x (%s)\tconfig\t0x%llx\n",
215 		    co, corep->core_status,
216 		    hwd_stat_decode(corep->core_status),
217 		    corep->core_config);
218 
219 		if (MIA(corep->core_status))
220 			continue;
221 
222 		if (v & DUMP_CORES) {
223 			mdb_printf("\t\tfrequency\t0x%llx\tversion\t0x%llx\n",
224 			    corep->core_frequency, corep->core_version);
225 			mdb_printf("\t\t(manuf/impl/mask: %x/%x/%x)\n",
226 			    corep->core_manufacturer,
227 			    corep->core_implementation, corep->core_mask);
228 			mdb_printf("\t\t\tSize\tLinesize\tAssoc\n");
229 			mdb_printf("\t\tL1I$\t%x\t%x\t\t%x\n",
230 			    corep->core_l1_icache_size,
231 			    corep->core_l1_icache_line_size,
232 			    corep->core_l1_icache_associativity);
233 			mdb_printf("\t\tL1D$\t%x\t%x\t\t%x\n",
234 			    corep->core_l1_dcache_size,
235 			    corep->core_l1_dcache_line_size,
236 			    corep->core_l1_dcache_associativity);
237 			mdb_printf("\t\tL2$\t%x\t%x\t\t%x",
238 			    corep->core_l2_cache_size,
239 			    corep->core_l2_cache_line_size,
240 			    corep->core_l2_cache_associativity);
241 			mdb_printf("\tsharing\t%x\n",
242 			    corep->core_l2_cache_sharing);
243 			mdb_printf("\t\tITLB entries\t0x%x\tDTLB entries "
244 				"0x%x\n", corep->core_num_itlb_entries,
245 			    corep->core_num_dtlb_entries);
246 		}
247 
248 		for (cp = 0; cp < HWD_CPUS_PER_CORE; cp++) {
249 			cpup = &corep->core_cpus[cp];
250 			mdb_printf("\t\tCPU %d:\tstatus\t0x%x (%s)\tcpuid"
251 				" = 0x%x\n", cp, cpup->cpu_status,
252 				hwd_stat_decode(cpup->cpu_status),
253 				cpup->cpu_cpuid);
254 			if (v & DUMP_COMP_NAME)
255 				mdb_printf("\t\t\tcomponent name:%s\n",
256 				    cpup->cpu_component_name);
257 		}
258 	}
259 }
260 
261 /* ARGSUSED */
262 static void
263 dumppcihwd(hwd_pci_ch_t *pcip, int ch, int v, int mv)
264 {
265 	int lf;
266 	hwd_leaf_t *leafp;
267 
268 	mdb_printf("\nPCI CH %d:\tstatus\t0x%x (%s)\n",
269 	    ch, pcip->pci_status, hwd_stat_decode(pcip->pci_status));
270 
271 	for (lf = 0; lf < HWD_LEAVES_PER_PCI_CHANNEL; lf++) {
272 		leafp = &pcip->pci_leaf[lf];
273 
274 		if (DONT_BOTHER(leafp->leaf_status, mv)) {
275 			mdb_printf("\tleaf %d:\tstatus\t0x%x (%s)\n",
276 			    lf, leafp->leaf_status,
277 			    hwd_stat_decode(leafp->leaf_status));
278 			continue;
279 		}
280 		mdb_printf("\tleaf %d:\tstatus\t0x%x (%s)\tportid 0x%x",
281 		    lf, leafp->leaf_status,
282 		    hwd_stat_decode(leafp->leaf_status), leafp->leaf_port_id);
283 		mdb_printf("\ttype0x%x\n)",
284 		    leafp->leaf_slot_type);
285 		mdb_printf("\t\t\tOffset\t\tSize\n");
286 		mdb_printf("\t\tcfgio\t0x%llx\t0x%llx\t\t%x\n",
287 		    leafp->leaf_cfgio_offset,
288 		    leafp->leaf_cfgio_size);
289 		mdb_printf("\t\tmem32\t0x%llx\t0x%llx\t\t%x\n",
290 		    leafp->leaf_mem32_offset,
291 		    leafp->leaf_mem32_size);
292 		mdb_printf("\t\tmem64\t0x%llx\t0x%llx\t\t%x\n",
293 		    leafp->leaf_mem64_offset,
294 		    leafp->leaf_mem64_size);
295 	}
296 }
297 
298 /* ARGSUSED */
299 static void
300 dumpahwd(int bd, int v)
301 {
302 	opl_board_cfg_t		boardcfg;
303 	hwd_header_t		hwd_hdr;
304 	hwd_sb_status_t		hwd_sb_status;
305 	hwd_domain_info_t	hwd_dinfo;
306 	hwd_sb_t		hwd_sb;
307 	caddr_t			statusp, dinfop, sbp = NULL;
308 
309 	/* A flag for whether or not to dump stuff that is missing */
310 	int mv = 0;
311 
312 	if (v & DUMP_MISSING)
313 		mv = 1;
314 
315 	bzero(&boardcfg, sizeof (opl_board_cfg_t));
316 	bzero(&hwd_hdr, sizeof (hwd_header_t));
317 	bzero(&hwd_sb_status, sizeof (hwd_sb_status_t));
318 	bzero(&hwd_dinfo, sizeof (hwd_domain_info_t));
319 	bzero(&hwd_sb, sizeof (hwd_sb_t));
320 
321 
322 	if (mdb_vread(&boardcfg, sizeof (opl_board_cfg_t),
323 		tmptr + (bd * sizeof (opl_board_cfg_t))) == -1) {
324 		mdb_warn("failed to read opl_board_cfg at %p",
325 			(tmptr + (bd * sizeof (opl_board_cfg_t))));
326 			return;
327 	}
328 
329 	if (boardcfg.cfg_hwd == NULL) {
330 		mdb_printf("Board %d has no HWD info\n", bd);
331 		return;
332 	}
333 
334 	mdb_printf("Board %d:\thwd pointer\t%8llx\n", bd, boardcfg.cfg_hwd);
335 
336 	/* We always need the header, for offsets */
337 	if (mdb_vread(&hwd_hdr, sizeof (hwd_header_t),
338 			(uintptr_t)boardcfg.cfg_hwd) == -1) {
339 		mdb_warn("failed to read hwd_header_t at %p\n",
340 				boardcfg.cfg_hwd);
341 		return;
342 	}
343 
344 	/* Figure out the inside pointers, in case we need them... */
345 	statusp = (caddr_t)boardcfg.cfg_hwd + hwd_hdr.hdr_sb_status_offset;
346 	dinfop = (caddr_t)boardcfg.cfg_hwd + hwd_hdr.hdr_domain_info_offset;
347 	sbp = (caddr_t)boardcfg.cfg_hwd + hwd_hdr.hdr_sb_info_offset;
348 
349 	/* The sb data is what we will surely be dumping */
350 	if (mdb_vread(&hwd_sb, sizeof (hwd_sb_t), (uintptr_t)sbp) == -1) {
351 		mdb_warn("failed to read hwd_sb_t at %p\n", sbp);
352 		return;
353 	}
354 
355 	if (v & DUMP_HDR) {
356 		/* Print the interesting stuff from the header */
357 		mdb_printf("\t\tversion\t%x.%x\tDID\t%x\tmagic\t0x%x\n\n",
358 		    hwd_hdr.hdr_version.major, hwd_hdr.hdr_version.minor,
359 		    hwd_hdr.hdr_domain_id, hwd_hdr.hdr_magic);
360 		mdb_printf("\tstatus offset = 0x%x\t(addr=%llx)\n",
361 		    hwd_hdr.hdr_sb_status_offset, statusp);
362 		mdb_printf("\tdomain offset = 0x%x\t(addr=%llx)\n",
363 		    hwd_hdr.hdr_domain_info_offset, dinfop);
364 		mdb_printf("\tboard  offset = 0x%x\t(addr=%llx)\n",
365 		    hwd_hdr.hdr_sb_info_offset, sbp);
366 	}
367 
368 	if (v & DUMP_SB_STAT) {
369 		int i;
370 		if (mdb_vread(&hwd_sb_status, sizeof (hwd_sb_status_t),
371 		    (uintptr_t)statusp) == -1) {
372 			mdb_warn("failed to read hwd_sb_status_t at %p\n",
373 					statusp);
374 			return;
375 		}
376 		mdb_printf("\nSTATUS:\tBoard\tStatus\n");
377 		for (i = 0; i < HWD_SBS_PER_DOMAIN; i++) {
378 			if (DONT_BOTHER(hwd_sb_status.sb_status[i], mv))
379 				continue;
380 			mdb_printf("\t%d\t0x%x (%s)\n", i,
381 			    hwd_sb_status.sb_status[i],
382 			    hwd_stat_decode(hwd_sb_status.sb_status[i]));
383 		}
384 	}
385 
386 	/* Domain Info */
387 	if (v & DUMP_DINFO) {
388 		if (mdb_vread(&hwd_dinfo, sizeof (hwd_domain_info_t),
389 		    (uintptr_t)dinfop) == -1) {
390 			mdb_warn("failed to read hwd_domain_info_t at %p\n",
391 				dinfop);
392 			return;
393 		}
394 		mdb_printf("\nDomain info:\tReset reason\t0x%x",
395 		    hwd_dinfo.dinf_reset_factor);
396 		mdb_printf("\tHost ID 0x%x\n", hwd_dinfo.dinf_host_id);
397 		mdb_printf("\tSystem freq\t0x%llx\tStick freq\t0x%llx\n",
398 		    hwd_dinfo.dinf_system_frequency,
399 		    hwd_dinfo.dinf_stick_frequency);
400 		mdb_printf("\tSCF timeout \t0x%x\tModel info\t%x",
401 		    hwd_dinfo.dinf_scf_command_timeout,
402 		    hwd_dinfo.dinf_model_info);
403 		if (hwd_dinfo.dinf_dr_status == 0)
404 			mdb_printf("\tDR capable\n");
405 		else
406 			mdb_printf("\tNOT DR capable (%x)\n",
407 			    hwd_dinfo.dinf_dr_status);
408 		mdb_printf("\tMAC address\t%02x.%02x.%02x.%02x.%02x.%02x",
409 		    hwd_dinfo.dinf_mac_address[0],
410 		    hwd_dinfo.dinf_mac_address[1],
411 		    hwd_dinfo.dinf_mac_address[2],
412 		    hwd_dinfo.dinf_mac_address[3],
413 		    hwd_dinfo.dinf_mac_address[4],
414 		    hwd_dinfo.dinf_mac_address[5]);
415 		mdb_printf("\tcpu_start_time\t0x%llx\n",
416 		    hwd_dinfo.dinf_cpu_start_time);
417 		mdb_printf("\tcfg policy\t%x\tdiag lvl\t%x\tboot mode\t%x\n",
418 		    hwd_dinfo.dinf_config_policy, hwd_dinfo.dinf_diag_level,
419 		    hwd_dinfo.dinf_boot_mode);
420 		mdb_printf("\tBanner name\t%s\n",
421 		    hwd_dinfo.dinf_banner_name);
422 		mdb_printf("\tPlatform token\t%s\n",
423 		    hwd_dinfo.dinf_platform_token);
424 		mdb_printf("\tFloating bd bitmap\t%04x\n",
425 		    hwd_dinfo.dinf_floating_board_bitmap);
426 		mdb_printf("\tChassis Serial#\t%s\n",
427 		    hwd_dinfo.dinf_chassis_sn);
428 		mdb_printf("\tBrand Control\t%d\n",
429 		    hwd_dinfo.dinf_brand_control);
430 
431 	}
432 
433 	/* SB info */
434 	if (v & DUMP_SB_INFO) {
435 		mdb_printf("\nBoard:\tstatus =0x%x (%s)\tmode =0x%x (%s)\
436 		    \tPSB =0x%x\n", hwd_sb.sb_status,
437 		    hwd_stat_decode(hwd_sb.sb_status),
438 		    hwd_sb.sb_mode, (hwd_sb.sb_mode == 0 ? "PSB" : "XSB"),
439 		    hwd_sb.sb_psb_number);
440 	}
441 
442 	/* CMU Chan info */
443 	if (v & DUMP_CMU_CHAN) {
444 		hwd_cmu_chan_t *cmup;
445 		cmup = &hwd_sb.sb_cmu.cmu_ch;
446 
447 		mdb_printf("\nCMU CH: status\t0x%x (%s)\tportid=0x%x"
448 				" LSB = 0x%x\n",
449 		    cmup->chan_status, hwd_stat_decode(cmup->chan_status),
450 		    cmup->chan_portid, ((cmup->chan_portid) >> 4));
451 
452 		if (v & DUMP_COMP_NAME)
453 			mdb_printf("\tcomponent name:%s\n",
454 			    cmup->chan_component_name);
455 
456 		/* scf_interface */
457 		mdb_printf("\tscf:\tstatus\t0x%x (%s)\n",
458 		    cmup->chan_scf_interface.scf_status,
459 		    hwd_stat_decode(cmup->chan_scf_interface.scf_status));
460 		if (v & DUMP_COMP_NAME)
461 			mdb_printf("\t\tcomponent name:%s\n",
462 			    cmup->chan_scf_interface.scf_component_name);
463 
464 		/* serial */
465 		mdb_printf("\tserial:\tstatus\t0x%x (%s)\n",
466 		    cmup->chan_serial.tty_status,
467 		    hwd_stat_decode(cmup->chan_serial.tty_status));
468 		if (v & DUMP_COMP_NAME)
469 			mdb_printf("\t\tcomponent name:%s\n",
470 			    cmup->chan_serial.tty_component_name);
471 
472 		/* fmem */
473 		mdb_printf("\tfmem[0]\tstatus\t0x%x (%s)",
474 		    cmup->chan_fmem[0].fmem_status,
475 		    hwd_stat_decode(cmup->chan_fmem[0].fmem_status));
476 		mdb_printf("\tused %x\tversion %x.%x.%x\n",
477 		    cmup->chan_fmem[0].fmem_used,
478 		    cmup->chan_fmem[0].fmem_version.fver_major,
479 		    cmup->chan_fmem[0].fmem_version.fver_minor,
480 		    cmup->chan_fmem[0].fmem_version.fver_local);
481 		if (v & DUMP_COMP_NAME)
482 			mdb_printf("\t\tcomponent name:%s\n",
483 			    cmup->chan_fmem[0].fmem_component_name);
484 		mdb_printf("\tfmem[1]\tstatus\t0x%x (%s)",
485 		    cmup->chan_fmem[1].fmem_status,
486 		    hwd_stat_decode(cmup->chan_fmem[1].fmem_status));
487 		mdb_printf("\tused %x\tversion %x.%x.%x\n",
488 		    cmup->chan_fmem[1].fmem_used,
489 		    cmup->chan_fmem[1].fmem_version.fver_major,
490 		    cmup->chan_fmem[1].fmem_version.fver_minor,
491 		    cmup->chan_fmem[1].fmem_version.fver_local);
492 		if (v & DUMP_COMP_NAME)
493 			mdb_printf("\t\tcomponent name:%s\n",
494 			    cmup->chan_fmem[1].fmem_component_name);
495 
496 	}
497 
498 	/* CMU SC info */
499 	if (v & DUMP_SCS) {
500 		hwd_sc_t *scp;
501 		int sc;
502 
503 		for (sc = 0; sc < HWD_SCS_PER_CMU; sc++) {
504 
505 			scp = &hwd_sb.sb_cmu.cmu_scs[sc];
506 
507 			if (DONT_BOTHER(scp->sc_status, mv))
508 			    mdb_printf("\nSC %d:\tstatus\t0x%x (%s)\n",
509 				sc, scp->sc_status,
510 				hwd_stat_decode(scp->sc_status));
511 			else {
512 			    mdb_printf("\nSC %d:\tstatus\t0x%x (%s)\t",
513 				sc, scp->sc_status,
514 				hwd_stat_decode(scp->sc_status));
515 			    mdb_printf("register addr\t0x%llx\n",
516 				scp->sc_register_address);
517 			}
518 		}
519 
520 	}
521 
522 	if (v & DUMP_MEM)
523 		dumpmemhwd(&hwd_sb.sb_cmu.cmu_memory, v, mv);
524 
525 	if (v & DUMP_CHIPS) {
526 		int ch;
527 		for (ch = 0; ch < HWD_CPU_CHIPS_PER_CMU; ch++) {
528 			if (MIA(hwd_sb.sb_cmu.cmu_cpu_chips[ch].chip_status)) {
529 				mdb_printf("\nChip %d: status\t0x%x (%s)\n",
530 				    ch,
531 				    hwd_sb.sb_cmu.cmu_cpu_chips[ch].chip_status,
532 				    "MISS");
533 				continue;
534 			}
535 			dumpchiphwd(&hwd_sb.sb_cmu.cmu_cpu_chips[ch], ch, v,
536 			    mv);
537 		}
538 	}
539 
540 	if (v & DUMP_PCI_CH) {
541 		int ch;
542 		for (ch = 0; ch < HWD_CPU_CHIPS_PER_CMU; ch++) {
543 			if (MIA(hwd_sb.sb_pci_ch[ch].pci_status)) {
544 				mdb_printf("\nPCI CH %d:\tstatus\t0x%x (%s)\n",
545 				    ch, hwd_sb.sb_pci_ch[ch].pci_status,
546 				    "MISS");
547 				continue;
548 			}
549 			dumppcihwd(&hwd_sb.sb_pci_ch[ch], ch, v, mv);
550 		}
551 	}
552 }
553 
554 /*
555  * oplhwd dcmd - Print out the per-board HWD, nicely formatted.
556  */
557 /*ARGSUSED*/
558 static int
559 oplhwd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
560 {
561 	int		bdi;
562 	uint64_t	v_mode = DUMP_HDR;
563 	uint_t		obits = 0;
564 	GElf_Sym	tmsym;
565 	uint64_t	bdo;
566 
567 	/*
568 	 * Either use the board number, or get an arg for it, or
569 	 * show all of them.
570 	 */
571 
572 	if (flags & DCMD_ADDRSPEC) {
573 		bdi = addr;
574 	} else {
575 		bdi = -1;
576 	}
577 
578 	bdo = bdi;
579 	if (mdb_getopts(argc, argv,
580 	    'a', MDB_OPT_SETBITS, DUMP_FULL, &obits,	 /* All possible info */
581 	    'b', MDB_OPT_UINT64, &bdo,			 /* board number */
582 	    'd', MDB_OPT_SETBITS, DUMP_DINFO, &obits,	 /* domain info */
583 	    's', MDB_OPT_SETBITS, DUMP_SB_STAT, &obits,	 /* SB status */
584 	    'i', MDB_OPT_SETBITS, DUMP_SB_INFO, &obits,	 /* SB info */
585 	    'c', MDB_OPT_SETBITS, DUMP_CMU_CHAN, &obits, /* CMU chan  */
586 	    'h', MDB_OPT_SETBITS, DUMP_CHIPS, &obits,	 /* chips */
587 	    'm', MDB_OPT_SETBITS, DUMP_MEM, &obits,	 /* memory */
588 	    'p', MDB_OPT_SETBITS, DUMP_PCI_CH, &obits,	 /* PCI chans */
589 	    'k', MDB_OPT_SETBITS, DUMP_MEM_BANKS, &obits, /* banks */
590 	    'o', MDB_OPT_SETBITS, DUMP_CORES, &obits,	  /* core details */
591 	    'r', MDB_OPT_SETBITS, DUMP_SCS, &obits,	  /* SC info */
592 	    'C', MDB_OPT_SETBITS, DUMP_COMP_NAME, &obits,  /* SC info */
593 	    'v', MDB_OPT_SETBITS, DUMP_VERBOSE, &obits,	/* all of the above */
594 	    NULL) != argc)
595 		return (DCMD_USAGE);
596 	bdi = bdo;
597 	v_mode |= obits;
598 
599 	if (mdb_lookup_by_obj("opl_cfg", "opl_boards", &tmsym) == -1) {
600 		mdb_warn("unable to reference opl_boards\n");
601 		return (DCMD_ERR);
602 	}
603 
604 	tmptr = (uintptr_t)tmsym.st_value;
605 	mdb_printf("Board %d:\tboardcfg \t%8llx\n", 0, tmptr);
606 
607 	if (bdi < 0) {
608 		/* get active boards */
609 		for (bdi = 0; bdi < OPL_MAX_BOARDS; bdi++)
610 		dumpahwd(bdi, v_mode);
611 	} else {
612 		dumpahwd(bdi, v_mode);
613 	}
614 	return (DCMD_OK);
615 }
616 
617 /*
618  * ::oplhwd help
619  */
620 static void
621 oplhwd_help(void)
622 {
623 	mdb_printf("oplhwd will dump HWD only for a particular board"
624 		" on which,");
625 	mdb_printf("an earlier DR operation has been executed.\n");
626 	mdb_printf("-b NUM \tlist oplhwd entry for a board\n"
627 		"-s \t\tlist oplhwd entry with SB status\n"
628 		"-d \t\tlist oplhwd entry with Domain info.\n"
629 		"-i \t\tlist oplhwd entry with SB info.\n"
630 		"-h \t\tlist oplhwd entry with Chips details\n"
631 		"-o \t\tlist oplhwd entry with Core details\n"
632 		"-m \t\tlist oplhwd entry with Memory info.\n"
633 		"-k \t\tlist oplhwd entry with Memory Bank info.\n"
634 		"-r \t\tlist oplhwd entry with SC info.\n"
635 		"-c \t\tlist oplhwd entry with CMU channels\n"
636 		"-p \t\tlist oplhwd entry with PCI channels\n"
637 		"-a \t\tlist oplhwd entry with all possible info.\n"
638 		"-C \t\tlist oplhwd entry with component names\n"
639 		"-v \t\tlist oplhwd entry in verbose mode\n");
640 }
641 
642 /*
643  * MDB module linkage information:
644  *
645  * We declare a list of structures describing our dcmds, and a function
646  * named _mdb_init to return a pointer to our module information.
647  */
648 
649 static const mdb_dcmd_t dcmds[] = {
650 	{ "oplhwd", "?[ -b NUM ] [ -sdihomkrcp ] [ -a ] [ -C ] [ -v ]",
651 	"dump hardware descriptor for SUNW,SPARC-Enterprise",
652 	oplhwd, oplhwd_help },
653 	{ NULL }
654 };
655 
656 static const mdb_modinfo_t modinfo = {
657 	MDB_API_VERSION, dcmds, NULL
658 };
659 
660 const mdb_modinfo_t *
661 _mdb_init(void)
662 {
663 	return (&modinfo);
664 }
665