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