xref: /onnv-gate/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c (revision 12120:8a783f4db0ad)
110696SDavid.Hollister@Sun.COM /*
210696SDavid.Hollister@Sun.COM  * CDDL HEADER START
310696SDavid.Hollister@Sun.COM  *
410696SDavid.Hollister@Sun.COM  * The contents of this file are subject to the terms of the
510696SDavid.Hollister@Sun.COM  * Common Development and Distribution License (the "License").
610696SDavid.Hollister@Sun.COM  * You may not use this file except in compliance with the License.
710696SDavid.Hollister@Sun.COM  *
810696SDavid.Hollister@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910696SDavid.Hollister@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010696SDavid.Hollister@Sun.COM  * See the License for the specific language governing permissions
1110696SDavid.Hollister@Sun.COM  * and limitations under the License.
1210696SDavid.Hollister@Sun.COM  *
1310696SDavid.Hollister@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410696SDavid.Hollister@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510696SDavid.Hollister@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610696SDavid.Hollister@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710696SDavid.Hollister@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810696SDavid.Hollister@Sun.COM  *
1910696SDavid.Hollister@Sun.COM  * CDDL HEADER END
2010696SDavid.Hollister@Sun.COM  */
2110696SDavid.Hollister@Sun.COM /*
2212060SDavid.Hollister@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2310696SDavid.Hollister@Sun.COM  */
2410696SDavid.Hollister@Sun.COM 
2510696SDavid.Hollister@Sun.COM #include <limits.h>
2610696SDavid.Hollister@Sun.COM #include <sys/mdb_modapi.h>
2711334SReed.Liu@Sun.COM #include <mdb/mdb_ctf.h>
2810696SDavid.Hollister@Sun.COM #include <sys/sysinfo.h>
2911048SDavid.Hollister@Sun.COM #include <sys/byteorder.h>
3011334SReed.Liu@Sun.COM #include <sys/nvpair.h>
3111334SReed.Liu@Sun.COM #include <sys/damap.h>
3210696SDavid.Hollister@Sun.COM #include <sys/scsi/scsi.h>
3310696SDavid.Hollister@Sun.COM #include <sys/scsi/adapters/pmcs/pmcs.h>
3411694SDavid.Hollister@Sun.COM #ifndef _KMDB
3511694SDavid.Hollister@Sun.COM #include <sys/types.h>
3611694SDavid.Hollister@Sun.COM #include <sys/stat.h>
3711694SDavid.Hollister@Sun.COM #include <fcntl.h>
3811694SDavid.Hollister@Sun.COM #include <unistd.h>
3911694SDavid.Hollister@Sun.COM #endif	/* _KMDB */
4010696SDavid.Hollister@Sun.COM 
4111334SReed.Liu@Sun.COM /*
4211334SReed.Liu@Sun.COM  * We need use this to pass the settings when display_iport
4311334SReed.Liu@Sun.COM  */
4411334SReed.Liu@Sun.COM typedef struct per_iport_setting {
4511334SReed.Liu@Sun.COM 	uint_t  pis_damap_info; /* -m: DAM/damap */
4611334SReed.Liu@Sun.COM 	uint_t  pis_dtc_info; /* -d: device tree children: dev_info/path_info */
4711334SReed.Liu@Sun.COM } per_iport_setting_t;
4811334SReed.Liu@Sun.COM 
4912060SDavid.Hollister@Sun.COM /*
5012060SDavid.Hollister@Sun.COM  * This structure is used for sorting work structures by the wserno
5112060SDavid.Hollister@Sun.COM  */
5212060SDavid.Hollister@Sun.COM typedef struct wserno_list {
5312060SDavid.Hollister@Sun.COM 	int serno;
5412060SDavid.Hollister@Sun.COM 	int idx;
5512060SDavid.Hollister@Sun.COM 	struct wserno_list *next;
5612060SDavid.Hollister@Sun.COM 	struct wserno_list *prev;
5712060SDavid.Hollister@Sun.COM } wserno_list_t;
5812060SDavid.Hollister@Sun.COM 
5911334SReed.Liu@Sun.COM #define	MDB_RD(a, b, c)		mdb_vread(a, b, (uintptr_t)c)
6011334SReed.Liu@Sun.COM #define	NOREAD(a, b)		mdb_warn("could not read " #a " at 0x%p", b)
6110696SDavid.Hollister@Sun.COM 
6210696SDavid.Hollister@Sun.COM static pmcs_hw_t ss;
6310696SDavid.Hollister@Sun.COM static pmcs_xscsi_t **targets = NULL;
6410696SDavid.Hollister@Sun.COM static int target_idx;
6510696SDavid.Hollister@Sun.COM 
6610696SDavid.Hollister@Sun.COM static uint32_t	sas_phys, sata_phys, exp_phys, num_expanders, empty_phys;
6710696SDavid.Hollister@Sun.COM 
6810696SDavid.Hollister@Sun.COM static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp);
6910743SDavid.Hollister@Sun.COM static void display_one_work(pmcwork_t *wp, int verbose, int idx);
7010696SDavid.Hollister@Sun.COM 
7110696SDavid.Hollister@Sun.COM static void
7210696SDavid.Hollister@Sun.COM print_sas_address(pmcs_phy_t *phy)
7310696SDavid.Hollister@Sun.COM {
7410696SDavid.Hollister@Sun.COM 	int idx;
7510696SDavid.Hollister@Sun.COM 
7610696SDavid.Hollister@Sun.COM 	for (idx = 0; idx < 8; idx++) {
7710696SDavid.Hollister@Sun.COM 		mdb_printf("%02x", phy->sas_address[idx]);
7810696SDavid.Hollister@Sun.COM 	}
7910696SDavid.Hollister@Sun.COM }
8010696SDavid.Hollister@Sun.COM 
81*12120SDavid.Hollister@Sun.COM static void
82*12120SDavid.Hollister@Sun.COM pmcs_fwtime_to_systime(struct pmcs_hw ss, uint32_t fw_hi, uint32_t fw_lo,
83*12120SDavid.Hollister@Sun.COM     struct timespec *stime)
84*12120SDavid.Hollister@Sun.COM {
85*12120SDavid.Hollister@Sun.COM 	uint64_t fwtime;
86*12120SDavid.Hollister@Sun.COM 	time_t secs;
87*12120SDavid.Hollister@Sun.COM 	long nsecs;
88*12120SDavid.Hollister@Sun.COM 	boolean_t backward_time = B_FALSE;
89*12120SDavid.Hollister@Sun.COM 
90*12120SDavid.Hollister@Sun.COM 	fwtime = ((uint64_t)fw_hi << 32) | fw_lo;
91*12120SDavid.Hollister@Sun.COM 
92*12120SDavid.Hollister@Sun.COM 	/*
93*12120SDavid.Hollister@Sun.COM 	 * If fwtime < ss.fw_timestamp, then we need to adjust the clock
94*12120SDavid.Hollister@Sun.COM 	 * time backwards from ss.sys_timestamp.  Otherwise, the adjustment
95*12120SDavid.Hollister@Sun.COM 	 * goes forward in time
96*12120SDavid.Hollister@Sun.COM 	 */
97*12120SDavid.Hollister@Sun.COM 	if (fwtime >= ss.fw_timestamp) {
98*12120SDavid.Hollister@Sun.COM 		fwtime -= ss.fw_timestamp;
99*12120SDavid.Hollister@Sun.COM 	} else {
100*12120SDavid.Hollister@Sun.COM 		fwtime = ss.fw_timestamp - fwtime;
101*12120SDavid.Hollister@Sun.COM 		backward_time = B_TRUE;
102*12120SDavid.Hollister@Sun.COM 	}
103*12120SDavid.Hollister@Sun.COM 
104*12120SDavid.Hollister@Sun.COM 	secs = ((time_t)fwtime / NSECS_PER_SEC);
105*12120SDavid.Hollister@Sun.COM 	nsecs = ((long)fwtime % NSECS_PER_SEC);
106*12120SDavid.Hollister@Sun.COM 
107*12120SDavid.Hollister@Sun.COM 	stime->tv_sec = ss.sys_timestamp.tv_sec;
108*12120SDavid.Hollister@Sun.COM 	stime->tv_nsec = ss.sys_timestamp.tv_nsec;
109*12120SDavid.Hollister@Sun.COM 
110*12120SDavid.Hollister@Sun.COM 	if (backward_time) {
111*12120SDavid.Hollister@Sun.COM 		if (stime->tv_nsec < nsecs) {
112*12120SDavid.Hollister@Sun.COM 			stime->tv_sec--;
113*12120SDavid.Hollister@Sun.COM 			stime->tv_nsec = stime->tv_nsec + NSECS_PER_SEC - nsecs;
114*12120SDavid.Hollister@Sun.COM 		} else {
115*12120SDavid.Hollister@Sun.COM 			stime->tv_nsec -= nsecs;
116*12120SDavid.Hollister@Sun.COM 		}
117*12120SDavid.Hollister@Sun.COM 		stime->tv_sec -= secs;
118*12120SDavid.Hollister@Sun.COM 	} else {
119*12120SDavid.Hollister@Sun.COM 		if (stime->tv_nsec + nsecs > NSECS_PER_SEC) {
120*12120SDavid.Hollister@Sun.COM 			stime->tv_sec++;
121*12120SDavid.Hollister@Sun.COM 		}
122*12120SDavid.Hollister@Sun.COM 		stime->tv_nsec = (stime->tv_nsec + nsecs) % NSECS_PER_SEC;
123*12120SDavid.Hollister@Sun.COM 		stime->tv_sec += secs;
124*12120SDavid.Hollister@Sun.COM 	}
125*12120SDavid.Hollister@Sun.COM }
126*12120SDavid.Hollister@Sun.COM 
12710696SDavid.Hollister@Sun.COM /*ARGSUSED*/
12810696SDavid.Hollister@Sun.COM static void
12910696SDavid.Hollister@Sun.COM display_ic(struct pmcs_hw m, int verbose)
13010696SDavid.Hollister@Sun.COM {
13110696SDavid.Hollister@Sun.COM 	int msec_per_tick;
13210696SDavid.Hollister@Sun.COM 
13310696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
13410696SDavid.Hollister@Sun.COM 		mdb_warn("can't read msec_per_tick");
13510696SDavid.Hollister@Sun.COM 		msec_per_tick = 0;
13610696SDavid.Hollister@Sun.COM 	}
13710696SDavid.Hollister@Sun.COM 
13810696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
13910696SDavid.Hollister@Sun.COM 	mdb_printf("Interrupt coalescing timer info\n");
14010696SDavid.Hollister@Sun.COM 	mdb_printf("-------------------------------\n");
14110696SDavid.Hollister@Sun.COM 	if (msec_per_tick == 0) {
14210696SDavid.Hollister@Sun.COM 		mdb_printf("Quantum                       : ?? ms\n");
14310696SDavid.Hollister@Sun.COM 	} else {
14410696SDavid.Hollister@Sun.COM 		mdb_printf("Quantum                       : %d ms\n",
14510696SDavid.Hollister@Sun.COM 		    m.io_intr_coal.quantum * msec_per_tick);
14610696SDavid.Hollister@Sun.COM 	}
14710696SDavid.Hollister@Sun.COM 	mdb_printf("Timer enabled                 : ");
14810696SDavid.Hollister@Sun.COM 	if (m.io_intr_coal.timer_on) {
14910696SDavid.Hollister@Sun.COM 		mdb_printf("Yes\n");
15010696SDavid.Hollister@Sun.COM 		mdb_printf("Coalescing timer value        : %d us\n",
15110696SDavid.Hollister@Sun.COM 		    m.io_intr_coal.intr_coal_timer);
15210696SDavid.Hollister@Sun.COM 	} else {
15310696SDavid.Hollister@Sun.COM 		mdb_printf("No\n");
15410696SDavid.Hollister@Sun.COM 	}
15510696SDavid.Hollister@Sun.COM 	mdb_printf("Total nsecs between interrupts: %ld\n",
15610696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.nsecs_between_intrs);
15710696SDavid.Hollister@Sun.COM 	mdb_printf("Time of last I/O interrupt    : %ld\n",
15810696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.last_io_comp);
15910696SDavid.Hollister@Sun.COM 	mdb_printf("Number of I/O interrupts      : %d\n",
16010696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.num_intrs);
16110696SDavid.Hollister@Sun.COM 	mdb_printf("Number of I/O completions     : %d\n",
16210696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.num_io_completions);
16310696SDavid.Hollister@Sun.COM 	mdb_printf("Max I/O completion interrupts : %d\n",
16410696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.max_io_completions);
16510696SDavid.Hollister@Sun.COM 	mdb_printf("Measured ECHO int latency     : %d ns\n",
16610696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.intr_latency);
16710696SDavid.Hollister@Sun.COM 	mdb_printf("Interrupt threshold           : %d\n",
16810696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.intr_threshold);
16910696SDavid.Hollister@Sun.COM }
17010696SDavid.Hollister@Sun.COM 
17110696SDavid.Hollister@Sun.COM /*ARGSUSED*/
17210696SDavid.Hollister@Sun.COM static int
17310696SDavid.Hollister@Sun.COM pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv)
17410696SDavid.Hollister@Sun.COM {
17510696SDavid.Hollister@Sun.COM 	struct pmcs_phy		phy;
17610696SDavid.Hollister@Sun.COM 
17710696SDavid.Hollister@Sun.COM 	if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) !=
17810696SDavid.Hollister@Sun.COM 	    sizeof (struct pmcs_phy)) {
17910696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
18010696SDavid.Hollister@Sun.COM 	}
18110696SDavid.Hollister@Sun.COM 
18210696SDavid.Hollister@Sun.COM 	mdb_printf("%16p %2d\n", addr, phy.phynum);
18310696SDavid.Hollister@Sun.COM 
18410696SDavid.Hollister@Sun.COM 	return (0);
18510696SDavid.Hollister@Sun.COM }
18610696SDavid.Hollister@Sun.COM 
18711334SReed.Liu@Sun.COM static int
18811334SReed.Liu@Sun.COM display_iport_damap(dev_info_t *pdip)
18911334SReed.Liu@Sun.COM {
19011334SReed.Liu@Sun.COM 	int rval = DCMD_ERR;
19111334SReed.Liu@Sun.COM 	struct dev_info dip;
19211334SReed.Liu@Sun.COM 	scsi_hba_tran_t sht;
19311334SReed.Liu@Sun.COM 	mdb_ctf_id_t istm_ctfid; /* impl_scsi_tgtmap_t ctf_id */
19411334SReed.Liu@Sun.COM 	ulong_t tmd_offset = 0; /* tgtmap_dam offset to impl_scsi_tgtmap_t */
19511334SReed.Liu@Sun.COM 	uintptr_t dam0;
19611334SReed.Liu@Sun.COM 	uintptr_t dam1;
19711334SReed.Liu@Sun.COM 
19811334SReed.Liu@Sun.COM 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
19911334SReed.Liu@Sun.COM 	    sizeof (struct dev_info)) {
20011334SReed.Liu@Sun.COM 		return (rval);
20111334SReed.Liu@Sun.COM 	}
20211334SReed.Liu@Sun.COM 
20311334SReed.Liu@Sun.COM 	if (dip.devi_driver_data == NULL) {
20411334SReed.Liu@Sun.COM 		return (rval);
20511334SReed.Liu@Sun.COM 	}
20611334SReed.Liu@Sun.COM 
20711334SReed.Liu@Sun.COM 	if (mdb_vread(&sht, sizeof (scsi_hba_tran_t),
20811334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_driver_data) != sizeof (scsi_hba_tran_t)) {
20911334SReed.Liu@Sun.COM 		return (rval);
21011334SReed.Liu@Sun.COM 	}
21111334SReed.Liu@Sun.COM 
21211334SReed.Liu@Sun.COM 	if (sht.tran_tgtmap == NULL) {
21311334SReed.Liu@Sun.COM 		return (rval);
21411334SReed.Liu@Sun.COM 	}
21511334SReed.Liu@Sun.COM 
21611334SReed.Liu@Sun.COM 	if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid) != 0) {
21711334SReed.Liu@Sun.COM 		return (rval);
21811334SReed.Liu@Sun.COM 	}
21911334SReed.Liu@Sun.COM 
22011334SReed.Liu@Sun.COM 	if (mdb_ctf_offsetof(istm_ctfid, "tgtmap_dam", &tmd_offset) != 0) {
22111334SReed.Liu@Sun.COM 		return (rval);
22211334SReed.Liu@Sun.COM 	}
22311334SReed.Liu@Sun.COM 
22411334SReed.Liu@Sun.COM 	tmd_offset /= NBBY;
22511334SReed.Liu@Sun.COM 	mdb_vread(&dam0, sizeof (dam0),
22611334SReed.Liu@Sun.COM 	    (uintptr_t)(tmd_offset + (char *)sht.tran_tgtmap));
22711334SReed.Liu@Sun.COM 	mdb_vread(&dam1, sizeof (dam1),
22811334SReed.Liu@Sun.COM 	    (uintptr_t)(sizeof (dam0) + tmd_offset + (char *)sht.tran_tgtmap));
22911334SReed.Liu@Sun.COM 
23011334SReed.Liu@Sun.COM 	if (dam0 != NULL) {
23111334SReed.Liu@Sun.COM 		rval = mdb_call_dcmd("damap", dam0, DCMD_ADDRSPEC, 0, NULL);
23211334SReed.Liu@Sun.COM 		mdb_printf("\n");
23311334SReed.Liu@Sun.COM 		if (rval != DCMD_OK) {
23411334SReed.Liu@Sun.COM 			return (rval);
23511334SReed.Liu@Sun.COM 		}
23611334SReed.Liu@Sun.COM 	}
23711334SReed.Liu@Sun.COM 
23811334SReed.Liu@Sun.COM 	if (dam1 != NULL) {
23911334SReed.Liu@Sun.COM 		rval = mdb_call_dcmd("damap", dam1, DCMD_ADDRSPEC, 0, NULL);
24011334SReed.Liu@Sun.COM 		mdb_printf("\n");
24111334SReed.Liu@Sun.COM 	}
24211334SReed.Liu@Sun.COM 
24311334SReed.Liu@Sun.COM 	return (rval);
24411334SReed.Liu@Sun.COM }
24511334SReed.Liu@Sun.COM 
24611334SReed.Liu@Sun.COM /* ARGSUSED */
24711334SReed.Liu@Sun.COM static int
24811334SReed.Liu@Sun.COM display_iport_di_cb(uintptr_t addr, const void *wdata, void *priv)
24911334SReed.Liu@Sun.COM {
25011334SReed.Liu@Sun.COM 	uint_t *idx = (uint_t *)priv;
25111334SReed.Liu@Sun.COM 	struct dev_info dip;
25211334SReed.Liu@Sun.COM 	char devi_name[MAXNAMELEN];
25311334SReed.Liu@Sun.COM 	char devi_addr[MAXNAMELEN];
25411334SReed.Liu@Sun.COM 
25511334SReed.Liu@Sun.COM 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)addr) !=
25611334SReed.Liu@Sun.COM 	    sizeof (struct dev_info)) {
25711334SReed.Liu@Sun.COM 		return (DCMD_ERR);
25811334SReed.Liu@Sun.COM 	}
25911334SReed.Liu@Sun.COM 
26011334SReed.Liu@Sun.COM 	if (mdb_readstr(devi_name, sizeof (devi_name),
26111334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_node_name) == -1) {
26211334SReed.Liu@Sun.COM 		devi_name[0] = '?';
26311334SReed.Liu@Sun.COM 		devi_name[1] = '\0';
26411334SReed.Liu@Sun.COM 	}
26511334SReed.Liu@Sun.COM 
26611334SReed.Liu@Sun.COM 	if (mdb_readstr(devi_addr, sizeof (devi_addr),
26711334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_addr) == -1) {
26811334SReed.Liu@Sun.COM 		devi_addr[0] = '?';
26911334SReed.Liu@Sun.COM 		devi_addr[1] = '\0';
27011334SReed.Liu@Sun.COM 	}
27111334SReed.Liu@Sun.COM 
27211334SReed.Liu@Sun.COM 	mdb_printf("  %3d: @%-21s%10s@\t%p::devinfo -s\n",
27311334SReed.Liu@Sun.COM 	    (*idx)++, devi_addr, devi_name, addr);
27411334SReed.Liu@Sun.COM 	return (DCMD_OK);
27511334SReed.Liu@Sun.COM }
27611334SReed.Liu@Sun.COM 
27711334SReed.Liu@Sun.COM /* ARGSUSED */
27811334SReed.Liu@Sun.COM static int
27911334SReed.Liu@Sun.COM display_iport_pi_cb(uintptr_t addr, const void *wdata, void *priv)
28011334SReed.Liu@Sun.COM {
28111334SReed.Liu@Sun.COM 	uint_t *idx = (uint_t *)priv;
28211334SReed.Liu@Sun.COM 	struct mdi_pathinfo mpi;
28311334SReed.Liu@Sun.COM 	char pi_addr[MAXNAMELEN];
28411334SReed.Liu@Sun.COM 
28511334SReed.Liu@Sun.COM 	if (mdb_vread(&mpi, sizeof (struct mdi_pathinfo), (uintptr_t)addr) !=
28611334SReed.Liu@Sun.COM 	    sizeof (struct mdi_pathinfo)) {
28711334SReed.Liu@Sun.COM 		return (DCMD_ERR);
28811334SReed.Liu@Sun.COM 	}
28911334SReed.Liu@Sun.COM 
29011334SReed.Liu@Sun.COM 	if (mdb_readstr(pi_addr, sizeof (pi_addr),
29111334SReed.Liu@Sun.COM 	    (uintptr_t)mpi.pi_addr) == -1) {
29211334SReed.Liu@Sun.COM 		pi_addr[0] = '?';
29311334SReed.Liu@Sun.COM 		pi_addr[1] = '\0';
29411334SReed.Liu@Sun.COM 	}
29511334SReed.Liu@Sun.COM 
29611334SReed.Liu@Sun.COM 	mdb_printf("  %3d: @%-21s %p::print struct mdi_pathinfo\n",
29711334SReed.Liu@Sun.COM 	    (*idx)++, pi_addr, addr);
29811334SReed.Liu@Sun.COM 	return (DCMD_OK);
29911334SReed.Liu@Sun.COM }
30011334SReed.Liu@Sun.COM 
30111334SReed.Liu@Sun.COM static int
30211334SReed.Liu@Sun.COM display_iport_dtc(dev_info_t *pdip)
30311334SReed.Liu@Sun.COM {
30411334SReed.Liu@Sun.COM 	int rval = DCMD_ERR;
30511334SReed.Liu@Sun.COM 	struct dev_info dip;
30611334SReed.Liu@Sun.COM 	struct mdi_phci phci;
30711334SReed.Liu@Sun.COM 	uint_t didx = 1;
30811334SReed.Liu@Sun.COM 	uint_t pidx = 1;
30911334SReed.Liu@Sun.COM 
31011334SReed.Liu@Sun.COM 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
31111334SReed.Liu@Sun.COM 	    sizeof (struct dev_info)) {
31211334SReed.Liu@Sun.COM 		return (rval);
31311334SReed.Liu@Sun.COM 	}
31411334SReed.Liu@Sun.COM 
31511334SReed.Liu@Sun.COM 	mdb_printf("Device tree children - dev_info:\n");
31611334SReed.Liu@Sun.COM 	if (dip.devi_child == NULL) {
31711334SReed.Liu@Sun.COM 		mdb_printf("\tdevi_child is NULL, no dev_info\n\n");
31811334SReed.Liu@Sun.COM 		goto skip_di;
31911334SReed.Liu@Sun.COM 	}
32011334SReed.Liu@Sun.COM 
32111334SReed.Liu@Sun.COM 	/*
32211334SReed.Liu@Sun.COM 	 * First, we dump the iport's children dev_info node information.
32311334SReed.Liu@Sun.COM 	 * use existing walker: devinfo_siblings
32411334SReed.Liu@Sun.COM 	 */
32511334SReed.Liu@Sun.COM 	mdb_printf("\t#: @unit-address               name@\tdrill-down\n");
32611334SReed.Liu@Sun.COM 	rval = mdb_pwalk("devinfo_siblings", display_iport_di_cb,
32711334SReed.Liu@Sun.COM 	    (void *)&didx, (uintptr_t)dip.devi_child);
32811334SReed.Liu@Sun.COM 	mdb_printf("\n");
32911334SReed.Liu@Sun.COM 
33011334SReed.Liu@Sun.COM skip_di:
33111334SReed.Liu@Sun.COM 	/*
33211334SReed.Liu@Sun.COM 	 * Then we try to dump the iport's path_info node information.
33311334SReed.Liu@Sun.COM 	 * use existing walker: mdipi_phci_list
33411334SReed.Liu@Sun.COM 	 */
33511334SReed.Liu@Sun.COM 	mdb_printf("Device tree children - path_info:\n");
33611334SReed.Liu@Sun.COM 	if (mdb_vread(&phci, sizeof (struct mdi_phci),
33711334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_mdi_xhci) != sizeof (struct mdi_phci)) {
33811334SReed.Liu@Sun.COM 		mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n");
33911334SReed.Liu@Sun.COM 		return (rval);
34011334SReed.Liu@Sun.COM 	}
34111334SReed.Liu@Sun.COM 
34211334SReed.Liu@Sun.COM 	if (phci.ph_path_head == NULL) {
34311334SReed.Liu@Sun.COM 		mdb_printf("\tph_path_head is NULL, no path_info\n\n");
34411334SReed.Liu@Sun.COM 		return (rval);
34511334SReed.Liu@Sun.COM 	}
34611334SReed.Liu@Sun.COM 
34711334SReed.Liu@Sun.COM 	mdb_printf("\t#: @unit-address          drill-down\n");
34811334SReed.Liu@Sun.COM 	rval = mdb_pwalk("mdipi_phci_list", display_iport_pi_cb,
34911334SReed.Liu@Sun.COM 	    (void *)&pidx, (uintptr_t)phci.ph_path_head);
35011334SReed.Liu@Sun.COM 	mdb_printf("\n");
35111334SReed.Liu@Sun.COM 	return (rval);
35211334SReed.Liu@Sun.COM }
35311334SReed.Liu@Sun.COM 
35411334SReed.Liu@Sun.COM static void
35511334SReed.Liu@Sun.COM display_iport_more(dev_info_t *dip, per_iport_setting_t *pis)
35611334SReed.Liu@Sun.COM {
35711334SReed.Liu@Sun.COM 	if (pis->pis_damap_info) {
35811334SReed.Liu@Sun.COM 		(void) display_iport_damap(dip);
35911334SReed.Liu@Sun.COM 	}
36011334SReed.Liu@Sun.COM 
36111334SReed.Liu@Sun.COM 	if (pis->pis_dtc_info) {
36211334SReed.Liu@Sun.COM 		(void) display_iport_dtc(dip);
36311334SReed.Liu@Sun.COM 	}
36411334SReed.Liu@Sun.COM }
36511334SReed.Liu@Sun.COM 
36610696SDavid.Hollister@Sun.COM /*ARGSUSED*/
36710696SDavid.Hollister@Sun.COM static int
36810696SDavid.Hollister@Sun.COM pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv)
36910696SDavid.Hollister@Sun.COM {
37010696SDavid.Hollister@Sun.COM 	struct pmcs_iport	iport;
37110696SDavid.Hollister@Sun.COM 	uintptr_t		list_addr;
37210696SDavid.Hollister@Sun.COM 	char			*ua_state;
37310696SDavid.Hollister@Sun.COM 	char			portid[4];
37410696SDavid.Hollister@Sun.COM 	char			unit_address[34];
37511334SReed.Liu@Sun.COM 	per_iport_setting_t	*pis = (per_iport_setting_t *)priv;
37610696SDavid.Hollister@Sun.COM 
37710696SDavid.Hollister@Sun.COM 	if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) !=
37810696SDavid.Hollister@Sun.COM 	    sizeof (struct pmcs_iport)) {
37910696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
38010696SDavid.Hollister@Sun.COM 	}
38110696SDavid.Hollister@Sun.COM 
38210696SDavid.Hollister@Sun.COM 	if (mdb_readstr(unit_address, sizeof (unit_address),
38310696SDavid.Hollister@Sun.COM 	    (uintptr_t)(iport.ua)) == -1) {
38410696SDavid.Hollister@Sun.COM 		strncpy(unit_address, "Unset", sizeof (unit_address));
38510696SDavid.Hollister@Sun.COM 	}
38610696SDavid.Hollister@Sun.COM 
38710696SDavid.Hollister@Sun.COM 	if (iport.portid == 0xffff) {
38810696SDavid.Hollister@Sun.COM 		mdb_snprintf(portid, sizeof (portid), "%s", "-");
38911347SRamana.Srikanth@Sun.COM 	} else if (iport.portid == PMCS_IPORT_INVALID_PORT_ID) {
39011347SRamana.Srikanth@Sun.COM 		mdb_snprintf(portid, sizeof (portid), "%s", "N/A");
39110696SDavid.Hollister@Sun.COM 	} else {
39210696SDavid.Hollister@Sun.COM 		mdb_snprintf(portid, sizeof (portid), "%d", iport.portid);
39310696SDavid.Hollister@Sun.COM 	}
39410696SDavid.Hollister@Sun.COM 
39510696SDavid.Hollister@Sun.COM 	switch (iport.ua_state) {
39610696SDavid.Hollister@Sun.COM 	case UA_INACTIVE:
39710696SDavid.Hollister@Sun.COM 		ua_state = "Inactive";
39810696SDavid.Hollister@Sun.COM 		break;
39910696SDavid.Hollister@Sun.COM 	case UA_PEND_ACTIVATE:
40010696SDavid.Hollister@Sun.COM 		ua_state = "PendActivate";
40110696SDavid.Hollister@Sun.COM 		break;
40210696SDavid.Hollister@Sun.COM 	case UA_ACTIVE:
40310696SDavid.Hollister@Sun.COM 		ua_state = "Active";
40410696SDavid.Hollister@Sun.COM 		break;
40510696SDavid.Hollister@Sun.COM 	case UA_PEND_DEACTIVATE:
40610696SDavid.Hollister@Sun.COM 		ua_state = "PendDeactivate";
40710696SDavid.Hollister@Sun.COM 		break;
40810696SDavid.Hollister@Sun.COM 	default:
40910696SDavid.Hollister@Sun.COM 		ua_state = "Unknown";
41010696SDavid.Hollister@Sun.COM 	}
41110696SDavid.Hollister@Sun.COM 
41210696SDavid.Hollister@Sun.COM 	if (strlen(unit_address) < 3) {
41310696SDavid.Hollister@Sun.COM 		/* Standard iport unit address */
41410696SDavid.Hollister@Sun.COM 		mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State",
41510696SDavid.Hollister@Sun.COM 		    "PortID", "NumPhys", "DIP\n");
41610696SDavid.Hollister@Sun.COM 		mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr,
41710696SDavid.Hollister@Sun.COM 		    ua_state, portid, iport.nphy, iport.dip);
41810696SDavid.Hollister@Sun.COM 	} else {
41910696SDavid.Hollister@Sun.COM 		/* Temporary iport unit address */
42010696SDavid.Hollister@Sun.COM 		mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport",
42110696SDavid.Hollister@Sun.COM 		    "UA State", "PortID", "NumPhys", "DIP\n");
42210696SDavid.Hollister@Sun.COM 		mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr,
42310696SDavid.Hollister@Sun.COM 		    ua_state, portid, iport.nphy, iport.dip);
42410696SDavid.Hollister@Sun.COM 	}
42510696SDavid.Hollister@Sun.COM 
42610696SDavid.Hollister@Sun.COM 	if (iport.nphy > 0) {
42710696SDavid.Hollister@Sun.COM 		mdb_inc_indent(4);
42810696SDavid.Hollister@Sun.COM 		mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
42910696SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
43010696SDavid.Hollister@Sun.COM 		list_addr =
43110696SDavid.Hollister@Sun.COM 		    (uintptr_t)(addr + offsetof(struct pmcs_iport, phys));
43210696SDavid.Hollister@Sun.COM 		if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL,
43310696SDavid.Hollister@Sun.COM 		    list_addr) == -1) {
43410696SDavid.Hollister@Sun.COM 			mdb_warn("pmcs iport walk failed");
43510696SDavid.Hollister@Sun.COM 		}
43610696SDavid.Hollister@Sun.COM 		mdb_dec_indent(6);
43710696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
43810696SDavid.Hollister@Sun.COM 	}
43910696SDavid.Hollister@Sun.COM 
44011334SReed.Liu@Sun.COM 	/*
44111334SReed.Liu@Sun.COM 	 * See if we need to show more information based on 'd' or 'm' options
44211334SReed.Liu@Sun.COM 	 */
44311334SReed.Liu@Sun.COM 	display_iport_more(iport.dip, pis);
44411334SReed.Liu@Sun.COM 
44510696SDavid.Hollister@Sun.COM 	return (0);
44610696SDavid.Hollister@Sun.COM }
44710696SDavid.Hollister@Sun.COM 
44810696SDavid.Hollister@Sun.COM /*ARGSUSED*/
44910696SDavid.Hollister@Sun.COM static void
45011334SReed.Liu@Sun.COM display_iport(struct pmcs_hw m, uintptr_t addr, int verbose,
45111334SReed.Liu@Sun.COM     per_iport_setting_t *pis)
45210696SDavid.Hollister@Sun.COM {
45310696SDavid.Hollister@Sun.COM 	uintptr_t	list_addr;
45410696SDavid.Hollister@Sun.COM 
45510696SDavid.Hollister@Sun.COM 	if (m.iports_attached) {
45610696SDavid.Hollister@Sun.COM 		mdb_printf("Iport information:\n");
45710696SDavid.Hollister@Sun.COM 		mdb_printf("-----------------\n");
45810696SDavid.Hollister@Sun.COM 	} else {
45910696SDavid.Hollister@Sun.COM 		mdb_printf("No Iports found.\n\n");
46010696SDavid.Hollister@Sun.COM 		return;
46110696SDavid.Hollister@Sun.COM 	}
46210696SDavid.Hollister@Sun.COM 
46310696SDavid.Hollister@Sun.COM 	list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports));
46410696SDavid.Hollister@Sun.COM 
46511334SReed.Liu@Sun.COM 	if (mdb_pwalk("list", pmcs_iport_walk_cb, pis, list_addr) == -1) {
46610696SDavid.Hollister@Sun.COM 		mdb_warn("pmcs iport walk failed");
46710696SDavid.Hollister@Sun.COM 	}
46810696SDavid.Hollister@Sun.COM 
46910696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
47010696SDavid.Hollister@Sun.COM }
47110696SDavid.Hollister@Sun.COM 
47211048SDavid.Hollister@Sun.COM /* ARGSUSED */
47311048SDavid.Hollister@Sun.COM static int
47411048SDavid.Hollister@Sun.COM pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv)
47511048SDavid.Hollister@Sun.COM {
47611048SDavid.Hollister@Sun.COM 	pmcs_phy_t phy;
47711048SDavid.Hollister@Sun.COM 
47811048SDavid.Hollister@Sun.COM 	if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) {
47911048SDavid.Hollister@Sun.COM 		mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p",
48011048SDavid.Hollister@Sun.COM 		    (void *)addr);
48111048SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
48211048SDavid.Hollister@Sun.COM 	}
48311048SDavid.Hollister@Sun.COM 
48411048SDavid.Hollister@Sun.COM 	if (phy.configured && (phy.target == NULL)) {
48511048SDavid.Hollister@Sun.COM 		mdb_printf("SAS address: ");
48611048SDavid.Hollister@Sun.COM 		print_sas_address(&phy);
48711048SDavid.Hollister@Sun.COM 		mdb_printf("  DType: ");
48811048SDavid.Hollister@Sun.COM 		switch (phy.dtype) {
48911048SDavid.Hollister@Sun.COM 		case SAS:
49011048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "SAS");
49111048SDavid.Hollister@Sun.COM 			break;
49211048SDavid.Hollister@Sun.COM 		case SATA:
49311048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "SATA");
49411048SDavid.Hollister@Sun.COM 			break;
49511048SDavid.Hollister@Sun.COM 		case EXPANDER:
49611048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "SMP");
49711048SDavid.Hollister@Sun.COM 			break;
49811048SDavid.Hollister@Sun.COM 		default:
49911048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "N/A");
50011048SDavid.Hollister@Sun.COM 			break;
50111048SDavid.Hollister@Sun.COM 		}
50211048SDavid.Hollister@Sun.COM 		mdb_printf("  Path: %s\n", phy.path);
50311048SDavid.Hollister@Sun.COM 	}
50411048SDavid.Hollister@Sun.COM 
50511048SDavid.Hollister@Sun.COM 	return (0);
50611048SDavid.Hollister@Sun.COM }
50711048SDavid.Hollister@Sun.COM 
50811048SDavid.Hollister@Sun.COM static void
50911048SDavid.Hollister@Sun.COM display_unconfigured_targets(uintptr_t addr)
51011048SDavid.Hollister@Sun.COM {
51111048SDavid.Hollister@Sun.COM 	mdb_printf("Unconfigured target SAS address:\n\n");
51211048SDavid.Hollister@Sun.COM 
51311048SDavid.Hollister@Sun.COM 	if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) {
51411048SDavid.Hollister@Sun.COM 		mdb_warn("pmcs phys walk failed");
51511048SDavid.Hollister@Sun.COM 	}
51611048SDavid.Hollister@Sun.COM }
51711048SDavid.Hollister@Sun.COM 
51810743SDavid.Hollister@Sun.COM static void
51910743SDavid.Hollister@Sun.COM display_completion_queue(struct pmcs_hw ss)
52010743SDavid.Hollister@Sun.COM {
52110743SDavid.Hollister@Sun.COM 	pmcs_iocomp_cb_t ccb, *ccbp;
52210743SDavid.Hollister@Sun.COM 	pmcwork_t work;
52310743SDavid.Hollister@Sun.COM 
52410743SDavid.Hollister@Sun.COM 	if (ss.iocomp_cb_head == NULL) {
52510743SDavid.Hollister@Sun.COM 		mdb_printf("Completion queue is empty.\n");
52610743SDavid.Hollister@Sun.COM 		return;
52710743SDavid.Hollister@Sun.COM 	}
52810743SDavid.Hollister@Sun.COM 
52910743SDavid.Hollister@Sun.COM 	ccbp = ss.iocomp_cb_head;
53010743SDavid.Hollister@Sun.COM 	mdb_printf("%8s %10s %20s %8s %8s O D\n",
53110743SDavid.Hollister@Sun.COM 	    "HTag", "State", "Phy Path", "Target", "Timer");
53210743SDavid.Hollister@Sun.COM 
53310743SDavid.Hollister@Sun.COM 	while (ccbp) {
53410743SDavid.Hollister@Sun.COM 		if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t),
53510743SDavid.Hollister@Sun.COM 		    (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) {
53610743SDavid.Hollister@Sun.COM 			mdb_warn("Unable to read completion queue entry\n");
53710743SDavid.Hollister@Sun.COM 			return;
53810743SDavid.Hollister@Sun.COM 		}
53910743SDavid.Hollister@Sun.COM 
54010743SDavid.Hollister@Sun.COM 		if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk)
54110743SDavid.Hollister@Sun.COM 		    != sizeof (pmcwork_t)) {
54210743SDavid.Hollister@Sun.COM 			mdb_warn("Unable to read work structure\n");
54310743SDavid.Hollister@Sun.COM 			return;
54410743SDavid.Hollister@Sun.COM 		}
54510743SDavid.Hollister@Sun.COM 
54610743SDavid.Hollister@Sun.COM 		/*
54710743SDavid.Hollister@Sun.COM 		 * Only print the work structure if it's still active.  If
54810743SDavid.Hollister@Sun.COM 		 * it's not, it's been completed since we started looking at
54910743SDavid.Hollister@Sun.COM 		 * it.
55010743SDavid.Hollister@Sun.COM 		 */
55110743SDavid.Hollister@Sun.COM 		if (work.state != PMCS_WORK_STATE_NIL) {
55210743SDavid.Hollister@Sun.COM 			display_one_work(&work, 0, 0);
55310743SDavid.Hollister@Sun.COM 		}
55410743SDavid.Hollister@Sun.COM 		ccbp = ccb.next;
55510743SDavid.Hollister@Sun.COM 	}
55610743SDavid.Hollister@Sun.COM }
55710743SDavid.Hollister@Sun.COM 
558*12120SDavid.Hollister@Sun.COM static void
559*12120SDavid.Hollister@Sun.COM display_event_log(struct pmcs_hw ss)
560*12120SDavid.Hollister@Sun.COM {
561*12120SDavid.Hollister@Sun.COM 	pmcs_fw_event_hdr_t fwhdr;
562*12120SDavid.Hollister@Sun.COM 	char *header_id, *entry, *fwlogp;
563*12120SDavid.Hollister@Sun.COM 	uint32_t total_size = PMCS_FWLOG_SIZE, log_size, index, *swapp, sidx;
564*12120SDavid.Hollister@Sun.COM 	pmcs_fw_event_entry_t *fw_entryp;
565*12120SDavid.Hollister@Sun.COM 	struct timespec systime;
566*12120SDavid.Hollister@Sun.COM 
567*12120SDavid.Hollister@Sun.COM 	if (ss.fwlogp == NULL) {
568*12120SDavid.Hollister@Sun.COM 		mdb_printf("There is no firmware event log.\n");
569*12120SDavid.Hollister@Sun.COM 		return;
570*12120SDavid.Hollister@Sun.COM 	}
571*12120SDavid.Hollister@Sun.COM 
572*12120SDavid.Hollister@Sun.COM 	fwlogp = (char *)ss.fwlogp;
573*12120SDavid.Hollister@Sun.COM 
574*12120SDavid.Hollister@Sun.COM 	while (total_size != 0) {
575*12120SDavid.Hollister@Sun.COM 		if (mdb_vread(&fwhdr, sizeof (pmcs_fw_event_hdr_t),
576*12120SDavid.Hollister@Sun.COM 		    (uintptr_t)fwlogp) != sizeof (pmcs_fw_event_hdr_t)) {
577*12120SDavid.Hollister@Sun.COM 			mdb_warn("Unable to read firmware event log header\n");
578*12120SDavid.Hollister@Sun.COM 			return;
579*12120SDavid.Hollister@Sun.COM 		}
580*12120SDavid.Hollister@Sun.COM 
581*12120SDavid.Hollister@Sun.COM 		/*
582*12120SDavid.Hollister@Sun.COM 		 * Firmware event log is little-endian
583*12120SDavid.Hollister@Sun.COM 		 */
584*12120SDavid.Hollister@Sun.COM 		swapp = (uint32_t *)&fwhdr;
585*12120SDavid.Hollister@Sun.COM 		for (sidx = 0; sidx < (sizeof (pmcs_fw_event_hdr_t) /
586*12120SDavid.Hollister@Sun.COM 		    sizeof (uint32_t)); sidx++) {
587*12120SDavid.Hollister@Sun.COM 			*swapp = LE_32(*swapp);
588*12120SDavid.Hollister@Sun.COM 			swapp++;
589*12120SDavid.Hollister@Sun.COM 		}
590*12120SDavid.Hollister@Sun.COM 
591*12120SDavid.Hollister@Sun.COM 		if (fwhdr.fw_el_signature == PMCS_FWLOG_AAP1_SIG) {
592*12120SDavid.Hollister@Sun.COM 			header_id = "AAP1";
593*12120SDavid.Hollister@Sun.COM 		} else if (fwhdr.fw_el_signature == PMCS_FWLOG_IOP_SIG) {
594*12120SDavid.Hollister@Sun.COM 			header_id = "IOP";
595*12120SDavid.Hollister@Sun.COM 		} else {
596*12120SDavid.Hollister@Sun.COM 			mdb_warn("Invalid firmware event log signature\n");
597*12120SDavid.Hollister@Sun.COM 			return;
598*12120SDavid.Hollister@Sun.COM 		}
599*12120SDavid.Hollister@Sun.COM 
600*12120SDavid.Hollister@Sun.COM 		mdb_printf("Event Log:    %s\n", header_id);
601*12120SDavid.Hollister@Sun.COM 		mdb_printf("Oldest entry: %d\n", fwhdr.fw_el_oldest_idx);
602*12120SDavid.Hollister@Sun.COM 		mdb_printf("Latest entry: %d\n", fwhdr.fw_el_latest_idx);
603*12120SDavid.Hollister@Sun.COM 
604*12120SDavid.Hollister@Sun.COM 		entry = mdb_alloc(fwhdr.fw_el_entry_size, UM_SLEEP);
605*12120SDavid.Hollister@Sun.COM 		fw_entryp = (pmcs_fw_event_entry_t *)((void *)entry);
606*12120SDavid.Hollister@Sun.COM 		total_size -= sizeof (pmcs_fw_event_hdr_t);
607*12120SDavid.Hollister@Sun.COM 		log_size = fwhdr.fw_el_buf_size;
608*12120SDavid.Hollister@Sun.COM 		fwlogp += fwhdr.fw_el_entry_start_offset;
609*12120SDavid.Hollister@Sun.COM 		swapp = (uint32_t *)((void *)entry);
610*12120SDavid.Hollister@Sun.COM 		index = 0;
611*12120SDavid.Hollister@Sun.COM 
612*12120SDavid.Hollister@Sun.COM 		mdb_printf("%8s %16s %32s %8s %3s %8s %8s %8s %8s",
613*12120SDavid.Hollister@Sun.COM 		    "Index", "Timestamp", "Time", "Seq Num", "Sev", "Word 0",
614*12120SDavid.Hollister@Sun.COM 		    "Word 1", "Word 2", "Word 3");
615*12120SDavid.Hollister@Sun.COM 		mdb_printf("\n");
616*12120SDavid.Hollister@Sun.COM 
617*12120SDavid.Hollister@Sun.COM 		while (log_size != 0) {
618*12120SDavid.Hollister@Sun.COM 			if (mdb_vread(entry, fwhdr.fw_el_entry_size,
619*12120SDavid.Hollister@Sun.COM 			    (uintptr_t)fwlogp) != fwhdr.fw_el_entry_size) {
620*12120SDavid.Hollister@Sun.COM 				mdb_warn("Unable to read event log entry\n");
621*12120SDavid.Hollister@Sun.COM 				goto bail_out;
622*12120SDavid.Hollister@Sun.COM 			}
623*12120SDavid.Hollister@Sun.COM 
624*12120SDavid.Hollister@Sun.COM 			for (sidx = 0; sidx < (fwhdr.fw_el_entry_size /
625*12120SDavid.Hollister@Sun.COM 			    sizeof (uint32_t)); sidx++) {
626*12120SDavid.Hollister@Sun.COM 				*(swapp + sidx) = LE_32(*(swapp + sidx));
627*12120SDavid.Hollister@Sun.COM 			}
628*12120SDavid.Hollister@Sun.COM 
629*12120SDavid.Hollister@Sun.COM 			if (fw_entryp->ts_upper || fw_entryp->ts_lower) {
630*12120SDavid.Hollister@Sun.COM 				pmcs_fwtime_to_systime(ss, fw_entryp->ts_upper,
631*12120SDavid.Hollister@Sun.COM 				    fw_entryp->ts_lower, &systime);
632*12120SDavid.Hollister@Sun.COM 				mdb_printf("%8d %08x%08x [%Y.%09ld] %8d %3d "
633*12120SDavid.Hollister@Sun.COM 				    "%08x %08x %08x %08x\n", index,
634*12120SDavid.Hollister@Sun.COM 				    fw_entryp->ts_upper, fw_entryp->ts_lower,
635*12120SDavid.Hollister@Sun.COM 				    systime, fw_entryp->seq_num,
636*12120SDavid.Hollister@Sun.COM 				    fw_entryp->severity, fw_entryp->logw0,
637*12120SDavid.Hollister@Sun.COM 				    fw_entryp->logw1, fw_entryp->logw2,
638*12120SDavid.Hollister@Sun.COM 				    fw_entryp->logw3);
639*12120SDavid.Hollister@Sun.COM 			}
640*12120SDavid.Hollister@Sun.COM 
641*12120SDavid.Hollister@Sun.COM 			fwlogp += fwhdr.fw_el_entry_size;
642*12120SDavid.Hollister@Sun.COM 			total_size -= fwhdr.fw_el_entry_size;
643*12120SDavid.Hollister@Sun.COM 			log_size -= fwhdr.fw_el_entry_size;
644*12120SDavid.Hollister@Sun.COM 			index++;
645*12120SDavid.Hollister@Sun.COM 		}
646*12120SDavid.Hollister@Sun.COM 
647*12120SDavid.Hollister@Sun.COM 		mdb_printf("\n");
648*12120SDavid.Hollister@Sun.COM 	}
649*12120SDavid.Hollister@Sun.COM 
650*12120SDavid.Hollister@Sun.COM bail_out:
651*12120SDavid.Hollister@Sun.COM 	mdb_free(entry, fwhdr.fw_el_entry_size);
652*12120SDavid.Hollister@Sun.COM }
653*12120SDavid.Hollister@Sun.COM 
65410696SDavid.Hollister@Sun.COM /*ARGSUSED*/
65510696SDavid.Hollister@Sun.COM static void
65610696SDavid.Hollister@Sun.COM display_hwinfo(struct pmcs_hw m, int verbose)
65710696SDavid.Hollister@Sun.COM {
65810696SDavid.Hollister@Sun.COM 	struct pmcs_hw	*mp = &m;
65910696SDavid.Hollister@Sun.COM 	char		*fwsupport;
66010696SDavid.Hollister@Sun.COM 
66110696SDavid.Hollister@Sun.COM 	switch (PMCS_FW_TYPE(mp)) {
66210696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_RELEASED:
66310696SDavid.Hollister@Sun.COM 		fwsupport = "Released";
66410696SDavid.Hollister@Sun.COM 		break;
66510696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_DEVELOPMENT:
66610696SDavid.Hollister@Sun.COM 		fwsupport = "Development";
66710696SDavid.Hollister@Sun.COM 		break;
66810696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_ALPHA:
66910696SDavid.Hollister@Sun.COM 		fwsupport = "Alpha";
67010696SDavid.Hollister@Sun.COM 		break;
67110696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_BETA:
67210696SDavid.Hollister@Sun.COM 		fwsupport = "Beta";
67310696SDavid.Hollister@Sun.COM 		break;
67410696SDavid.Hollister@Sun.COM 	default:
67510696SDavid.Hollister@Sun.COM 		fwsupport = "Special";
67610696SDavid.Hollister@Sun.COM 		break;
67710696SDavid.Hollister@Sun.COM 	}
67810696SDavid.Hollister@Sun.COM 
67910696SDavid.Hollister@Sun.COM 	mdb_printf("\nHardware information:\n");
68010696SDavid.Hollister@Sun.COM 	mdb_printf("---------------------\n");
68110696SDavid.Hollister@Sun.COM 
68210696SDavid.Hollister@Sun.COM 	mdb_printf("Chip revision:    %c\n", 'A' + m.chiprev);
68310696SDavid.Hollister@Sun.COM 	mdb_printf("SAS WWID:         %"PRIx64"\n", m.sas_wwns[0]);
68410696SDavid.Hollister@Sun.COM 	mdb_printf("Firmware version: %x.%x.%x (%s)\n",
68510696SDavid.Hollister@Sun.COM 	    PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp),
68610696SDavid.Hollister@Sun.COM 	    fwsupport);
68711980SDavid.Hollister@Sun.COM 	mdb_printf("ILA version:      %08x\n", m.ila_ver);
68811980SDavid.Hollister@Sun.COM 	mdb_printf("Active f/w img:   %c\n", (m.fw_active_img) ? 'A' : 'B');
68910696SDavid.Hollister@Sun.COM 
69010696SDavid.Hollister@Sun.COM 	mdb_printf("Number of PHYs:   %d\n", m.nphy);
69110696SDavid.Hollister@Sun.COM 	mdb_printf("Maximum commands: %d\n", m.max_cmd);
69210696SDavid.Hollister@Sun.COM 	mdb_printf("Maximum devices:  %d\n", m.max_dev);
69310696SDavid.Hollister@Sun.COM 	mdb_printf("I/O queue depth:  %d\n", m.ioq_depth);
69412060SDavid.Hollister@Sun.COM 	mdb_printf("Open retry intvl: %d usecs\n", m.open_retry_interval);
69510696SDavid.Hollister@Sun.COM 	if (m.fwlog == 0) {
69610696SDavid.Hollister@Sun.COM 		mdb_printf("Firmware logging: Disabled\n");
69710696SDavid.Hollister@Sun.COM 	} else {
69810696SDavid.Hollister@Sun.COM 		mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog);
69910696SDavid.Hollister@Sun.COM 	}
70011980SDavid.Hollister@Sun.COM 	if (m.fwlog_file == 0) {
70111980SDavid.Hollister@Sun.COM 		mdb_printf("Firmware logfile: Not configured\n");
70211980SDavid.Hollister@Sun.COM 	} else {
70311980SDavid.Hollister@Sun.COM 		mdb_printf("Firmware logfile: Configured\n");
70411980SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
70511980SDavid.Hollister@Sun.COM 		mdb_printf("AAP1 log file:  %s\n", m.fwlogfile_aap1);
70611980SDavid.Hollister@Sun.COM 		mdb_printf("IOP logfile:    %s\n", m.fwlogfile_iop);
70711980SDavid.Hollister@Sun.COM 		mdb_dec_indent(2);
70811980SDavid.Hollister@Sun.COM 	}
70910696SDavid.Hollister@Sun.COM }
71010696SDavid.Hollister@Sun.COM 
71110696SDavid.Hollister@Sun.COM static void
71210696SDavid.Hollister@Sun.COM display_targets(struct pmcs_hw m, int verbose, int totals_only)
71310696SDavid.Hollister@Sun.COM {
71410696SDavid.Hollister@Sun.COM 	char		*dtype;
71510696SDavid.Hollister@Sun.COM 	pmcs_xscsi_t	xs;
71610696SDavid.Hollister@Sun.COM 	pmcs_phy_t	phy;
71710696SDavid.Hollister@Sun.COM 	uint16_t	max_dev, idx;
71810696SDavid.Hollister@Sun.COM 	uint32_t	sas_targets = 0, smp_targets = 0, sata_targets = 0;
71910696SDavid.Hollister@Sun.COM 
72010696SDavid.Hollister@Sun.COM 	max_dev = m.max_dev;
72110696SDavid.Hollister@Sun.COM 
72210696SDavid.Hollister@Sun.COM 	if (targets == NULL) {
72310696SDavid.Hollister@Sun.COM 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
72410696SDavid.Hollister@Sun.COM 	}
72510696SDavid.Hollister@Sun.COM 
72610696SDavid.Hollister@Sun.COM 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
72710696SDavid.Hollister@Sun.COM 		NOREAD(targets, m.targets);
72810696SDavid.Hollister@Sun.COM 		return;
72910696SDavid.Hollister@Sun.COM 	}
73010696SDavid.Hollister@Sun.COM 
73110696SDavid.Hollister@Sun.COM 	if (!totals_only) {
73210696SDavid.Hollister@Sun.COM 		mdb_printf("\nTarget information:\n");
73310696SDavid.Hollister@Sun.COM 		mdb_printf("---------------------------------------\n");
73411347SRamana.Srikanth@Sun.COM 		mdb_printf("VTGT %-16s %-16s %-5s %4s %6s %s", "SAS Address",
73511347SRamana.Srikanth@Sun.COM 		    "PHY Address", "DType", "Actv", "OnChip", "DS");
73610696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
73710696SDavid.Hollister@Sun.COM 	}
73810696SDavid.Hollister@Sun.COM 
73910696SDavid.Hollister@Sun.COM 	for (idx = 0; idx < max_dev; idx++) {
74010696SDavid.Hollister@Sun.COM 		if (targets[idx] == NULL) {
74110696SDavid.Hollister@Sun.COM 			continue;
74210696SDavid.Hollister@Sun.COM 		}
74310696SDavid.Hollister@Sun.COM 
74410696SDavid.Hollister@Sun.COM 		if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) {
74510696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_xscsi_t, targets[idx]);
74610696SDavid.Hollister@Sun.COM 			continue;
74710696SDavid.Hollister@Sun.COM 		}
74810696SDavid.Hollister@Sun.COM 
74910696SDavid.Hollister@Sun.COM 		/*
75010755SJesse.Butler@Sun.COM 		 * It has to be new or assigned to be of interest.
75110696SDavid.Hollister@Sun.COM 		 */
75210755SJesse.Butler@Sun.COM 		if (xs.new == 0 && xs.assigned == 0) {
75310696SDavid.Hollister@Sun.COM 			continue;
75410696SDavid.Hollister@Sun.COM 		}
75510696SDavid.Hollister@Sun.COM 
75610696SDavid.Hollister@Sun.COM 		switch (xs.dtype) {
75710696SDavid.Hollister@Sun.COM 		case NOTHING:
75810696SDavid.Hollister@Sun.COM 			dtype = "None";
75910696SDavid.Hollister@Sun.COM 			break;
76010696SDavid.Hollister@Sun.COM 		case SATA:
76110696SDavid.Hollister@Sun.COM 			dtype = "SATA";
76210696SDavid.Hollister@Sun.COM 			sata_targets++;
76310696SDavid.Hollister@Sun.COM 			break;
76410696SDavid.Hollister@Sun.COM 		case SAS:
76510696SDavid.Hollister@Sun.COM 			dtype = "SAS";
76610696SDavid.Hollister@Sun.COM 			sas_targets++;
76710696SDavid.Hollister@Sun.COM 			break;
76810696SDavid.Hollister@Sun.COM 		case EXPANDER:
76910696SDavid.Hollister@Sun.COM 			dtype = "SMP";
77010696SDavid.Hollister@Sun.COM 			smp_targets++;
77110696SDavid.Hollister@Sun.COM 			break;
77210696SDavid.Hollister@Sun.COM 		}
77310696SDavid.Hollister@Sun.COM 
77410696SDavid.Hollister@Sun.COM 		if (totals_only) {
77510696SDavid.Hollister@Sun.COM 			continue;
77610696SDavid.Hollister@Sun.COM 		}
77710696SDavid.Hollister@Sun.COM 
77810696SDavid.Hollister@Sun.COM 		if (xs.phy) {
77910696SDavid.Hollister@Sun.COM 			if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) {
78010696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_phy_t, xs.phy);
78110696SDavid.Hollister@Sun.COM 				continue;
78210696SDavid.Hollister@Sun.COM 			}
78310696SDavid.Hollister@Sun.COM 			mdb_printf("%4d ", idx);
78410696SDavid.Hollister@Sun.COM 			print_sas_address(&phy);
78510696SDavid.Hollister@Sun.COM 			mdb_printf(" %16p", xs.phy);
78610696SDavid.Hollister@Sun.COM 		} else {
78710696SDavid.Hollister@Sun.COM 			mdb_printf("%4d %16s", idx, "<no phy avail>");
78810696SDavid.Hollister@Sun.COM 		}
78910696SDavid.Hollister@Sun.COM 		mdb_printf(" %5s", dtype);
79011347SRamana.Srikanth@Sun.COM 		mdb_printf(" %4d", xs.actv_pkts);
79111347SRamana.Srikanth@Sun.COM 		mdb_printf(" %6d", xs.actv_cnt);
79210696SDavid.Hollister@Sun.COM 		mdb_printf(" %2d", xs.dev_state);
79310696SDavid.Hollister@Sun.COM 
79410696SDavid.Hollister@Sun.COM 		if (verbose) {
79510696SDavid.Hollister@Sun.COM 			if (xs.new) {
79610696SDavid.Hollister@Sun.COM 				mdb_printf(" new");
79710755SJesse.Butler@Sun.COM 			}
79810755SJesse.Butler@Sun.COM 			if (xs.assigned) {
79910696SDavid.Hollister@Sun.COM 				mdb_printf(" assigned");
80010696SDavid.Hollister@Sun.COM 			}
80110696SDavid.Hollister@Sun.COM 			if (xs.draining) {
80210696SDavid.Hollister@Sun.COM 				mdb_printf(" draining");
80310696SDavid.Hollister@Sun.COM 			}
80410696SDavid.Hollister@Sun.COM 			if (xs.reset_wait) {
80510696SDavid.Hollister@Sun.COM 				mdb_printf(" reset_wait");
80610696SDavid.Hollister@Sun.COM 			}
80710696SDavid.Hollister@Sun.COM 			if (xs.resetting) {
80810696SDavid.Hollister@Sun.COM 				mdb_printf(" resetting");
80910696SDavid.Hollister@Sun.COM 			}
81010696SDavid.Hollister@Sun.COM 			if (xs.recover_wait) {
81110696SDavid.Hollister@Sun.COM 				mdb_printf(" recover_wait");
81210696SDavid.Hollister@Sun.COM 			}
81310696SDavid.Hollister@Sun.COM 			if (xs.recovering) {
81410696SDavid.Hollister@Sun.COM 				mdb_printf(" recovering");
81510696SDavid.Hollister@Sun.COM 			}
81610696SDavid.Hollister@Sun.COM 			if (xs.event_recovery) {
81710696SDavid.Hollister@Sun.COM 				mdb_printf(" event recovery");
81810696SDavid.Hollister@Sun.COM 			}
81910696SDavid.Hollister@Sun.COM 			if (xs.special_running) {
82010696SDavid.Hollister@Sun.COM 				mdb_printf(" special_active");
82110696SDavid.Hollister@Sun.COM 			}
82210696SDavid.Hollister@Sun.COM 			if (xs.ncq) {
82310696SDavid.Hollister@Sun.COM 				mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
82410696SDavid.Hollister@Sun.COM 				    xs.tagmap, xs.qdepth);
82510696SDavid.Hollister@Sun.COM 			} else if (xs.pio) {
82610696SDavid.Hollister@Sun.COM 				mdb_printf(" pio");
82710696SDavid.Hollister@Sun.COM 			}
82810696SDavid.Hollister@Sun.COM 		}
82910696SDavid.Hollister@Sun.COM 
83010696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
83110696SDavid.Hollister@Sun.COM 	}
83210696SDavid.Hollister@Sun.COM 
83310696SDavid.Hollister@Sun.COM 	if (!totals_only) {
83410696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
83510696SDavid.Hollister@Sun.COM 	}
83610696SDavid.Hollister@Sun.COM 
83710696SDavid.Hollister@Sun.COM 	mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
83810696SDavid.Hollister@Sun.COM 	    "Configured targets:", (sas_targets + sata_targets + smp_targets),
83910696SDavid.Hollister@Sun.COM 	    sas_targets, sata_targets, smp_targets);
84010696SDavid.Hollister@Sun.COM }
84110696SDavid.Hollister@Sun.COM 
84210743SDavid.Hollister@Sun.COM static char *
84310743SDavid.Hollister@Sun.COM work_state_to_string(uint32_t state)
84410743SDavid.Hollister@Sun.COM {
84510743SDavid.Hollister@Sun.COM 	char *state_string;
84610743SDavid.Hollister@Sun.COM 
84710743SDavid.Hollister@Sun.COM 	switch (state) {
84810743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_NIL:
84910743SDavid.Hollister@Sun.COM 		state_string = "Free";
85010743SDavid.Hollister@Sun.COM 		break;
85110743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_READY:
85210743SDavid.Hollister@Sun.COM 		state_string = "Ready";
85310743SDavid.Hollister@Sun.COM 		break;
85410743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_ONCHIP:
85510743SDavid.Hollister@Sun.COM 		state_string = "On Chip";
85610743SDavid.Hollister@Sun.COM 		break;
85710743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_INTR:
85810743SDavid.Hollister@Sun.COM 		state_string = "In Intr";
85910743SDavid.Hollister@Sun.COM 		break;
86010743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_IOCOMPQ:
86110743SDavid.Hollister@Sun.COM 		state_string = "I/O Comp";
86210743SDavid.Hollister@Sun.COM 		break;
86310743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_ABORTED:
86410743SDavid.Hollister@Sun.COM 		state_string = "I/O Aborted";
86510743SDavid.Hollister@Sun.COM 		break;
86610743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_TIMED_OUT:
86710743SDavid.Hollister@Sun.COM 		state_string = "I/O Timed Out";
86810743SDavid.Hollister@Sun.COM 		break;
86910743SDavid.Hollister@Sun.COM 	default:
87010743SDavid.Hollister@Sun.COM 		state_string = "INVALID";
87110743SDavid.Hollister@Sun.COM 		break;
87210743SDavid.Hollister@Sun.COM 	}
87310743SDavid.Hollister@Sun.COM 
87410743SDavid.Hollister@Sun.COM 	return (state_string);
87510743SDavid.Hollister@Sun.COM }
87610743SDavid.Hollister@Sun.COM 
87710743SDavid.Hollister@Sun.COM static void
87810743SDavid.Hollister@Sun.COM display_one_work(pmcwork_t *wp, int verbose, int idx)
87910743SDavid.Hollister@Sun.COM {
88010743SDavid.Hollister@Sun.COM 	char		*state, *last_state;
88110743SDavid.Hollister@Sun.COM 	char		*path;
88210743SDavid.Hollister@Sun.COM 	pmcs_xscsi_t	xs;
88310743SDavid.Hollister@Sun.COM 	pmcs_phy_t	phy;
88410743SDavid.Hollister@Sun.COM 	int		tgt;
88510743SDavid.Hollister@Sun.COM 
88610743SDavid.Hollister@Sun.COM 	state = work_state_to_string(wp->state);
88710743SDavid.Hollister@Sun.COM 	last_state = work_state_to_string(wp->last_state);
88810743SDavid.Hollister@Sun.COM 
88910743SDavid.Hollister@Sun.COM 	if (wp->ssp_event && wp->ssp_event != 0xffffffff) {
89010743SDavid.Hollister@Sun.COM 		mdb_printf("SSP event 0x%x", wp->ssp_event);
89110743SDavid.Hollister@Sun.COM 	}
89210743SDavid.Hollister@Sun.COM 
89310743SDavid.Hollister@Sun.COM 	tgt = -1;
89410743SDavid.Hollister@Sun.COM 	if (wp->xp) {
89510743SDavid.Hollister@Sun.COM 		if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) {
89610743SDavid.Hollister@Sun.COM 			NOREAD(pmcs_xscsi_t, wp->xp);
89710743SDavid.Hollister@Sun.COM 		} else {
89810743SDavid.Hollister@Sun.COM 			tgt = xs.target_num;
89910743SDavid.Hollister@Sun.COM 		}
90010743SDavid.Hollister@Sun.COM 	}
90110743SDavid.Hollister@Sun.COM 	if (wp->phy) {
90210743SDavid.Hollister@Sun.COM 		if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) {
90310743SDavid.Hollister@Sun.COM 			NOREAD(pmcs_phy_t, wp->phy);
90410743SDavid.Hollister@Sun.COM 		}
90510743SDavid.Hollister@Sun.COM 		path = phy.path;
90610743SDavid.Hollister@Sun.COM 	} else {
90710743SDavid.Hollister@Sun.COM 		path = "N/A";
90810743SDavid.Hollister@Sun.COM 	}
90910743SDavid.Hollister@Sun.COM 
91010743SDavid.Hollister@Sun.COM 	if (verbose) {
91110743SDavid.Hollister@Sun.COM 		mdb_printf("%4d ", idx);
91210743SDavid.Hollister@Sun.COM 	}
91310743SDavid.Hollister@Sun.COM 	if (tgt == -1) {
91410743SDavid.Hollister@Sun.COM 		mdb_printf("%08x %10s %20s      N/A %8u %1d %1d ",
91510743SDavid.Hollister@Sun.COM 		    wp->htag, state, path, wp->timer,
91610743SDavid.Hollister@Sun.COM 		    wp->onwire, wp->dead);
91710743SDavid.Hollister@Sun.COM 	} else {
91810743SDavid.Hollister@Sun.COM 		mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
91910743SDavid.Hollister@Sun.COM 		    wp->htag, state, path, tgt, wp->timer,
92010743SDavid.Hollister@Sun.COM 		    wp->onwire, wp->dead);
92110743SDavid.Hollister@Sun.COM 	}
92210743SDavid.Hollister@Sun.COM 	if (verbose) {
92311601SDavid.Hollister@Sun.COM 		mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n",
92411601SDavid.Hollister@Sun.COM 		    wp->last_htag, last_state, wp->last_phy, wp->last_xp,
92511601SDavid.Hollister@Sun.COM 		    wp->last_arg);
92610743SDavid.Hollister@Sun.COM 	} else {
92710743SDavid.Hollister@Sun.COM 		mdb_printf("\n");
92810743SDavid.Hollister@Sun.COM 	}
92910743SDavid.Hollister@Sun.COM }
93010743SDavid.Hollister@Sun.COM 
93110696SDavid.Hollister@Sun.COM static void
93212060SDavid.Hollister@Sun.COM display_work(struct pmcs_hw m, int verbose, int wserno)
93310696SDavid.Hollister@Sun.COM {
93410696SDavid.Hollister@Sun.COM 	int		idx;
93510743SDavid.Hollister@Sun.COM 	boolean_t	header_printed = B_FALSE;
93612060SDavid.Hollister@Sun.COM 	pmcwork_t	*wp;
93712060SDavid.Hollister@Sun.COM 	wserno_list_t	*sernop, *sp, *newsp, *sphead = NULL;
93810696SDavid.Hollister@Sun.COM 	uintptr_t	_wp;
93912060SDavid.Hollister@Sun.COM 	int		serno;
94012060SDavid.Hollister@Sun.COM 
94112060SDavid.Hollister@Sun.COM 	wp = mdb_alloc(sizeof (pmcwork_t) * m.max_cmd, UM_SLEEP);
94212060SDavid.Hollister@Sun.COM 	_wp = (uintptr_t)m.work;
94312060SDavid.Hollister@Sun.COM 	sernop = mdb_alloc(sizeof (wserno_list_t) * m.max_cmd, UM_SLEEP);
94412060SDavid.Hollister@Sun.COM 	bzero(sernop, sizeof (wserno_list_t) * m.max_cmd);
94510696SDavid.Hollister@Sun.COM 
94610696SDavid.Hollister@Sun.COM 	mdb_printf("\nActive Work structure information:\n");
94710696SDavid.Hollister@Sun.COM 	mdb_printf("----------------------------------\n");
94810696SDavid.Hollister@Sun.COM 
94912060SDavid.Hollister@Sun.COM 	/*
95012060SDavid.Hollister@Sun.COM 	 * Read in all the work structures
95112060SDavid.Hollister@Sun.COM 	 */
95210696SDavid.Hollister@Sun.COM 	for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
95312060SDavid.Hollister@Sun.COM 		if (MDB_RD(wp + idx, sizeof (pmcwork_t), _wp) == -1) {
95410696SDavid.Hollister@Sun.COM 			NOREAD(pmcwork_t, _wp);
95510696SDavid.Hollister@Sun.COM 			continue;
95610696SDavid.Hollister@Sun.COM 		}
95712060SDavid.Hollister@Sun.COM 	}
95810743SDavid.Hollister@Sun.COM 
95912060SDavid.Hollister@Sun.COM 	/*
96012060SDavid.Hollister@Sun.COM 	 * Sort by serial number?
96112060SDavid.Hollister@Sun.COM 	 */
96212060SDavid.Hollister@Sun.COM 	if (wserno) {
96312060SDavid.Hollister@Sun.COM 		for (idx = 0; idx < m.max_cmd; idx++) {
96412060SDavid.Hollister@Sun.COM 			if ((wp + idx)->htag == 0) {
96512060SDavid.Hollister@Sun.COM 				serno = PMCS_TAG_SERNO((wp + idx)->last_htag);
96612060SDavid.Hollister@Sun.COM 			} else {
96712060SDavid.Hollister@Sun.COM 				serno = PMCS_TAG_SERNO((wp + idx)->htag);
96812060SDavid.Hollister@Sun.COM 			}
96912060SDavid.Hollister@Sun.COM 
97012060SDavid.Hollister@Sun.COM 			/* Start at the beginning of the list */
97112060SDavid.Hollister@Sun.COM 			sp = sphead;
97212060SDavid.Hollister@Sun.COM 			newsp = sernop + idx;
97312060SDavid.Hollister@Sun.COM 			/* If this is the first entry, just add it */
97412060SDavid.Hollister@Sun.COM 			if (sphead == NULL) {
97512060SDavid.Hollister@Sun.COM 				sphead = sernop;
97612060SDavid.Hollister@Sun.COM 				sphead->serno = serno;
97712060SDavid.Hollister@Sun.COM 				sphead->idx = idx;
97812060SDavid.Hollister@Sun.COM 				sphead->next = NULL;
97912060SDavid.Hollister@Sun.COM 				sphead->prev = NULL;
98012060SDavid.Hollister@Sun.COM 				continue;
98112060SDavid.Hollister@Sun.COM 			}
98212060SDavid.Hollister@Sun.COM 
98312060SDavid.Hollister@Sun.COM 			newsp->serno = serno;
98412060SDavid.Hollister@Sun.COM 			newsp->idx = idx;
98512060SDavid.Hollister@Sun.COM 
98612060SDavid.Hollister@Sun.COM 			/* Find out where in the list this goes */
98712060SDavid.Hollister@Sun.COM 			while (sp) {
98812060SDavid.Hollister@Sun.COM 				/* This item goes before sp */
98912060SDavid.Hollister@Sun.COM 				if (serno < sp->serno) {
99012060SDavid.Hollister@Sun.COM 					newsp->next = sp;
99112060SDavid.Hollister@Sun.COM 					newsp->prev = sp->prev;
99212060SDavid.Hollister@Sun.COM 					if (newsp->prev == NULL) {
99312060SDavid.Hollister@Sun.COM 						sphead = newsp;
99412060SDavid.Hollister@Sun.COM 					} else {
99512060SDavid.Hollister@Sun.COM 						newsp->prev->next = newsp;
99612060SDavid.Hollister@Sun.COM 					}
99712060SDavid.Hollister@Sun.COM 					sp->prev = newsp;
99812060SDavid.Hollister@Sun.COM 					break;
99912060SDavid.Hollister@Sun.COM 				}
100012060SDavid.Hollister@Sun.COM 
100112060SDavid.Hollister@Sun.COM 				/*
100212060SDavid.Hollister@Sun.COM 				 * If sp->next is NULL, this entry goes at the
100312060SDavid.Hollister@Sun.COM 				 * end of the list
100412060SDavid.Hollister@Sun.COM 				 */
100512060SDavid.Hollister@Sun.COM 				if (sp->next == NULL) {
100612060SDavid.Hollister@Sun.COM 					sp->next = newsp;
100712060SDavid.Hollister@Sun.COM 					newsp->next = NULL;
100812060SDavid.Hollister@Sun.COM 					newsp->prev = sp;
100912060SDavid.Hollister@Sun.COM 					break;
101012060SDavid.Hollister@Sun.COM 				}
101112060SDavid.Hollister@Sun.COM 
101212060SDavid.Hollister@Sun.COM 				sp = sp->next;
101312060SDavid.Hollister@Sun.COM 			}
101412060SDavid.Hollister@Sun.COM 		}
101512060SDavid.Hollister@Sun.COM 
101612060SDavid.Hollister@Sun.COM 		/*
101712060SDavid.Hollister@Sun.COM 		 * Now print the sorted list
101812060SDavid.Hollister@Sun.COM 		 */
101912060SDavid.Hollister@Sun.COM 		mdb_printf(" Idx %8s %10s %20s %8s %8s O D ",
102012060SDavid.Hollister@Sun.COM 		    "HTag", "State", "Phy Path", "Target", "Timer");
102112060SDavid.Hollister@Sun.COM 		mdb_printf("%8s %10s %18s %18s %18s\n", "LastHTAG",
102212060SDavid.Hollister@Sun.COM 		    "LastState", "LastPHY", "LastTgt", "LastArg");
102312060SDavid.Hollister@Sun.COM 
102412060SDavid.Hollister@Sun.COM 		sp = sphead;
102512060SDavid.Hollister@Sun.COM 		while (sp) {
102612060SDavid.Hollister@Sun.COM 			display_one_work(wp + sp->idx, 1, sp->idx);
102712060SDavid.Hollister@Sun.COM 			sp = sp->next;
102812060SDavid.Hollister@Sun.COM 		}
102912060SDavid.Hollister@Sun.COM 
103012060SDavid.Hollister@Sun.COM 		goto out;
103112060SDavid.Hollister@Sun.COM 	}
103212060SDavid.Hollister@Sun.COM 
103312060SDavid.Hollister@Sun.COM 	/*
103412060SDavid.Hollister@Sun.COM 	 * Now print the list, sorted by index
103512060SDavid.Hollister@Sun.COM 	 */
103612060SDavid.Hollister@Sun.COM 	for (idx = 0; idx < m.max_cmd; idx++) {
103712060SDavid.Hollister@Sun.COM 		if (!verbose && ((wp + idx)->htag == PMCS_TAG_TYPE_FREE)) {
103810696SDavid.Hollister@Sun.COM 			continue;
103910696SDavid.Hollister@Sun.COM 		}
104010743SDavid.Hollister@Sun.COM 
104110743SDavid.Hollister@Sun.COM 		if (header_printed == B_FALSE) {
104210743SDavid.Hollister@Sun.COM 			if (verbose) {
104310743SDavid.Hollister@Sun.COM 				mdb_printf("%4s ", "Idx");
104410743SDavid.Hollister@Sun.COM 			}
104510743SDavid.Hollister@Sun.COM 			mdb_printf("%8s %10s %20s %8s %8s O D ",
104610696SDavid.Hollister@Sun.COM 			    "HTag", "State", "Phy Path", "Target", "Timer");
104710743SDavid.Hollister@Sun.COM 			if (verbose) {
104811601SDavid.Hollister@Sun.COM 				mdb_printf("%8s %10s %18s %18s %18s\n",
104911601SDavid.Hollister@Sun.COM 				    "LastHTAG", "LastState", "LastPHY",
105011601SDavid.Hollister@Sun.COM 				    "LastTgt", "LastArg");
105110743SDavid.Hollister@Sun.COM 			} else {
105210743SDavid.Hollister@Sun.COM 				mdb_printf("\n");
105310743SDavid.Hollister@Sun.COM 			}
105410743SDavid.Hollister@Sun.COM 			header_printed = B_TRUE;
105510696SDavid.Hollister@Sun.COM 		}
105610743SDavid.Hollister@Sun.COM 
105712060SDavid.Hollister@Sun.COM 		display_one_work(wp + idx, verbose, idx);
105810696SDavid.Hollister@Sun.COM 	}
105912060SDavid.Hollister@Sun.COM 
106012060SDavid.Hollister@Sun.COM out:
106112060SDavid.Hollister@Sun.COM 	mdb_free(wp, sizeof (pmcwork_t) * m.max_cmd);
106212060SDavid.Hollister@Sun.COM 	mdb_free(sernop, sizeof (wserno_list_t) * m.max_cmd);
106310696SDavid.Hollister@Sun.COM }
106410696SDavid.Hollister@Sun.COM 
106510696SDavid.Hollister@Sun.COM static void
106610743SDavid.Hollister@Sun.COM print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose)
106710696SDavid.Hollister@Sun.COM {
106810743SDavid.Hollister@Sun.COM 	int cdb_size, idx;
106910743SDavid.Hollister@Sun.COM 	struct scsi_pkt pkt;
107010743SDavid.Hollister@Sun.COM 	uchar_t cdb[256];
107110743SDavid.Hollister@Sun.COM 
107210696SDavid.Hollister@Sun.COM 	if (printhdr) {
107310743SDavid.Hollister@Sun.COM 		if (verbose) {
107410743SDavid.Hollister@Sun.COM 			mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
107510743SDavid.Hollister@Sun.COM 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
107610743SDavid.Hollister@Sun.COM 		} else {
107710743SDavid.Hollister@Sun.COM 			mdb_printf("%16s %16s %16s %8s %s\n", "Command",
107810743SDavid.Hollister@Sun.COM 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
107910743SDavid.Hollister@Sun.COM 		}
108010696SDavid.Hollister@Sun.COM 	}
108110743SDavid.Hollister@Sun.COM 
108210743SDavid.Hollister@Sun.COM 	mdb_printf("%16p %16p %16p %08x %08x ",
108310696SDavid.Hollister@Sun.COM 	    kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag);
108410743SDavid.Hollister@Sun.COM 
108510743SDavid.Hollister@Sun.COM 	/*
108610743SDavid.Hollister@Sun.COM 	 * If we're printing verbose, dump the CDB as well.
108710743SDavid.Hollister@Sun.COM 	 */
108810743SDavid.Hollister@Sun.COM 	if (verbose) {
108910743SDavid.Hollister@Sun.COM 		if (sp->cmd_pkt) {
109010743SDavid.Hollister@Sun.COM 			if (mdb_vread(&pkt, sizeof (struct scsi_pkt),
109110743SDavid.Hollister@Sun.COM 			    (uintptr_t)sp->cmd_pkt) !=
109210743SDavid.Hollister@Sun.COM 			    sizeof (struct scsi_pkt)) {
109310743SDavid.Hollister@Sun.COM 				mdb_warn("Unable to read SCSI pkt\n");
109410743SDavid.Hollister@Sun.COM 				return;
109510743SDavid.Hollister@Sun.COM 			}
109610743SDavid.Hollister@Sun.COM 			cdb_size = pkt.pkt_cdblen;
109710743SDavid.Hollister@Sun.COM 			if (mdb_vread(&cdb[0], cdb_size,
109810743SDavid.Hollister@Sun.COM 			    (uintptr_t)pkt.pkt_cdbp) != cdb_size) {
109910743SDavid.Hollister@Sun.COM 				mdb_warn("Unable to read CDB\n");
110010743SDavid.Hollister@Sun.COM 				return;
110110743SDavid.Hollister@Sun.COM 			}
110210743SDavid.Hollister@Sun.COM 
110310743SDavid.Hollister@Sun.COM 			for (idx = 0; idx < cdb_size; idx++) {
110410743SDavid.Hollister@Sun.COM 				mdb_printf("%02x ", cdb[idx]);
110510743SDavid.Hollister@Sun.COM 			}
110610743SDavid.Hollister@Sun.COM 		} else {
110710743SDavid.Hollister@Sun.COM 			mdb_printf("N/A");
110810743SDavid.Hollister@Sun.COM 		}
110910743SDavid.Hollister@Sun.COM 
111010743SDavid.Hollister@Sun.COM 		mdb_printf("\n");
111110743SDavid.Hollister@Sun.COM 	} else {
111210743SDavid.Hollister@Sun.COM 		mdb_printf("\n");
111310743SDavid.Hollister@Sun.COM 	}
111410696SDavid.Hollister@Sun.COM }
111510696SDavid.Hollister@Sun.COM 
111610696SDavid.Hollister@Sun.COM /*ARGSUSED1*/
111710696SDavid.Hollister@Sun.COM static void
111810696SDavid.Hollister@Sun.COM display_waitqs(struct pmcs_hw m, int verbose)
111910696SDavid.Hollister@Sun.COM {
112010696SDavid.Hollister@Sun.COM 	pmcs_cmd_t	*sp, s;
112110696SDavid.Hollister@Sun.COM 	pmcs_xscsi_t	xs;
112210696SDavid.Hollister@Sun.COM 	int		first, i;
112310696SDavid.Hollister@Sun.COM 	int		max_dev = m.max_dev;
112410696SDavid.Hollister@Sun.COM 
112510696SDavid.Hollister@Sun.COM 	sp = m.dq.stqh_first;
112610696SDavid.Hollister@Sun.COM 	first = 1;
112710696SDavid.Hollister@Sun.COM 	while (sp) {
112810696SDavid.Hollister@Sun.COM 		if (first) {
112910696SDavid.Hollister@Sun.COM 			mdb_printf("\nDead Command Queue:\n");
113010696SDavid.Hollister@Sun.COM 			mdb_printf("---------------------------\n");
113110696SDavid.Hollister@Sun.COM 		}
113210696SDavid.Hollister@Sun.COM 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
113310696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_cmd_t, sp);
113410696SDavid.Hollister@Sun.COM 			break;
113510696SDavid.Hollister@Sun.COM 		}
113610743SDavid.Hollister@Sun.COM 		print_spcmd(&s, sp, first, verbose);
113710696SDavid.Hollister@Sun.COM 		sp = s.cmd_next.stqe_next;
113810696SDavid.Hollister@Sun.COM 		first = 0;
113910696SDavid.Hollister@Sun.COM 	}
114010696SDavid.Hollister@Sun.COM 
114110696SDavid.Hollister@Sun.COM 	sp = m.cq.stqh_first;
114210696SDavid.Hollister@Sun.COM 	first = 1;
114310696SDavid.Hollister@Sun.COM 	while (sp) {
114410696SDavid.Hollister@Sun.COM 		if (first) {
114510696SDavid.Hollister@Sun.COM 			mdb_printf("\nCompletion Command Queue:\n");
114610696SDavid.Hollister@Sun.COM 			mdb_printf("---------------------------\n");
114710696SDavid.Hollister@Sun.COM 		}
114810696SDavid.Hollister@Sun.COM 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
114910696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_cmd_t, sp);
115010696SDavid.Hollister@Sun.COM 			break;
115110696SDavid.Hollister@Sun.COM 		}
115210743SDavid.Hollister@Sun.COM 		print_spcmd(&s, sp, first, verbose);
115310696SDavid.Hollister@Sun.COM 		sp = s.cmd_next.stqe_next;
115410696SDavid.Hollister@Sun.COM 		first = 0;
115510696SDavid.Hollister@Sun.COM 	}
115610696SDavid.Hollister@Sun.COM 
115710696SDavid.Hollister@Sun.COM 
115810696SDavid.Hollister@Sun.COM 	if (targets == NULL) {
115910696SDavid.Hollister@Sun.COM 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
116010696SDavid.Hollister@Sun.COM 	}
116110696SDavid.Hollister@Sun.COM 
116210696SDavid.Hollister@Sun.COM 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
116310696SDavid.Hollister@Sun.COM 		NOREAD(targets, m.targets);
116410696SDavid.Hollister@Sun.COM 		return;
116510696SDavid.Hollister@Sun.COM 	}
116610696SDavid.Hollister@Sun.COM 
116710696SDavid.Hollister@Sun.COM 	for (i = 0; i < max_dev; i++) {
116810696SDavid.Hollister@Sun.COM 		if (targets[i] == NULL) {
116910696SDavid.Hollister@Sun.COM 			continue;
117010696SDavid.Hollister@Sun.COM 		}
117110696SDavid.Hollister@Sun.COM 		if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) {
117210696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_xscsi_t, targets[i]);
117310696SDavid.Hollister@Sun.COM 			continue;
117410696SDavid.Hollister@Sun.COM 		}
117510696SDavid.Hollister@Sun.COM 		sp = xs.wq.stqh_first;
117610696SDavid.Hollister@Sun.COM 		first = 1;
117710696SDavid.Hollister@Sun.COM 		while (sp) {
117810696SDavid.Hollister@Sun.COM 			if (first) {
117910696SDavid.Hollister@Sun.COM 				mdb_printf("\nTarget %u Wait Queue:\n",
118010696SDavid.Hollister@Sun.COM 				    xs.target_num);
118110696SDavid.Hollister@Sun.COM 				mdb_printf("---------------------------\n");
118210696SDavid.Hollister@Sun.COM 			}
118310696SDavid.Hollister@Sun.COM 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
118410696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_cmd_t, sp);
118510696SDavid.Hollister@Sun.COM 				break;
118610696SDavid.Hollister@Sun.COM 			}
118710743SDavid.Hollister@Sun.COM 			print_spcmd(&s, sp, first, verbose);
118810696SDavid.Hollister@Sun.COM 			sp = s.cmd_next.stqe_next;
118910696SDavid.Hollister@Sun.COM 			first = 0;
119010696SDavid.Hollister@Sun.COM 		}
119110696SDavid.Hollister@Sun.COM 		sp = xs.aq.stqh_first;
119210696SDavid.Hollister@Sun.COM 		first = 1;
119310696SDavid.Hollister@Sun.COM 		while (sp) {
119410696SDavid.Hollister@Sun.COM 			if (first) {
119510696SDavid.Hollister@Sun.COM 				mdb_printf("\nTarget %u Active Queue:\n",
119610696SDavid.Hollister@Sun.COM 				    xs.target_num);
119710696SDavid.Hollister@Sun.COM 				mdb_printf("---------------------------\n");
119810696SDavid.Hollister@Sun.COM 			}
119910696SDavid.Hollister@Sun.COM 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
120010696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_cmd_t, sp);
120110696SDavid.Hollister@Sun.COM 				break;
120210696SDavid.Hollister@Sun.COM 			}
120310743SDavid.Hollister@Sun.COM 			print_spcmd(&s, sp, first, verbose);
120410696SDavid.Hollister@Sun.COM 			sp = s.cmd_next.stqe_next;
120510696SDavid.Hollister@Sun.COM 			first = 0;
120610696SDavid.Hollister@Sun.COM 		}
120710696SDavid.Hollister@Sun.COM 		sp = xs.sq.stqh_first;
120810696SDavid.Hollister@Sun.COM 		first = 1;
120910696SDavid.Hollister@Sun.COM 		while (sp) {
121010696SDavid.Hollister@Sun.COM 			if (first) {
121110696SDavid.Hollister@Sun.COM 				mdb_printf("\nTarget %u Special Queue:\n",
121210696SDavid.Hollister@Sun.COM 				    xs.target_num);
121310696SDavid.Hollister@Sun.COM 				mdb_printf("---------------------------\n");
121410696SDavid.Hollister@Sun.COM 			}
121510696SDavid.Hollister@Sun.COM 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
121610696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_cmd_t, sp);
121710696SDavid.Hollister@Sun.COM 				break;
121810696SDavid.Hollister@Sun.COM 			}
121910743SDavid.Hollister@Sun.COM 			print_spcmd(&s, sp, first, verbose);
122010696SDavid.Hollister@Sun.COM 			sp = s.cmd_next.stqe_next;
122110696SDavid.Hollister@Sun.COM 			first = 0;
122210696SDavid.Hollister@Sun.COM 		}
122310696SDavid.Hollister@Sun.COM 	}
122410696SDavid.Hollister@Sun.COM }
122510696SDavid.Hollister@Sun.COM 
122610696SDavid.Hollister@Sun.COM static char *
122710696SDavid.Hollister@Sun.COM ibq_type(int qnum)
122810696SDavid.Hollister@Sun.COM {
122910696SDavid.Hollister@Sun.COM 	if (qnum < 0 || qnum >= PMCS_NIQ) {
123010696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
123110696SDavid.Hollister@Sun.COM 	}
123210696SDavid.Hollister@Sun.COM 
123310696SDavid.Hollister@Sun.COM 	if (qnum < PMCS_IQ_OTHER) {
123410696SDavid.Hollister@Sun.COM 		return ("I/O");
123510696SDavid.Hollister@Sun.COM 	}
123610696SDavid.Hollister@Sun.COM 
123710696SDavid.Hollister@Sun.COM 	return ("Other");
123810696SDavid.Hollister@Sun.COM }
123910696SDavid.Hollister@Sun.COM 
124010696SDavid.Hollister@Sun.COM static char *
124110696SDavid.Hollister@Sun.COM obq_type(int qnum)
124210696SDavid.Hollister@Sun.COM {
124310696SDavid.Hollister@Sun.COM 	switch (qnum) {
124410696SDavid.Hollister@Sun.COM 	case PMCS_OQ_IODONE:
124510696SDavid.Hollister@Sun.COM 		return ("I/O");
124610696SDavid.Hollister@Sun.COM 		break;
124710696SDavid.Hollister@Sun.COM 	case PMCS_OQ_GENERAL:
124810696SDavid.Hollister@Sun.COM 		return ("General");
124910696SDavid.Hollister@Sun.COM 		break;
125010696SDavid.Hollister@Sun.COM 	case PMCS_OQ_EVENTS:
125110696SDavid.Hollister@Sun.COM 		return ("Events");
125210696SDavid.Hollister@Sun.COM 		break;
125310696SDavid.Hollister@Sun.COM 	default:
125410696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
125510696SDavid.Hollister@Sun.COM 	}
125610696SDavid.Hollister@Sun.COM }
125710696SDavid.Hollister@Sun.COM 
125810696SDavid.Hollister@Sun.COM static char *
125910696SDavid.Hollister@Sun.COM iomb_cat(uint32_t cat)
126010696SDavid.Hollister@Sun.COM {
126110696SDavid.Hollister@Sun.COM 	switch (cat) {
126210696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_NET:
126310696SDavid.Hollister@Sun.COM 		return ("NET");
126410696SDavid.Hollister@Sun.COM 		break;
126510696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_FC:
126610696SDavid.Hollister@Sun.COM 		return ("FC");
126710696SDavid.Hollister@Sun.COM 		break;
126810696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_SAS:
126910696SDavid.Hollister@Sun.COM 		return ("SAS");
127010696SDavid.Hollister@Sun.COM 		break;
127110696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_SCSI:
127210696SDavid.Hollister@Sun.COM 		return ("SCSI");
127310696SDavid.Hollister@Sun.COM 		break;
127410696SDavid.Hollister@Sun.COM 	default:
127510696SDavid.Hollister@Sun.COM 		return ("???");
127610696SDavid.Hollister@Sun.COM 	}
127710696SDavid.Hollister@Sun.COM }
127810696SDavid.Hollister@Sun.COM 
127910696SDavid.Hollister@Sun.COM static char *
128011601SDavid.Hollister@Sun.COM iomb_event(uint8_t event)
128111601SDavid.Hollister@Sun.COM {
128211601SDavid.Hollister@Sun.COM 	switch (event) {
128311601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_STOP_STATUS:
128411601SDavid.Hollister@Sun.COM 		return ("PHY STOP");
128511601SDavid.Hollister@Sun.COM 		break;
128611601SDavid.Hollister@Sun.COM 	case IOP_EVENT_SAS_PHY_UP:
128711601SDavid.Hollister@Sun.COM 		return ("PHY UP");
128811601SDavid.Hollister@Sun.COM 		break;
128911601SDavid.Hollister@Sun.COM 	case IOP_EVENT_SATA_PHY_UP:
129011601SDavid.Hollister@Sun.COM 		return ("SATA PHY UP");
129111601SDavid.Hollister@Sun.COM 		break;
129211601SDavid.Hollister@Sun.COM 	case IOP_EVENT_SATA_SPINUP_HOLD:
129311601SDavid.Hollister@Sun.COM 		return ("SATA SPINUP HOLD");
129411601SDavid.Hollister@Sun.COM 		break;
129511601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_DOWN:
129611601SDavid.Hollister@Sun.COM 		return ("PHY DOWN");
129711601SDavid.Hollister@Sun.COM 		break;
129811601SDavid.Hollister@Sun.COM 	case IOP_EVENT_BROADCAST_CHANGE:
129911601SDavid.Hollister@Sun.COM 		return ("BROADCAST CHANGE");
130011601SDavid.Hollister@Sun.COM 		break;
130111601SDavid.Hollister@Sun.COM 	case IOP_EVENT_BROADCAST_SES:
130211601SDavid.Hollister@Sun.COM 		return ("BROADCAST SES");
130311601SDavid.Hollister@Sun.COM 		break;
130411601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_ERR_INBOUND_CRC:
130511601SDavid.Hollister@Sun.COM 		return ("INBOUND CRC ERROR");
130611601SDavid.Hollister@Sun.COM 		break;
130711601SDavid.Hollister@Sun.COM 	case IOP_EVENT_HARD_RESET_RECEIVED:
130811601SDavid.Hollister@Sun.COM 		return ("HARD RESET");
130911601SDavid.Hollister@Sun.COM 		break;
131011601SDavid.Hollister@Sun.COM 	case IOP_EVENT_EVENT_ID_FRAME_TIMO:
131111601SDavid.Hollister@Sun.COM 		return ("IDENTIFY FRAME TIMEOUT");
131211601SDavid.Hollister@Sun.COM 		break;
131311601SDavid.Hollister@Sun.COM 	case IOP_EVENT_BROADCAST_EXP:
131411601SDavid.Hollister@Sun.COM 		return ("BROADCAST EXPANDER");
131511601SDavid.Hollister@Sun.COM 		break;
131611601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_START_STATUS:
131711601SDavid.Hollister@Sun.COM 		return ("PHY START");
131811601SDavid.Hollister@Sun.COM 		break;
131911601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_ERR_INVALID_DWORD:
132011601SDavid.Hollister@Sun.COM 		return ("INVALID DWORD");
132111601SDavid.Hollister@Sun.COM 		break;
132211601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_ERR_DISPARITY_ERROR:
132311601SDavid.Hollister@Sun.COM 		return ("DISPARITY ERROR");
132411601SDavid.Hollister@Sun.COM 		break;
132511601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_ERR_CODE_VIOLATION:
132611601SDavid.Hollister@Sun.COM 		return ("CODE VIOLATION");
132711601SDavid.Hollister@Sun.COM 		break;
132811601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN:
132911601SDavid.Hollister@Sun.COM 		return ("LOSS OF DWORD SYNC");
133011601SDavid.Hollister@Sun.COM 		break;
133111601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD:
133211601SDavid.Hollister@Sun.COM 		return ("PHY RESET FAILED");
133311601SDavid.Hollister@Sun.COM 		break;
133411601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PORT_RECOVERY_TIMER_TMO:
133511601SDavid.Hollister@Sun.COM 		return ("PORT RECOVERY TIMEOUT");
133611601SDavid.Hollister@Sun.COM 		break;
133711601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PORT_RECOVER:
133811601SDavid.Hollister@Sun.COM 		return ("PORT RECOVERY");
133911601SDavid.Hollister@Sun.COM 		break;
134011601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PORT_RESET_TIMER_TMO:
134111601SDavid.Hollister@Sun.COM 		return ("PORT RESET TIMEOUT");
134211601SDavid.Hollister@Sun.COM 		break;
134311601SDavid.Hollister@Sun.COM 	case IOP_EVENT_PORT_RESET_COMPLETE:
134411601SDavid.Hollister@Sun.COM 		return ("PORT RESET COMPLETE");
134511601SDavid.Hollister@Sun.COM 		break;
134611601SDavid.Hollister@Sun.COM 	case IOP_EVENT_BROADCAST_ASYNC_EVENT:
134711601SDavid.Hollister@Sun.COM 		return ("BROADCAST ASYNC");
134811601SDavid.Hollister@Sun.COM 		break;
134911601SDavid.Hollister@Sun.COM 	case IOP_EVENT_IT_NEXUS_LOSS:
135011601SDavid.Hollister@Sun.COM 		return ("I/T NEXUS LOSS");
135111601SDavid.Hollister@Sun.COM 		break;
135211601SDavid.Hollister@Sun.COM 	default:
135311601SDavid.Hollister@Sun.COM 		return ("Unknown Event");
135411601SDavid.Hollister@Sun.COM 	}
135511601SDavid.Hollister@Sun.COM }
135611601SDavid.Hollister@Sun.COM 
135711601SDavid.Hollister@Sun.COM static char *
135810696SDavid.Hollister@Sun.COM inbound_iomb_opcode(uint32_t opcode)
135910696SDavid.Hollister@Sun.COM {
136010696SDavid.Hollister@Sun.COM 	switch (opcode) {
136110696SDavid.Hollister@Sun.COM 	case PMCIN_ECHO:
136210696SDavid.Hollister@Sun.COM 		return ("ECHO");
136310696SDavid.Hollister@Sun.COM 		break;
136410696SDavid.Hollister@Sun.COM 	case PMCIN_GET_INFO:
136510696SDavid.Hollister@Sun.COM 		return ("GET_INFO");
136610696SDavid.Hollister@Sun.COM 		break;
136710696SDavid.Hollister@Sun.COM 	case PMCIN_GET_VPD:
136810696SDavid.Hollister@Sun.COM 		return ("GET_VPD");
136910696SDavid.Hollister@Sun.COM 		break;
137010696SDavid.Hollister@Sun.COM 	case PMCIN_PHY_START:
137110696SDavid.Hollister@Sun.COM 		return ("PHY_START");
137210696SDavid.Hollister@Sun.COM 		break;
137310696SDavid.Hollister@Sun.COM 	case PMCIN_PHY_STOP:
137410696SDavid.Hollister@Sun.COM 		return ("PHY_STOP");
137510696SDavid.Hollister@Sun.COM 		break;
137610696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_IO_START:
137710696SDavid.Hollister@Sun.COM 		return ("INI_IO_START");
137810696SDavid.Hollister@Sun.COM 		break;
137910696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_TM_START:
138010696SDavid.Hollister@Sun.COM 		return ("INI_TM_START");
138110696SDavid.Hollister@Sun.COM 		break;
138210696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_EXT_IO_START:
138310696SDavid.Hollister@Sun.COM 		return ("INI_EXT_IO_START");
138410696SDavid.Hollister@Sun.COM 		break;
138510696SDavid.Hollister@Sun.COM 	case PMCIN_DEVICE_HANDLE_ACCEPT:
138610696SDavid.Hollister@Sun.COM 		return ("DEVICE_HANDLE_ACCEPT");
138710696SDavid.Hollister@Sun.COM 		break;
138810696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_TGT_IO_START:
138910696SDavid.Hollister@Sun.COM 		return ("TGT_IO_START");
139010696SDavid.Hollister@Sun.COM 		break;
139110696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_TGT_RESPONSE_START:
139210696SDavid.Hollister@Sun.COM 		return ("TGT_RESPONSE_START");
139310696SDavid.Hollister@Sun.COM 		break;
139410696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_EDC_EXT_IO_START:
139510696SDavid.Hollister@Sun.COM 		return ("INI_EDC_EXT_IO_START");
139610696SDavid.Hollister@Sun.COM 		break;
139710696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_EDC_EXT_IO_START1:
139810696SDavid.Hollister@Sun.COM 		return ("INI_EDC_EXT_IO_START1");
139910696SDavid.Hollister@Sun.COM 		break;
140010696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_TGT_EDC_IO_START:
140110696SDavid.Hollister@Sun.COM 		return ("TGT_EDC_IO_START");
140210696SDavid.Hollister@Sun.COM 		break;
140310696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_ABORT:
140410696SDavid.Hollister@Sun.COM 		return ("SSP_ABORT");
140510696SDavid.Hollister@Sun.COM 		break;
140610696SDavid.Hollister@Sun.COM 	case PMCIN_DEREGISTER_DEVICE_HANDLE:
140710696SDavid.Hollister@Sun.COM 		return ("DEREGISTER_DEVICE_HANDLE");
140810696SDavid.Hollister@Sun.COM 		break;
140910696SDavid.Hollister@Sun.COM 	case PMCIN_GET_DEVICE_HANDLE:
141010696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_HANDLE");
141110696SDavid.Hollister@Sun.COM 		break;
141210696SDavid.Hollister@Sun.COM 	case PMCIN_SMP_REQUEST:
141310696SDavid.Hollister@Sun.COM 		return ("SMP_REQUEST");
141410696SDavid.Hollister@Sun.COM 		break;
141510696SDavid.Hollister@Sun.COM 	case PMCIN_SMP_RESPONSE:
141610696SDavid.Hollister@Sun.COM 		return ("SMP_RESPONSE");
141710696SDavid.Hollister@Sun.COM 		break;
141810696SDavid.Hollister@Sun.COM 	case PMCIN_SMP_ABORT:
141910696SDavid.Hollister@Sun.COM 		return ("SMP_ABORT");
142010696SDavid.Hollister@Sun.COM 		break;
142110696SDavid.Hollister@Sun.COM 	case PMCIN_ASSISTED_DISCOVERY:
142210696SDavid.Hollister@Sun.COM 		return ("ASSISTED_DISCOVERY");
142310696SDavid.Hollister@Sun.COM 		break;
142410696SDavid.Hollister@Sun.COM 	case PMCIN_REGISTER_DEVICE:
142510696SDavid.Hollister@Sun.COM 		return ("REGISTER_DEVICE");
142610696SDavid.Hollister@Sun.COM 		break;
142710696SDavid.Hollister@Sun.COM 	case PMCIN_SATA_HOST_IO_START:
142810696SDavid.Hollister@Sun.COM 		return ("SATA_HOST_IO_START");
142910696SDavid.Hollister@Sun.COM 		break;
143010696SDavid.Hollister@Sun.COM 	case PMCIN_SATA_ABORT:
143110696SDavid.Hollister@Sun.COM 		return ("SATA_ABORT");
143210696SDavid.Hollister@Sun.COM 		break;
143310696SDavid.Hollister@Sun.COM 	case PMCIN_LOCAL_PHY_CONTROL:
143410696SDavid.Hollister@Sun.COM 		return ("LOCAL_PHY_CONTROL");
143510696SDavid.Hollister@Sun.COM 		break;
143610696SDavid.Hollister@Sun.COM 	case PMCIN_GET_DEVICE_INFO:
143710696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_INFO");
143810696SDavid.Hollister@Sun.COM 		break;
143910696SDavid.Hollister@Sun.COM 	case PMCIN_TWI:
144010696SDavid.Hollister@Sun.COM 		return ("TWI");
144110696SDavid.Hollister@Sun.COM 		break;
144210696SDavid.Hollister@Sun.COM 	case PMCIN_FW_FLASH_UPDATE:
144310696SDavid.Hollister@Sun.COM 		return ("FW_FLASH_UPDATE");
144410696SDavid.Hollister@Sun.COM 		break;
144510696SDavid.Hollister@Sun.COM 	case PMCIN_SET_VPD:
144610696SDavid.Hollister@Sun.COM 		return ("SET_VPD");
144710696SDavid.Hollister@Sun.COM 		break;
144810696SDavid.Hollister@Sun.COM 	case PMCIN_GPIO:
144910696SDavid.Hollister@Sun.COM 		return ("GPIO");
145010696SDavid.Hollister@Sun.COM 		break;
145110696SDavid.Hollister@Sun.COM 	case PMCIN_SAS_DIAG_MODE_START_END:
145210696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_MODE_START_END");
145310696SDavid.Hollister@Sun.COM 		break;
145410696SDavid.Hollister@Sun.COM 	case PMCIN_SAS_DIAG_EXECUTE:
145510696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_EXECUTE");
145610696SDavid.Hollister@Sun.COM 		break;
145710696SDavid.Hollister@Sun.COM 	case PMCIN_SAW_HW_EVENT_ACK:
145810696SDavid.Hollister@Sun.COM 		return ("SAS_HW_EVENT_ACK");
145910696SDavid.Hollister@Sun.COM 		break;
146010696SDavid.Hollister@Sun.COM 	case PMCIN_GET_TIME_STAMP:
146110696SDavid.Hollister@Sun.COM 		return ("GET_TIME_STAMP");
146210696SDavid.Hollister@Sun.COM 		break;
146310696SDavid.Hollister@Sun.COM 	case PMCIN_PORT_CONTROL:
146410696SDavid.Hollister@Sun.COM 		return ("PORT_CONTROL");
146510696SDavid.Hollister@Sun.COM 		break;
146610696SDavid.Hollister@Sun.COM 	case PMCIN_GET_NVMD_DATA:
146710696SDavid.Hollister@Sun.COM 		return ("GET_NVMD_DATA");
146810696SDavid.Hollister@Sun.COM 		break;
146910696SDavid.Hollister@Sun.COM 	case PMCIN_SET_NVMD_DATA:
147010696SDavid.Hollister@Sun.COM 		return ("SET_NVMD_DATA");
147110696SDavid.Hollister@Sun.COM 		break;
147210696SDavid.Hollister@Sun.COM 	case PMCIN_SET_DEVICE_STATE:
147310696SDavid.Hollister@Sun.COM 		return ("SET_DEVICE_STATE");
147410696SDavid.Hollister@Sun.COM 		break;
147510696SDavid.Hollister@Sun.COM 	case PMCIN_GET_DEVICE_STATE:
147610696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_STATE");
147710696SDavid.Hollister@Sun.COM 		break;
147810696SDavid.Hollister@Sun.COM 	default:
147910696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
148010696SDavid.Hollister@Sun.COM 		break;
148110696SDavid.Hollister@Sun.COM 	}
148210696SDavid.Hollister@Sun.COM }
148310696SDavid.Hollister@Sun.COM 
148410696SDavid.Hollister@Sun.COM static char *
148510696SDavid.Hollister@Sun.COM outbound_iomb_opcode(uint32_t opcode)
148610696SDavid.Hollister@Sun.COM {
148710696SDavid.Hollister@Sun.COM 	switch (opcode) {
148810696SDavid.Hollister@Sun.COM 	case PMCOUT_ECHO:
148910696SDavid.Hollister@Sun.COM 		return ("ECHO");
149010696SDavid.Hollister@Sun.COM 		break;
149110696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_INFO:
149210696SDavid.Hollister@Sun.COM 		return ("GET_INFO");
149310696SDavid.Hollister@Sun.COM 		break;
149410696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_VPD:
149510696SDavid.Hollister@Sun.COM 		return ("GET_VPD");
149610696SDavid.Hollister@Sun.COM 		break;
149710696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_HW_EVENT:
149810696SDavid.Hollister@Sun.COM 		return ("SAS_HW_EVENT");
149910696SDavid.Hollister@Sun.COM 		break;
150010696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_COMPLETION:
150110696SDavid.Hollister@Sun.COM 		return ("SSP_COMPLETION");
150210696SDavid.Hollister@Sun.COM 		break;
150310696SDavid.Hollister@Sun.COM 	case PMCOUT_SMP_COMPLETION:
150410696SDavid.Hollister@Sun.COM 		return ("SMP_COMPLETION");
150510696SDavid.Hollister@Sun.COM 		break;
150610696SDavid.Hollister@Sun.COM 	case PMCOUT_LOCAL_PHY_CONTROL:
150710696SDavid.Hollister@Sun.COM 		return ("LOCAL_PHY_CONTROL");
150810696SDavid.Hollister@Sun.COM 		break;
150910696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT:
151010696SDavid.Hollister@Sun.COM 		return ("SAS_ASSISTED_DISCOVERY_SENT");
151110696SDavid.Hollister@Sun.COM 		break;
151210696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT:
151310696SDavid.Hollister@Sun.COM 		return ("SATA_ASSISTED_DISCOVERY_SENT");
151410696SDavid.Hollister@Sun.COM 		break;
151510696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_REGISTRATION:
151610696SDavid.Hollister@Sun.COM 		return ("DEVICE_REGISTRATION");
151710696SDavid.Hollister@Sun.COM 		break;
151810696SDavid.Hollister@Sun.COM 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
151910696SDavid.Hollister@Sun.COM 		return ("DEREGISTER_DEVICE_HANDLE");
152010696SDavid.Hollister@Sun.COM 		break;
152110696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_DEVICE_HANDLE:
152210696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_HANDLE");
152310696SDavid.Hollister@Sun.COM 		break;
152410696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_COMPLETION:
152510696SDavid.Hollister@Sun.COM 		return ("SATA_COMPLETION");
152610696SDavid.Hollister@Sun.COM 		break;
152710696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_EVENT:
152810696SDavid.Hollister@Sun.COM 		return ("SATA_EVENT");
152910696SDavid.Hollister@Sun.COM 		break;
153010696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_EVENT:
153110696SDavid.Hollister@Sun.COM 		return ("SSP_EVENT");
153210696SDavid.Hollister@Sun.COM 		break;
153310696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
153410696SDavid.Hollister@Sun.COM 		return ("DEVICE_HANDLE_ARRIVED");
153510696SDavid.Hollister@Sun.COM 		break;
153610696SDavid.Hollister@Sun.COM 	case PMCOUT_SMP_REQUEST_RECEIVED:
153710696SDavid.Hollister@Sun.COM 		return ("SMP_REQUEST_RECEIVED");
153810696SDavid.Hollister@Sun.COM 		break;
153910696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_REQUEST_RECEIVED:
154010696SDavid.Hollister@Sun.COM 		return ("SSP_REQUEST_RECEIVED");
154110696SDavid.Hollister@Sun.COM 		break;
154210696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_INFO:
154310696SDavid.Hollister@Sun.COM 		return ("DEVICE_INFO");
154410696SDavid.Hollister@Sun.COM 		break;
154510696SDavid.Hollister@Sun.COM 	case PMCOUT_FW_FLASH_UPDATE:
154610696SDavid.Hollister@Sun.COM 		return ("FW_FLASH_UPDATE");
154710696SDavid.Hollister@Sun.COM 		break;
154810696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_VPD:
154910696SDavid.Hollister@Sun.COM 		return ("SET_VPD");
155010696SDavid.Hollister@Sun.COM 		break;
155110696SDavid.Hollister@Sun.COM 	case PMCOUT_GPIO:
155210696SDavid.Hollister@Sun.COM 		return ("GPIO");
155310696SDavid.Hollister@Sun.COM 		break;
155410696SDavid.Hollister@Sun.COM 	case PMCOUT_GPIO_EVENT:
155510696SDavid.Hollister@Sun.COM 		return ("GPIO_EVENT");
155610696SDavid.Hollister@Sun.COM 		break;
155710696SDavid.Hollister@Sun.COM 	case PMCOUT_GENERAL_EVENT:
155810696SDavid.Hollister@Sun.COM 		return ("GENERAL_EVENT");
155910696SDavid.Hollister@Sun.COM 		break;
156010696SDavid.Hollister@Sun.COM 	case PMCOUT_TWI:
156110696SDavid.Hollister@Sun.COM 		return ("TWI");
156210696SDavid.Hollister@Sun.COM 		break;
156310696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_ABORT:
156410696SDavid.Hollister@Sun.COM 		return ("SSP_ABORT");
156510696SDavid.Hollister@Sun.COM 		break;
156610696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_ABORT:
156710696SDavid.Hollister@Sun.COM 		return ("SATA_ABORT");
156810696SDavid.Hollister@Sun.COM 		break;
156910696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_DIAG_MODE_START_END:
157010696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_MODE_START_END");
157110696SDavid.Hollister@Sun.COM 		break;
157210696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_DIAG_EXECUTE:
157310696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_EXECUTE");
157410696SDavid.Hollister@Sun.COM 		break;
157510696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_TIME_STAMP:
157610696SDavid.Hollister@Sun.COM 		return ("GET_TIME_STAMP");
157710696SDavid.Hollister@Sun.COM 		break;
157810696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_HW_EVENT_ACK_ACK:
157910696SDavid.Hollister@Sun.COM 		return ("SAS_HW_EVENT_ACK_ACK");
158010696SDavid.Hollister@Sun.COM 		break;
158110696SDavid.Hollister@Sun.COM 	case PMCOUT_PORT_CONTROL:
158210696SDavid.Hollister@Sun.COM 		return ("PORT_CONTROL");
158310696SDavid.Hollister@Sun.COM 		break;
158410696SDavid.Hollister@Sun.COM 	case PMCOUT_SKIP_ENTRIES:
158510696SDavid.Hollister@Sun.COM 		return ("SKIP_ENTRIES");
158610696SDavid.Hollister@Sun.COM 		break;
158710696SDavid.Hollister@Sun.COM 	case PMCOUT_SMP_ABORT:
158810696SDavid.Hollister@Sun.COM 		return ("SMP_ABORT");
158910696SDavid.Hollister@Sun.COM 		break;
159010696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_NVMD_DATA:
159110696SDavid.Hollister@Sun.COM 		return ("GET_NVMD_DATA");
159210696SDavid.Hollister@Sun.COM 		break;
159310696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_NVMD_DATA:
159410696SDavid.Hollister@Sun.COM 		return ("SET_NVMD_DATA");
159510696SDavid.Hollister@Sun.COM 		break;
159610696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_HANDLE_REMOVED:
159710696SDavid.Hollister@Sun.COM 		return ("DEVICE_HANDLE_REMOVED");
159810696SDavid.Hollister@Sun.COM 		break;
159910696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_DEVICE_STATE:
160010696SDavid.Hollister@Sun.COM 		return ("SET_DEVICE_STATE");
160110696SDavid.Hollister@Sun.COM 		break;
160210696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_DEVICE_STATE:
160310696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_STATE");
160410696SDavid.Hollister@Sun.COM 		break;
160510696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_DEVICE_INFO:
160610696SDavid.Hollister@Sun.COM 		return ("SET_DEVICE_INFO");
160710696SDavid.Hollister@Sun.COM 		break;
160810696SDavid.Hollister@Sun.COM 	default:
160910696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
161010696SDavid.Hollister@Sun.COM 		break;
161110696SDavid.Hollister@Sun.COM 	}
161210696SDavid.Hollister@Sun.COM }
161310696SDavid.Hollister@Sun.COM 
161410696SDavid.Hollister@Sun.COM static void
161510696SDavid.Hollister@Sun.COM dump_one_qentry_outbound(uint32_t *qentryp, int idx)
161610696SDavid.Hollister@Sun.COM {
161710696SDavid.Hollister@Sun.COM 	int qeidx;
161810696SDavid.Hollister@Sun.COM 	uint32_t word0 = LE_32(*qentryp);
161911601SDavid.Hollister@Sun.COM 	uint32_t word1 = LE_32(*(qentryp + 1));
162011601SDavid.Hollister@Sun.COM 	uint8_t iop_event;
162110696SDavid.Hollister@Sun.COM 
162210696SDavid.Hollister@Sun.COM 	mdb_printf("Entry #%02d\n", idx);
162310696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
162410696SDavid.Hollister@Sun.COM 
162510696SDavid.Hollister@Sun.COM 	mdb_printf("Header: 0x%08x (", word0);
162610696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_VALID) {
162710696SDavid.Hollister@Sun.COM 		mdb_printf("VALID, ");
162810696SDavid.Hollister@Sun.COM 	}
162910696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_HIPRI) {
163010696SDavid.Hollister@Sun.COM 		mdb_printf("HIPRI, ");
163110696SDavid.Hollister@Sun.COM 	}
163210696SDavid.Hollister@Sun.COM 	mdb_printf("OBID=%d, ",
163310696SDavid.Hollister@Sun.COM 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
163410696SDavid.Hollister@Sun.COM 	mdb_printf("CAT=%s, ",
163510696SDavid.Hollister@Sun.COM 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
163610696SDavid.Hollister@Sun.COM 	mdb_printf("OPCODE=%s",
163710696SDavid.Hollister@Sun.COM 	    outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
163811601SDavid.Hollister@Sun.COM 	if ((word0 & PMCS_IOMB_OPCODE_MASK) == PMCOUT_SAS_HW_EVENT) {
163911601SDavid.Hollister@Sun.COM 		iop_event = IOP_EVENT_EVENT(word1);
164011601SDavid.Hollister@Sun.COM 		mdb_printf(" <%s>", iomb_event(iop_event));
164111601SDavid.Hollister@Sun.COM 	}
164210696SDavid.Hollister@Sun.COM 	mdb_printf(")\n");
164310696SDavid.Hollister@Sun.COM 
164410696SDavid.Hollister@Sun.COM 	mdb_printf("Remaining Payload:\n");
164510696SDavid.Hollister@Sun.COM 
164610696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
164710696SDavid.Hollister@Sun.COM 	for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
164810696SDavid.Hollister@Sun.COM 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
164910696SDavid.Hollister@Sun.COM 	}
165010696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
165110696SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
165210696SDavid.Hollister@Sun.COM }
165310696SDavid.Hollister@Sun.COM 
165410696SDavid.Hollister@Sun.COM static void
165510696SDavid.Hollister@Sun.COM display_outbound_queues(struct pmcs_hw ss, uint_t verbose)
165610696SDavid.Hollister@Sun.COM {
165710696SDavid.Hollister@Sun.COM 	int		idx, qidx;
165810696SDavid.Hollister@Sun.COM 	uintptr_t	obqp;
165910696SDavid.Hollister@Sun.COM 	uint32_t	*cip;
166010696SDavid.Hollister@Sun.COM 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
166110696SDavid.Hollister@Sun.COM 	uint32_t	last_consumed, oqpi;
166210696SDavid.Hollister@Sun.COM 
166310696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
166410696SDavid.Hollister@Sun.COM 	mdb_printf("Outbound Queues\n");
166510696SDavid.Hollister@Sun.COM 	mdb_printf("---------------\n");
166610696SDavid.Hollister@Sun.COM 
166710696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
166810696SDavid.Hollister@Sun.COM 
166910696SDavid.Hollister@Sun.COM 	for (qidx = 0; qidx < PMCS_NOQ; qidx++) {
167010696SDavid.Hollister@Sun.COM 		obqp = (uintptr_t)ss.oqp[qidx];
167110696SDavid.Hollister@Sun.COM 
167210696SDavid.Hollister@Sun.COM 		if (obqp == NULL) {
167310696SDavid.Hollister@Sun.COM 			mdb_printf("No outbound queue ptr for queue #%d\n",
167410696SDavid.Hollister@Sun.COM 			    qidx);
167510696SDavid.Hollister@Sun.COM 			continue;
167610696SDavid.Hollister@Sun.COM 		}
167710696SDavid.Hollister@Sun.COM 
167810696SDavid.Hollister@Sun.COM 		mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx,
167910696SDavid.Hollister@Sun.COM 		    obq_type(qidx));
168010696SDavid.Hollister@Sun.COM 		/*
168110696SDavid.Hollister@Sun.COM 		 * Chip is the producer, so read the actual producer index
168210696SDavid.Hollister@Sun.COM 		 * and not the driver's version
168310696SDavid.Hollister@Sun.COM 		 */
168410696SDavid.Hollister@Sun.COM 		cip = (uint32_t *)((void *)ss.cip);
168510696SDavid.Hollister@Sun.COM 		if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET +
168610696SDavid.Hollister@Sun.COM 		    (qidx * 4)) == -1) {
168710696SDavid.Hollister@Sun.COM 			mdb_warn("Couldn't read oqpi\n");
168810696SDavid.Hollister@Sun.COM 			break;
168910696SDavid.Hollister@Sun.COM 		}
169010696SDavid.Hollister@Sun.COM 
169110696SDavid.Hollister@Sun.COM 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
169210696SDavid.Hollister@Sun.COM 		    LE_32(oqpi), ss.oqci[qidx]);
169310696SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
169410696SDavid.Hollister@Sun.COM 
169510696SDavid.Hollister@Sun.COM 		if (ss.oqci[qidx] == 0) {
169610696SDavid.Hollister@Sun.COM 			last_consumed = ss.ioq_depth - 1;
169710696SDavid.Hollister@Sun.COM 		} else {
169810696SDavid.Hollister@Sun.COM 			last_consumed = ss.oqci[qidx] - 1;
169910696SDavid.Hollister@Sun.COM 		}
170010696SDavid.Hollister@Sun.COM 
170110696SDavid.Hollister@Sun.COM 
170210696SDavid.Hollister@Sun.COM 		if (!verbose) {
170310696SDavid.Hollister@Sun.COM 			mdb_printf("Last processed entry:\n");
170410696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
170510696SDavid.Hollister@Sun.COM 			    (obqp + (PMCS_QENTRY_SIZE * last_consumed)))
170610696SDavid.Hollister@Sun.COM 			    == -1) {
170710696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
170810696SDavid.Hollister@Sun.COM 				    (obqp + (PMCS_QENTRY_SIZE *
170910696SDavid.Hollister@Sun.COM 				    last_consumed)));
171010696SDavid.Hollister@Sun.COM 				break;
171110696SDavid.Hollister@Sun.COM 			}
171210696SDavid.Hollister@Sun.COM 			dump_one_qentry_outbound(qentryp, last_consumed);
171310696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
171410696SDavid.Hollister@Sun.COM 			mdb_dec_indent(2);
171510696SDavid.Hollister@Sun.COM 			continue;
171610696SDavid.Hollister@Sun.COM 		}
171710696SDavid.Hollister@Sun.COM 
171810696SDavid.Hollister@Sun.COM 		for (idx = 0; idx < ss.ioq_depth; idx++) {
171910696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
172010696SDavid.Hollister@Sun.COM 			    (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
172110696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
172210696SDavid.Hollister@Sun.COM 				    (obqp + (PMCS_QENTRY_SIZE * idx)));
172310696SDavid.Hollister@Sun.COM 				break;
172410696SDavid.Hollister@Sun.COM 			}
172510696SDavid.Hollister@Sun.COM 			dump_one_qentry_outbound(qentryp, idx);
172610696SDavid.Hollister@Sun.COM 		}
172710696SDavid.Hollister@Sun.COM 
172810696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
172910696SDavid.Hollister@Sun.COM 		mdb_dec_indent(2);
173010696SDavid.Hollister@Sun.COM 	}
173110696SDavid.Hollister@Sun.COM 
173210696SDavid.Hollister@Sun.COM 	mdb_dec_indent(2);
173310696SDavid.Hollister@Sun.COM 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
173410696SDavid.Hollister@Sun.COM }
173510696SDavid.Hollister@Sun.COM 
173610696SDavid.Hollister@Sun.COM static void
173710696SDavid.Hollister@Sun.COM dump_one_qentry_inbound(uint32_t *qentryp, int idx)
173810696SDavid.Hollister@Sun.COM {
173910696SDavid.Hollister@Sun.COM 	int qeidx;
174010696SDavid.Hollister@Sun.COM 	uint32_t word0 = LE_32(*qentryp);
174110696SDavid.Hollister@Sun.COM 
174210696SDavid.Hollister@Sun.COM 	mdb_printf("Entry #%02d\n", idx);
174310696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
174410696SDavid.Hollister@Sun.COM 
174510696SDavid.Hollister@Sun.COM 	mdb_printf("Header: 0x%08x (", word0);
174610696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_VALID) {
174710696SDavid.Hollister@Sun.COM 		mdb_printf("VALID, ");
174810696SDavid.Hollister@Sun.COM 	}
174910696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_HIPRI) {
175010696SDavid.Hollister@Sun.COM 		mdb_printf("HIPRI, ");
175110696SDavid.Hollister@Sun.COM 	}
175210696SDavid.Hollister@Sun.COM 	mdb_printf("OBID=%d, ",
175310696SDavid.Hollister@Sun.COM 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
175410696SDavid.Hollister@Sun.COM 	mdb_printf("CAT=%s, ",
175510696SDavid.Hollister@Sun.COM 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
175610696SDavid.Hollister@Sun.COM 	mdb_printf("OPCODE=%s",
175710696SDavid.Hollister@Sun.COM 	    inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
175810696SDavid.Hollister@Sun.COM 	mdb_printf(")\n");
175910696SDavid.Hollister@Sun.COM 
176010696SDavid.Hollister@Sun.COM 	mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1)));
176110696SDavid.Hollister@Sun.COM 	mdb_printf("Remaining Payload:\n");
176210696SDavid.Hollister@Sun.COM 
176310696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
176410696SDavid.Hollister@Sun.COM 	for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
176510696SDavid.Hollister@Sun.COM 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
176610696SDavid.Hollister@Sun.COM 	}
176710696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
176810696SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
176910696SDavid.Hollister@Sun.COM }
177010696SDavid.Hollister@Sun.COM 
177110696SDavid.Hollister@Sun.COM static void
177210696SDavid.Hollister@Sun.COM display_inbound_queues(struct pmcs_hw ss, uint_t verbose)
177310696SDavid.Hollister@Sun.COM {
177410696SDavid.Hollister@Sun.COM 	int		idx, qidx, iqci, last_consumed;
177510696SDavid.Hollister@Sun.COM 	uintptr_t	ibqp;
177610696SDavid.Hollister@Sun.COM 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
177710696SDavid.Hollister@Sun.COM 	uint32_t	*cip;
177810696SDavid.Hollister@Sun.COM 
177910696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
178010696SDavid.Hollister@Sun.COM 	mdb_printf("Inbound Queues\n");
178110696SDavid.Hollister@Sun.COM 	mdb_printf("--------------\n");
178210696SDavid.Hollister@Sun.COM 
178310696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
178410696SDavid.Hollister@Sun.COM 
178510696SDavid.Hollister@Sun.COM 	for (qidx = 0; qidx < PMCS_NIQ; qidx++) {
178610696SDavid.Hollister@Sun.COM 		ibqp = (uintptr_t)ss.iqp[qidx];
178710696SDavid.Hollister@Sun.COM 
178810696SDavid.Hollister@Sun.COM 		if (ibqp == NULL) {
178910696SDavid.Hollister@Sun.COM 			mdb_printf("No inbound queue ptr for queue #%d\n",
179010696SDavid.Hollister@Sun.COM 			    qidx);
179110696SDavid.Hollister@Sun.COM 			continue;
179210696SDavid.Hollister@Sun.COM 		}
179310696SDavid.Hollister@Sun.COM 
179410696SDavid.Hollister@Sun.COM 		mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx,
179510696SDavid.Hollister@Sun.COM 		    ibq_type(qidx));
179610696SDavid.Hollister@Sun.COM 
179710696SDavid.Hollister@Sun.COM 		cip = (uint32_t *)((void *)ss.cip);
179810696SDavid.Hollister@Sun.COM 		if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) {
179910696SDavid.Hollister@Sun.COM 			mdb_warn("Couldn't read iqci\n");
180010696SDavid.Hollister@Sun.COM 			break;
180110696SDavid.Hollister@Sun.COM 		}
180210696SDavid.Hollister@Sun.COM 		iqci = LE_32(iqci);
180310696SDavid.Hollister@Sun.COM 
180410696SDavid.Hollister@Sun.COM 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
180510696SDavid.Hollister@Sun.COM 		    ss.shadow_iqpi[qidx], iqci);
180610696SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
180710696SDavid.Hollister@Sun.COM 
180810696SDavid.Hollister@Sun.COM 		if (iqci == 0) {
180910696SDavid.Hollister@Sun.COM 			last_consumed = ss.ioq_depth - 1;
181010696SDavid.Hollister@Sun.COM 		} else {
181110696SDavid.Hollister@Sun.COM 			last_consumed = iqci - 1;
181210696SDavid.Hollister@Sun.COM 		}
181310696SDavid.Hollister@Sun.COM 
181410696SDavid.Hollister@Sun.COM 		if (!verbose) {
181510696SDavid.Hollister@Sun.COM 			mdb_printf("Last processed entry:\n");
181610696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
181710696SDavid.Hollister@Sun.COM 			    (ibqp + (PMCS_QENTRY_SIZE * last_consumed)))
181810696SDavid.Hollister@Sun.COM 			    == -1) {
181910696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
182010696SDavid.Hollister@Sun.COM 				    (ibqp + (PMCS_QENTRY_SIZE *
182110696SDavid.Hollister@Sun.COM 				    last_consumed)));
182210696SDavid.Hollister@Sun.COM 				break;
182310696SDavid.Hollister@Sun.COM 			}
182410696SDavid.Hollister@Sun.COM 			dump_one_qentry_inbound(qentryp, last_consumed);
182510696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
182610696SDavid.Hollister@Sun.COM 			mdb_dec_indent(2);
182710696SDavid.Hollister@Sun.COM 			continue;
182810696SDavid.Hollister@Sun.COM 		}
182910696SDavid.Hollister@Sun.COM 
183010696SDavid.Hollister@Sun.COM 		for (idx = 0; idx < ss.ioq_depth; idx++) {
183110696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
183210696SDavid.Hollister@Sun.COM 			    (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
183310696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
183410696SDavid.Hollister@Sun.COM 				    (ibqp + (PMCS_QENTRY_SIZE * idx)));
183510696SDavid.Hollister@Sun.COM 				break;
183610696SDavid.Hollister@Sun.COM 			}
183710696SDavid.Hollister@Sun.COM 			dump_one_qentry_inbound(qentryp, idx);
183810696SDavid.Hollister@Sun.COM 		}
183910696SDavid.Hollister@Sun.COM 
184010696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
184110696SDavid.Hollister@Sun.COM 		mdb_dec_indent(2);
184210696SDavid.Hollister@Sun.COM 	}
184310696SDavid.Hollister@Sun.COM 
184410696SDavid.Hollister@Sun.COM 	mdb_dec_indent(2);
184510696SDavid.Hollister@Sun.COM 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
184610696SDavid.Hollister@Sun.COM }
184710696SDavid.Hollister@Sun.COM 
184811601SDavid.Hollister@Sun.COM /*
184911601SDavid.Hollister@Sun.COM  * phy is our copy of the PHY structure.  phyp is the pointer to the actual
185011601SDavid.Hollister@Sun.COM  * kernel PHY data structure
185111601SDavid.Hollister@Sun.COM  */
185210696SDavid.Hollister@Sun.COM static void
185311601SDavid.Hollister@Sun.COM display_phy(struct pmcs_phy phy, struct pmcs_phy *phyp, int verbose,
185411601SDavid.Hollister@Sun.COM     int totals_only)
185510696SDavid.Hollister@Sun.COM {
185610696SDavid.Hollister@Sun.COM 	char		*dtype, *speed;
185710696SDavid.Hollister@Sun.COM 	char		*yes = "Yes";
185810696SDavid.Hollister@Sun.COM 	char		*no = "No";
185910696SDavid.Hollister@Sun.COM 	char		*cfgd = no;
186010696SDavid.Hollister@Sun.COM 	char		*apend = no;
186110696SDavid.Hollister@Sun.COM 	char		*asent = no;
186210696SDavid.Hollister@Sun.COM 	char		*dead = no;
186310696SDavid.Hollister@Sun.COM 	char		*changed = no;
186411601SDavid.Hollister@Sun.COM 	char		route_attr, route_method;
186510696SDavid.Hollister@Sun.COM 
186610696SDavid.Hollister@Sun.COM 	switch (phy.dtype) {
186710696SDavid.Hollister@Sun.COM 	case NOTHING:
186810696SDavid.Hollister@Sun.COM 		dtype = "None";
186910696SDavid.Hollister@Sun.COM 		break;
187010696SDavid.Hollister@Sun.COM 	case SATA:
187110696SDavid.Hollister@Sun.COM 		dtype = "SATA";
187210696SDavid.Hollister@Sun.COM 		if (phy.configured) {
187310696SDavid.Hollister@Sun.COM 			++sata_phys;
187410696SDavid.Hollister@Sun.COM 		}
187510696SDavid.Hollister@Sun.COM 		break;
187610696SDavid.Hollister@Sun.COM 	case SAS:
187710696SDavid.Hollister@Sun.COM 		dtype = "SAS";
187810696SDavid.Hollister@Sun.COM 		if (phy.configured) {
187910696SDavid.Hollister@Sun.COM 			++sas_phys;
188010696SDavid.Hollister@Sun.COM 		}
188110696SDavid.Hollister@Sun.COM 		break;
188210696SDavid.Hollister@Sun.COM 	case EXPANDER:
188310696SDavid.Hollister@Sun.COM 		dtype = "EXP";
188410696SDavid.Hollister@Sun.COM 		if (phy.configured) {
188510696SDavid.Hollister@Sun.COM 			++exp_phys;
188610696SDavid.Hollister@Sun.COM 		}
188710696SDavid.Hollister@Sun.COM 		break;
188810696SDavid.Hollister@Sun.COM 	}
188910696SDavid.Hollister@Sun.COM 
189010696SDavid.Hollister@Sun.COM 	if (phy.dtype == NOTHING) {
189110696SDavid.Hollister@Sun.COM 		empty_phys++;
189210696SDavid.Hollister@Sun.COM 	} else if ((phy.dtype == EXPANDER) && phy.configured) {
189310696SDavid.Hollister@Sun.COM 		num_expanders++;
189410696SDavid.Hollister@Sun.COM 	}
189510696SDavid.Hollister@Sun.COM 
189610696SDavid.Hollister@Sun.COM 	if (totals_only) {
189710696SDavid.Hollister@Sun.COM 		return;
189810696SDavid.Hollister@Sun.COM 	}
189910696SDavid.Hollister@Sun.COM 
190010696SDavid.Hollister@Sun.COM 	switch (phy.link_rate) {
190110696SDavid.Hollister@Sun.COM 	case SAS_LINK_RATE_1_5GBIT:
190210696SDavid.Hollister@Sun.COM 		speed = "1.5Gb/s";
190310696SDavid.Hollister@Sun.COM 		break;
190410696SDavid.Hollister@Sun.COM 	case SAS_LINK_RATE_3GBIT:
190510696SDavid.Hollister@Sun.COM 		speed = "3 Gb/s";
190610696SDavid.Hollister@Sun.COM 		break;
190710696SDavid.Hollister@Sun.COM 	case SAS_LINK_RATE_6GBIT:
190810696SDavid.Hollister@Sun.COM 		speed = "6 Gb/s";
190910696SDavid.Hollister@Sun.COM 		break;
191010696SDavid.Hollister@Sun.COM 	default:
191110696SDavid.Hollister@Sun.COM 		speed = "N/A";
191210696SDavid.Hollister@Sun.COM 		break;
191310696SDavid.Hollister@Sun.COM 	}
191410696SDavid.Hollister@Sun.COM 
191510696SDavid.Hollister@Sun.COM 	if ((phy.dtype != NOTHING) || verbose) {
191610696SDavid.Hollister@Sun.COM 		print_sas_address(&phy);
191710696SDavid.Hollister@Sun.COM 
191810696SDavid.Hollister@Sun.COM 		if (phy.device_id != PMCS_INVALID_DEVICE_ID) {
191910696SDavid.Hollister@Sun.COM 			mdb_printf(" %3d %4d %6s %4s ",
192010696SDavid.Hollister@Sun.COM 			    phy.device_id, phy.phynum, speed, dtype);
192110696SDavid.Hollister@Sun.COM 		} else {
192210696SDavid.Hollister@Sun.COM 			mdb_printf(" N/A %4d %6s %4s ",
192310696SDavid.Hollister@Sun.COM 			    phy.phynum, speed, dtype);
192410696SDavid.Hollister@Sun.COM 		}
192510696SDavid.Hollister@Sun.COM 
192610696SDavid.Hollister@Sun.COM 		if (verbose) {
192710696SDavid.Hollister@Sun.COM 			if (phy.abort_sent) {
192810696SDavid.Hollister@Sun.COM 				asent = yes;
192910696SDavid.Hollister@Sun.COM 			}
193010696SDavid.Hollister@Sun.COM 			if (phy.abort_pending) {
193110696SDavid.Hollister@Sun.COM 				apend = yes;
193210696SDavid.Hollister@Sun.COM 			}
193310696SDavid.Hollister@Sun.COM 			if (phy.configured) {
193410696SDavid.Hollister@Sun.COM 				cfgd = yes;
193510696SDavid.Hollister@Sun.COM 			}
193610696SDavid.Hollister@Sun.COM 			if (phy.dead) {
193710696SDavid.Hollister@Sun.COM 				dead = yes;
193810696SDavid.Hollister@Sun.COM 			}
193910696SDavid.Hollister@Sun.COM 			if (phy.changed) {
194010696SDavid.Hollister@Sun.COM 				changed = yes;
194110696SDavid.Hollister@Sun.COM 			}
194210696SDavid.Hollister@Sun.COM 
194311601SDavid.Hollister@Sun.COM 			switch (phy.routing_attr) {
194411601SDavid.Hollister@Sun.COM 			case SMP_ROUTING_DIRECT:
194511601SDavid.Hollister@Sun.COM 				route_attr = 'D';
194611601SDavid.Hollister@Sun.COM 				break;
194711601SDavid.Hollister@Sun.COM 			case SMP_ROUTING_SUBTRACTIVE:
194811601SDavid.Hollister@Sun.COM 				route_attr = 'S';
194911601SDavid.Hollister@Sun.COM 				break;
195011601SDavid.Hollister@Sun.COM 			case SMP_ROUTING_TABLE:
195111601SDavid.Hollister@Sun.COM 				route_attr = 'T';
195211601SDavid.Hollister@Sun.COM 				break;
195311601SDavid.Hollister@Sun.COM 			default:
195411601SDavid.Hollister@Sun.COM 				route_attr = '?';
195511601SDavid.Hollister@Sun.COM 				break;
195611601SDavid.Hollister@Sun.COM 			}
195711601SDavid.Hollister@Sun.COM 
195811601SDavid.Hollister@Sun.COM 			switch (phy.routing_method) {
195911601SDavid.Hollister@Sun.COM 			case SMP_ROUTING_DIRECT:
196011601SDavid.Hollister@Sun.COM 				route_method = 'D';
196111601SDavid.Hollister@Sun.COM 				break;
196211601SDavid.Hollister@Sun.COM 			case SMP_ROUTING_SUBTRACTIVE:
196311601SDavid.Hollister@Sun.COM 				route_method = 'S';
196411601SDavid.Hollister@Sun.COM 				break;
196511601SDavid.Hollister@Sun.COM 			case SMP_ROUTING_TABLE:
196611601SDavid.Hollister@Sun.COM 				route_method = 'T';
196711601SDavid.Hollister@Sun.COM 				break;
196811601SDavid.Hollister@Sun.COM 			default:
196911601SDavid.Hollister@Sun.COM 				route_attr = '?';
197011601SDavid.Hollister@Sun.COM 				break;
197111601SDavid.Hollister@Sun.COM 			}
197211601SDavid.Hollister@Sun.COM 
197311601SDavid.Hollister@Sun.COM 			mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d "
197411601SDavid.Hollister@Sun.COM 			    "%1d 0x%p ", cfgd, apend, asent, changed, dead,
197511601SDavid.Hollister@Sun.COM 			    phy.ref_count, route_attr, route_method,
197611601SDavid.Hollister@Sun.COM 			    phy.enum_attempts, phy.reenumerate, phy.phy_lock);
197710696SDavid.Hollister@Sun.COM 		}
197810696SDavid.Hollister@Sun.COM 
197910696SDavid.Hollister@Sun.COM 		mdb_printf("Path: %s\n", phy.path);
198011601SDavid.Hollister@Sun.COM 
198111601SDavid.Hollister@Sun.COM 		/*
198211601SDavid.Hollister@Sun.COM 		 * In verbose mode, on the next line print the drill down
198311601SDavid.Hollister@Sun.COM 		 * info to see either the DISCOVER response or the REPORT
198411601SDavid.Hollister@Sun.COM 		 * GENERAL response depending on the PHY's dtype
198511601SDavid.Hollister@Sun.COM 		 */
198611601SDavid.Hollister@Sun.COM 		if (verbose) {
198711601SDavid.Hollister@Sun.COM 			uintptr_t tphyp = (uintptr_t)phyp;
198811601SDavid.Hollister@Sun.COM 
198911601SDavid.Hollister@Sun.COM 			mdb_inc_indent(4);
199011601SDavid.Hollister@Sun.COM 			switch (phy.dtype) {
199111601SDavid.Hollister@Sun.COM 			case EXPANDER:
199211601SDavid.Hollister@Sun.COM 				if (!phy.configured) {
199311601SDavid.Hollister@Sun.COM 					break;
199411601SDavid.Hollister@Sun.COM 				}
199511601SDavid.Hollister@Sun.COM 				mdb_printf("REPORT GENERAL response: %p::"
199611601SDavid.Hollister@Sun.COM 				    "print smp_report_general_resp_t\n",
199711601SDavid.Hollister@Sun.COM 				    (tphyp + offsetof(struct pmcs_phy,
199811601SDavid.Hollister@Sun.COM 				    rg_resp)));
199911601SDavid.Hollister@Sun.COM 				break;
200011601SDavid.Hollister@Sun.COM 			case SAS:
200111601SDavid.Hollister@Sun.COM 			case SATA:
200211601SDavid.Hollister@Sun.COM 				mdb_printf("DISCOVER response: %p::"
200311601SDavid.Hollister@Sun.COM 				    "print smp_discover_resp_t\n",
200411601SDavid.Hollister@Sun.COM 				    (tphyp + offsetof(struct pmcs_phy,
200511601SDavid.Hollister@Sun.COM 				    disc_resp)));
200611601SDavid.Hollister@Sun.COM 				break;
200711601SDavid.Hollister@Sun.COM 			default:
200811601SDavid.Hollister@Sun.COM 				break;
200911601SDavid.Hollister@Sun.COM 			}
201011601SDavid.Hollister@Sun.COM 			mdb_dec_indent(4);
201111601SDavid.Hollister@Sun.COM 		}
201210696SDavid.Hollister@Sun.COM 	}
201310696SDavid.Hollister@Sun.COM }
201410696SDavid.Hollister@Sun.COM 
201510696SDavid.Hollister@Sun.COM static void
201610696SDavid.Hollister@Sun.COM display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level,
201710696SDavid.Hollister@Sun.COM     int totals_only)
201810696SDavid.Hollister@Sun.COM {
201910696SDavid.Hollister@Sun.COM 	pmcs_phy_t	phy;
202010696SDavid.Hollister@Sun.COM 	pmcs_phy_t	*pphy = parent;
202110696SDavid.Hollister@Sun.COM 
202210696SDavid.Hollister@Sun.COM 	mdb_inc_indent(3);
202310696SDavid.Hollister@Sun.COM 
202410696SDavid.Hollister@Sun.COM 	if (parent == NULL) {
202510696SDavid.Hollister@Sun.COM 		pphy = (pmcs_phy_t *)ss.root_phys;
202610696SDavid.Hollister@Sun.COM 	} else {
202710696SDavid.Hollister@Sun.COM 		pphy = (pmcs_phy_t *)parent;
202810696SDavid.Hollister@Sun.COM 	}
202910696SDavid.Hollister@Sun.COM 
203010696SDavid.Hollister@Sun.COM 	if (level == 0) {
203110696SDavid.Hollister@Sun.COM 		sas_phys = 0;
203210696SDavid.Hollister@Sun.COM 		sata_phys = 0;
203310696SDavid.Hollister@Sun.COM 		exp_phys = 0;
203410696SDavid.Hollister@Sun.COM 		num_expanders = 0;
203510696SDavid.Hollister@Sun.COM 		empty_phys = 0;
203610696SDavid.Hollister@Sun.COM 	}
203710696SDavid.Hollister@Sun.COM 
203810696SDavid.Hollister@Sun.COM 	if (!totals_only) {
203910696SDavid.Hollister@Sun.COM 		if (level == 0) {
204010696SDavid.Hollister@Sun.COM 			mdb_printf("PHY information\n");
204110696SDavid.Hollister@Sun.COM 		}
204210696SDavid.Hollister@Sun.COM 		mdb_printf("--------\n");
204310696SDavid.Hollister@Sun.COM 		mdb_printf("Level %2d\n", level);
204410696SDavid.Hollister@Sun.COM 		mdb_printf("--------\n");
204510696SDavid.Hollister@Sun.COM 		mdb_printf("SAS Address      Hdl Phy#  Speed Type ");
204610696SDavid.Hollister@Sun.COM 
204710696SDavid.Hollister@Sun.COM 		if (verbose) {
204811601SDavid.Hollister@Sun.COM 			mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R "
204911601SDavid.Hollister@Sun.COM 			    "Lock\n");
205010696SDavid.Hollister@Sun.COM 		} else {
205110696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
205210696SDavid.Hollister@Sun.COM 		}
205310696SDavid.Hollister@Sun.COM 	}
205410696SDavid.Hollister@Sun.COM 
205510696SDavid.Hollister@Sun.COM 	while (pphy) {
205610696SDavid.Hollister@Sun.COM 		if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) {
205710696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_phy_t, phy);
205810696SDavid.Hollister@Sun.COM 			break;
205910696SDavid.Hollister@Sun.COM 		}
206010696SDavid.Hollister@Sun.COM 
206111601SDavid.Hollister@Sun.COM 		display_phy(phy, pphy, verbose, totals_only);
206210696SDavid.Hollister@Sun.COM 
206310696SDavid.Hollister@Sun.COM 		if (phy.children) {
206410696SDavid.Hollister@Sun.COM 			display_phys(ss, verbose, phy.children, level + 1,
206510696SDavid.Hollister@Sun.COM 			    totals_only);
206610696SDavid.Hollister@Sun.COM 			if (!totals_only) {
206710696SDavid.Hollister@Sun.COM 				mdb_printf("\n");
206810696SDavid.Hollister@Sun.COM 			}
206910696SDavid.Hollister@Sun.COM 		}
207010696SDavid.Hollister@Sun.COM 
207110696SDavid.Hollister@Sun.COM 		pphy = phy.sibling;
207210696SDavid.Hollister@Sun.COM 	}
207310696SDavid.Hollister@Sun.COM 
207410696SDavid.Hollister@Sun.COM 	mdb_dec_indent(3);
207510696SDavid.Hollister@Sun.COM 
207610696SDavid.Hollister@Sun.COM 	if (level == 0) {
207710696SDavid.Hollister@Sun.COM 		if (verbose) {
207810696SDavid.Hollister@Sun.COM 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
207910696SDavid.Hollister@Sun.COM 			    "(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
208010696SDavid.Hollister@Sun.COM 			    (sas_phys + sata_phys + num_expanders),
208110696SDavid.Hollister@Sun.COM 			    sas_phys, sata_phys, num_expanders,
208210696SDavid.Hollister@Sun.COM 			    (exp_phys - num_expanders), empty_phys);
208310696SDavid.Hollister@Sun.COM 		} else {
208410696SDavid.Hollister@Sun.COM 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
208510696SDavid.Hollister@Sun.COM 			    "Occupied PHYs:",
208610696SDavid.Hollister@Sun.COM 			    (sas_phys + sata_phys + num_expanders),
208710696SDavid.Hollister@Sun.COM 			    sas_phys, sata_phys, num_expanders);
208810696SDavid.Hollister@Sun.COM 		}
208910696SDavid.Hollister@Sun.COM 	}
209010696SDavid.Hollister@Sun.COM }
209110696SDavid.Hollister@Sun.COM 
209210696SDavid.Hollister@Sun.COM /*
209311048SDavid.Hollister@Sun.COM  * filter is used to indicate whether we are filtering log messages based
209411048SDavid.Hollister@Sun.COM  * on "instance".  The other filtering (based on options) depends on the
209511048SDavid.Hollister@Sun.COM  * values that are passed in for "sas_addr" and "phy_path".
209611048SDavid.Hollister@Sun.COM  *
209710696SDavid.Hollister@Sun.COM  * MAX_INST_STRLEN is the largest string size from which we will attempt
209810696SDavid.Hollister@Sun.COM  * to convert to an instance number.  The string will be formed up as
209910696SDavid.Hollister@Sun.COM  * "0t<inst>\0" so that mdb_strtoull can parse it properly.
210010696SDavid.Hollister@Sun.COM  */
210110696SDavid.Hollister@Sun.COM #define	MAX_INST_STRLEN	8
210210696SDavid.Hollister@Sun.COM 
210310696SDavid.Hollister@Sun.COM static int
210411347SRamana.Srikanth@Sun.COM pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines,
2105*12120SDavid.Hollister@Sun.COM     const char *phy_path, uint64_t sas_address, uint64_t verbose)
210610696SDavid.Hollister@Sun.COM {
210710696SDavid.Hollister@Sun.COM 	pmcs_tbuf_t *tbuf_addr;
210810696SDavid.Hollister@Sun.COM 	uint_t tbuf_idx;
210910696SDavid.Hollister@Sun.COM 	pmcs_tbuf_t tbuf;
211010696SDavid.Hollister@Sun.COM 	boolean_t wrap, elem_filtered;
211110696SDavid.Hollister@Sun.COM 	uint_t start_idx, elems_to_print, idx, tbuf_num_elems;
211210696SDavid.Hollister@Sun.COM 	char *bufp;
211310696SDavid.Hollister@Sun.COM 	char elem_inst[MAX_INST_STRLEN], ei_idx;
211411048SDavid.Hollister@Sun.COM 	uint64_t sas_addr;
211511048SDavid.Hollister@Sun.COM 	uint8_t *sas_addressp;
211610696SDavid.Hollister@Sun.COM 
211710696SDavid.Hollister@Sun.COM 	/* Get the address of the first element */
211810696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) {
211910696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf");
212010696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
212110696SDavid.Hollister@Sun.COM 	}
212210696SDavid.Hollister@Sun.COM 
212310696SDavid.Hollister@Sun.COM 	/* Get the total number */
212410696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) {
212510696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf_num_elems");
212610696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
212710696SDavid.Hollister@Sun.COM 	}
212810696SDavid.Hollister@Sun.COM 
212910696SDavid.Hollister@Sun.COM 	/* Get the current index */
213010696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) {
213110696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf_idx");
213210696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
213310696SDavid.Hollister@Sun.COM 	}
213410696SDavid.Hollister@Sun.COM 
213510696SDavid.Hollister@Sun.COM 	/* Indicator as to whether the buffer has wrapped */
213610696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) {
213710696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf_wrap");
213810696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
213910696SDavid.Hollister@Sun.COM 	}
214010696SDavid.Hollister@Sun.COM 
214111048SDavid.Hollister@Sun.COM 	/*
214211048SDavid.Hollister@Sun.COM 	 * On little-endian systems, the SAS address passed in will be
214311048SDavid.Hollister@Sun.COM 	 * byte swapped.  Take care of that here.
214411048SDavid.Hollister@Sun.COM 	 */
214511048SDavid.Hollister@Sun.COM #if defined(_LITTLE_ENDIAN)
214611048SDavid.Hollister@Sun.COM 	sas_addr = ((sas_address << 56) |
214711048SDavid.Hollister@Sun.COM 	    ((sas_address << 40) & 0xff000000000000ULL) |
214811048SDavid.Hollister@Sun.COM 	    ((sas_address << 24) & 0xff0000000000ULL) |
214911048SDavid.Hollister@Sun.COM 	    ((sas_address << 8)  & 0xff00000000ULL) |
215011048SDavid.Hollister@Sun.COM 	    ((sas_address >> 8)  & 0xff000000ULL) |
215111048SDavid.Hollister@Sun.COM 	    ((sas_address >> 24) & 0xff0000ULL) |
215211048SDavid.Hollister@Sun.COM 	    ((sas_address >> 40) & 0xff00ULL) |
215311048SDavid.Hollister@Sun.COM 	    (sas_address  >> 56));
215411048SDavid.Hollister@Sun.COM #else
215511048SDavid.Hollister@Sun.COM 	sas_addr = sas_address;
215611048SDavid.Hollister@Sun.COM #endif
215711048SDavid.Hollister@Sun.COM 	sas_addressp = (uint8_t *)&sas_addr;
215811048SDavid.Hollister@Sun.COM 
215911347SRamana.Srikanth@Sun.COM 	/* Ensure the tail number isn't greater than the size of the log */
216011347SRamana.Srikanth@Sun.COM 	if (tail_lines > tbuf_num_elems) {
216111347SRamana.Srikanth@Sun.COM 		tail_lines = tbuf_num_elems;
216211347SRamana.Srikanth@Sun.COM 	}
216311347SRamana.Srikanth@Sun.COM 
216410696SDavid.Hollister@Sun.COM 	/* Figure out where we start and stop */
216510696SDavid.Hollister@Sun.COM 	if (wrap) {
216611347SRamana.Srikanth@Sun.COM 		if (tail_lines) {
216711347SRamana.Srikanth@Sun.COM 			/* Do we need to wrap backwards? */
216811347SRamana.Srikanth@Sun.COM 			if (tail_lines > tbuf_idx) {
216911347SRamana.Srikanth@Sun.COM 				start_idx = tbuf_num_elems - (tail_lines -
217011347SRamana.Srikanth@Sun.COM 				    tbuf_idx);
217111347SRamana.Srikanth@Sun.COM 			} else {
217211347SRamana.Srikanth@Sun.COM 				start_idx = tbuf_idx - tail_lines;
217311347SRamana.Srikanth@Sun.COM 			}
217411347SRamana.Srikanth@Sun.COM 			elems_to_print = tail_lines;
217511347SRamana.Srikanth@Sun.COM 		} else {
217611347SRamana.Srikanth@Sun.COM 			start_idx = tbuf_idx;
217711347SRamana.Srikanth@Sun.COM 			elems_to_print = tbuf_num_elems;
217811347SRamana.Srikanth@Sun.COM 		}
217910696SDavid.Hollister@Sun.COM 	} else {
218011347SRamana.Srikanth@Sun.COM 		if (tail_lines > tbuf_idx) {
218111347SRamana.Srikanth@Sun.COM 			tail_lines = tbuf_idx;
218211347SRamana.Srikanth@Sun.COM 		}
218311347SRamana.Srikanth@Sun.COM 		if (tail_lines) {
218411347SRamana.Srikanth@Sun.COM 			start_idx = tbuf_idx - tail_lines;
218511347SRamana.Srikanth@Sun.COM 			elems_to_print = tail_lines;
218611347SRamana.Srikanth@Sun.COM 		} else {
218711347SRamana.Srikanth@Sun.COM 			start_idx = 0;
218811347SRamana.Srikanth@Sun.COM 			elems_to_print = tbuf_idx;
218911347SRamana.Srikanth@Sun.COM 		}
219010696SDavid.Hollister@Sun.COM 	}
219110696SDavid.Hollister@Sun.COM 
219210696SDavid.Hollister@Sun.COM 	idx = start_idx;
219310696SDavid.Hollister@Sun.COM 
219410696SDavid.Hollister@Sun.COM 	/* Dump the buffer contents */
219510696SDavid.Hollister@Sun.COM 	while (elems_to_print != 0) {
219610696SDavid.Hollister@Sun.COM 		if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx))
219710696SDavid.Hollister@Sun.COM 		    == -1) {
219810696SDavid.Hollister@Sun.COM 			NOREAD(tbuf, (tbuf_addr + idx));
219910696SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
220010696SDavid.Hollister@Sun.COM 		}
220110696SDavid.Hollister@Sun.COM 
220211048SDavid.Hollister@Sun.COM 		/*
220311048SDavid.Hollister@Sun.COM 		 * Check for filtering on HBA instance
220411048SDavid.Hollister@Sun.COM 		 */
220510696SDavid.Hollister@Sun.COM 		elem_filtered = B_FALSE;
220610696SDavid.Hollister@Sun.COM 
220710696SDavid.Hollister@Sun.COM 		if (filter) {
220810696SDavid.Hollister@Sun.COM 			bufp = tbuf.buf;
220910696SDavid.Hollister@Sun.COM 			/* Skip the driver name */
221010696SDavid.Hollister@Sun.COM 			while (*bufp < '0' || *bufp > '9') {
221110696SDavid.Hollister@Sun.COM 				bufp++;
221210696SDavid.Hollister@Sun.COM 			}
221310696SDavid.Hollister@Sun.COM 
221410696SDavid.Hollister@Sun.COM 			ei_idx = 0;
221510696SDavid.Hollister@Sun.COM 			elem_inst[ei_idx++] = '0';
221610696SDavid.Hollister@Sun.COM 			elem_inst[ei_idx++] = 't';
221710696SDavid.Hollister@Sun.COM 			while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) {
221810696SDavid.Hollister@Sun.COM 				elem_inst[ei_idx++] = *bufp;
221910696SDavid.Hollister@Sun.COM 				bufp++;
222010696SDavid.Hollister@Sun.COM 			}
222110696SDavid.Hollister@Sun.COM 			elem_inst[ei_idx] = 0;
222210696SDavid.Hollister@Sun.COM 
222310696SDavid.Hollister@Sun.COM 			/* Get the instance */
222410696SDavid.Hollister@Sun.COM 			if ((int)mdb_strtoull(elem_inst) != instance) {
222510696SDavid.Hollister@Sun.COM 				elem_filtered = B_TRUE;
222610696SDavid.Hollister@Sun.COM 			}
222710696SDavid.Hollister@Sun.COM 		}
222810696SDavid.Hollister@Sun.COM 
222911048SDavid.Hollister@Sun.COM 		if (!elem_filtered && (phy_path || sas_address)) {
223011048SDavid.Hollister@Sun.COM 			/*
223111048SDavid.Hollister@Sun.COM 			 * This message is not being filtered by HBA instance.
223211048SDavid.Hollister@Sun.COM 			 * Now check to see if we're filtering based on
223311048SDavid.Hollister@Sun.COM 			 * PHY path or SAS address.
223411048SDavid.Hollister@Sun.COM 			 * Filtering is an "OR" operation.  So, if any of the
223511048SDavid.Hollister@Sun.COM 			 * criteria matches, this message will be printed.
223611048SDavid.Hollister@Sun.COM 			 */
223711048SDavid.Hollister@Sun.COM 			elem_filtered = B_TRUE;
223811048SDavid.Hollister@Sun.COM 
223911048SDavid.Hollister@Sun.COM 			if (phy_path != NULL) {
224011048SDavid.Hollister@Sun.COM 				if (strncmp(phy_path, tbuf.phy_path,
224111048SDavid.Hollister@Sun.COM 				    PMCS_TBUF_UA_MAX_SIZE) == 0) {
224211048SDavid.Hollister@Sun.COM 					elem_filtered = B_FALSE;
224311048SDavid.Hollister@Sun.COM 				}
224411048SDavid.Hollister@Sun.COM 			}
224511048SDavid.Hollister@Sun.COM 			if (sas_address != 0) {
224611048SDavid.Hollister@Sun.COM 				if (memcmp(sas_addressp, tbuf.phy_sas_address,
224711048SDavid.Hollister@Sun.COM 				    8) == 0) {
224811048SDavid.Hollister@Sun.COM 					elem_filtered = B_FALSE;
224911048SDavid.Hollister@Sun.COM 				}
225011048SDavid.Hollister@Sun.COM 			}
225111048SDavid.Hollister@Sun.COM 		}
225211048SDavid.Hollister@Sun.COM 
225310696SDavid.Hollister@Sun.COM 		if (!elem_filtered) {
2254*12120SDavid.Hollister@Sun.COM 			/*
2255*12120SDavid.Hollister@Sun.COM 			 * If the -v flag was given, print the firmware
2256*12120SDavid.Hollister@Sun.COM 			 * timestamp along with the clock time
2257*12120SDavid.Hollister@Sun.COM 			 */
2258*12120SDavid.Hollister@Sun.COM 			mdb_printf("%Y.%09ld ", tbuf.timestamp);
2259*12120SDavid.Hollister@Sun.COM 			if (verbose) {
2260*12120SDavid.Hollister@Sun.COM 				mdb_printf("(0x%" PRIx64 ") ",
2261*12120SDavid.Hollister@Sun.COM 				    tbuf.fw_timestamp);
2262*12120SDavid.Hollister@Sun.COM 			}
2263*12120SDavid.Hollister@Sun.COM 			mdb_printf("%s\n", tbuf.buf);
226410696SDavid.Hollister@Sun.COM 		}
226510696SDavid.Hollister@Sun.COM 
226610696SDavid.Hollister@Sun.COM 		--elems_to_print;
226710696SDavid.Hollister@Sun.COM 		if (++idx == tbuf_num_elems) {
226810696SDavid.Hollister@Sun.COM 			idx = 0;
226910696SDavid.Hollister@Sun.COM 		}
227010696SDavid.Hollister@Sun.COM 	}
227110696SDavid.Hollister@Sun.COM 
227210696SDavid.Hollister@Sun.COM 	return (DCMD_OK);
227310696SDavid.Hollister@Sun.COM }
227410696SDavid.Hollister@Sun.COM 
227510696SDavid.Hollister@Sun.COM /*
227610696SDavid.Hollister@Sun.COM  * Walkers
227710696SDavid.Hollister@Sun.COM  */
227810696SDavid.Hollister@Sun.COM static int
227910696SDavid.Hollister@Sun.COM targets_walk_i(mdb_walk_state_t *wsp)
228010696SDavid.Hollister@Sun.COM {
228110696SDavid.Hollister@Sun.COM 	if (wsp->walk_addr == NULL) {
228210696SDavid.Hollister@Sun.COM 		mdb_warn("Can not perform global walk\n");
228310696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
228410696SDavid.Hollister@Sun.COM 	}
228510696SDavid.Hollister@Sun.COM 
228610696SDavid.Hollister@Sun.COM 	/*
228710696SDavid.Hollister@Sun.COM 	 * Address provided belongs to HBA softstate.  Get the targets pointer
228810696SDavid.Hollister@Sun.COM 	 * to begin the walk.
228910696SDavid.Hollister@Sun.COM 	 */
229010696SDavid.Hollister@Sun.COM 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
229110696SDavid.Hollister@Sun.COM 	    sizeof (pmcs_hw_t)) {
229210696SDavid.Hollister@Sun.COM 		mdb_warn("Unable to read HBA softstate\n");
229310696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
229410696SDavid.Hollister@Sun.COM 	}
229510696SDavid.Hollister@Sun.COM 
229610696SDavid.Hollister@Sun.COM 	if (targets == NULL) {
229710696SDavid.Hollister@Sun.COM 		targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP);
229810696SDavid.Hollister@Sun.COM 	}
229910696SDavid.Hollister@Sun.COM 
230010696SDavid.Hollister@Sun.COM 	if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) {
230110696SDavid.Hollister@Sun.COM 		NOREAD(targets, ss.targets);
230210696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
230310696SDavid.Hollister@Sun.COM 	}
230410696SDavid.Hollister@Sun.COM 
230510696SDavid.Hollister@Sun.COM 	target_idx = 0;
230610696SDavid.Hollister@Sun.COM 	wsp->walk_addr = (uintptr_t)(targets[0]);
230710696SDavid.Hollister@Sun.COM 	wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP);
230810696SDavid.Hollister@Sun.COM 
230910696SDavid.Hollister@Sun.COM 	return (WALK_NEXT);
231010696SDavid.Hollister@Sun.COM }
231110696SDavid.Hollister@Sun.COM 
231210696SDavid.Hollister@Sun.COM static int
231310696SDavid.Hollister@Sun.COM targets_walk_s(mdb_walk_state_t *wsp)
231410696SDavid.Hollister@Sun.COM {
231510696SDavid.Hollister@Sun.COM 	int status;
231610696SDavid.Hollister@Sun.COM 
231710696SDavid.Hollister@Sun.COM 	if (target_idx == ss.max_dev) {
231810696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
231910696SDavid.Hollister@Sun.COM 	}
232010696SDavid.Hollister@Sun.COM 
232110696SDavid.Hollister@Sun.COM 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t),
232210696SDavid.Hollister@Sun.COM 	    wsp->walk_addr) == -1) {
232310696SDavid.Hollister@Sun.COM 		mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr);
232410696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
232510696SDavid.Hollister@Sun.COM 	}
232610696SDavid.Hollister@Sun.COM 
232710696SDavid.Hollister@Sun.COM 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
232810696SDavid.Hollister@Sun.COM 	    wsp->walk_cbdata);
232910696SDavid.Hollister@Sun.COM 
233010696SDavid.Hollister@Sun.COM 	do {
233110696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)(targets[++target_idx]);
233210696SDavid.Hollister@Sun.COM 	} while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev));
233310696SDavid.Hollister@Sun.COM 
233410696SDavid.Hollister@Sun.COM 	if (target_idx == ss.max_dev) {
233510696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
233610696SDavid.Hollister@Sun.COM 	}
233710696SDavid.Hollister@Sun.COM 
233810696SDavid.Hollister@Sun.COM 	return (status);
233910696SDavid.Hollister@Sun.COM }
234010696SDavid.Hollister@Sun.COM 
234110696SDavid.Hollister@Sun.COM static void
234210696SDavid.Hollister@Sun.COM targets_walk_f(mdb_walk_state_t *wsp)
234310696SDavid.Hollister@Sun.COM {
234410696SDavid.Hollister@Sun.COM 	mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t));
234510696SDavid.Hollister@Sun.COM }
234610696SDavid.Hollister@Sun.COM 
234710696SDavid.Hollister@Sun.COM 
234810696SDavid.Hollister@Sun.COM static pmcs_phy_t *
234910696SDavid.Hollister@Sun.COM pmcs_next_sibling(pmcs_phy_t *phyp)
235010696SDavid.Hollister@Sun.COM {
235110696SDavid.Hollister@Sun.COM 	pmcs_phy_t parent;
235210696SDavid.Hollister@Sun.COM 
235310696SDavid.Hollister@Sun.COM 	/*
235410696SDavid.Hollister@Sun.COM 	 * First, if this is a root PHY, there are no more siblings
235510696SDavid.Hollister@Sun.COM 	 */
235610696SDavid.Hollister@Sun.COM 	if (phyp->level == 0) {
235710696SDavid.Hollister@Sun.COM 		return (NULL);
235810696SDavid.Hollister@Sun.COM 	}
235910696SDavid.Hollister@Sun.COM 
236010696SDavid.Hollister@Sun.COM 	/*
236110696SDavid.Hollister@Sun.COM 	 * Otherwise, next sibling is the parent's sibling
236210696SDavid.Hollister@Sun.COM 	 */
236310696SDavid.Hollister@Sun.COM 	while (phyp->level > 0) {
236410696SDavid.Hollister@Sun.COM 		if (mdb_vread(&parent, sizeof (pmcs_phy_t),
236510696SDavid.Hollister@Sun.COM 		    (uintptr_t)phyp->parent) == -1) {
236610696SDavid.Hollister@Sun.COM 			mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
236710696SDavid.Hollister@Sun.COM 			    (void *)phyp->parent);
236810696SDavid.Hollister@Sun.COM 			return (NULL);
236910696SDavid.Hollister@Sun.COM 		}
237010696SDavid.Hollister@Sun.COM 
237110696SDavid.Hollister@Sun.COM 		if (parent.sibling != NULL) {
237210696SDavid.Hollister@Sun.COM 			break;
237310696SDavid.Hollister@Sun.COM 		}
237410696SDavid.Hollister@Sun.COM 
237511898SJesse.Butler@Sun.COM 		/*
237611898SJesse.Butler@Sun.COM 		 * If this PHY's sibling is NULL and it's a root phy,
237711898SJesse.Butler@Sun.COM 		 * we're done.
237811898SJesse.Butler@Sun.COM 		 */
237911898SJesse.Butler@Sun.COM 		if (parent.level == 0) {
238011898SJesse.Butler@Sun.COM 			return (NULL);
238111898SJesse.Butler@Sun.COM 		}
238211898SJesse.Butler@Sun.COM 
238310696SDavid.Hollister@Sun.COM 		phyp = phyp->parent;
238410696SDavid.Hollister@Sun.COM 	}
238510696SDavid.Hollister@Sun.COM 
238610696SDavid.Hollister@Sun.COM 	return (parent.sibling);
238710696SDavid.Hollister@Sun.COM }
238810696SDavid.Hollister@Sun.COM 
238910696SDavid.Hollister@Sun.COM static int
239010696SDavid.Hollister@Sun.COM phy_walk_i(mdb_walk_state_t *wsp)
239110696SDavid.Hollister@Sun.COM {
239210696SDavid.Hollister@Sun.COM 	if (wsp->walk_addr == NULL) {
239310696SDavid.Hollister@Sun.COM 		mdb_warn("Can not perform global walk\n");
239410696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
239510696SDavid.Hollister@Sun.COM 	}
239610696SDavid.Hollister@Sun.COM 
239710696SDavid.Hollister@Sun.COM 	/*
239810696SDavid.Hollister@Sun.COM 	 * Address provided belongs to HBA softstate.  Get the targets pointer
239910696SDavid.Hollister@Sun.COM 	 * to begin the walk.
240010696SDavid.Hollister@Sun.COM 	 */
240110696SDavid.Hollister@Sun.COM 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
240210696SDavid.Hollister@Sun.COM 	    sizeof (pmcs_hw_t)) {
240310696SDavid.Hollister@Sun.COM 		mdb_warn("Unable to read HBA softstate\n");
240410696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
240510696SDavid.Hollister@Sun.COM 	}
240610696SDavid.Hollister@Sun.COM 
240710696SDavid.Hollister@Sun.COM 	wsp->walk_addr = (uintptr_t)(ss.root_phys);
240810696SDavid.Hollister@Sun.COM 	wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
240910696SDavid.Hollister@Sun.COM 
241010696SDavid.Hollister@Sun.COM 	return (WALK_NEXT);
241110696SDavid.Hollister@Sun.COM }
241210696SDavid.Hollister@Sun.COM 
241310696SDavid.Hollister@Sun.COM static int
241410696SDavid.Hollister@Sun.COM phy_walk_s(mdb_walk_state_t *wsp)
241510696SDavid.Hollister@Sun.COM {
241610696SDavid.Hollister@Sun.COM 	pmcs_phy_t *phyp, *nphyp;
241710696SDavid.Hollister@Sun.COM 	int status;
241810696SDavid.Hollister@Sun.COM 
241910696SDavid.Hollister@Sun.COM 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t),
242010696SDavid.Hollister@Sun.COM 	    wsp->walk_addr) == -1) {
242110696SDavid.Hollister@Sun.COM 		mdb_warn("phy_walk_s: Failed to read PHY at %p",
242210696SDavid.Hollister@Sun.COM 		    (void *)wsp->walk_addr);
242310696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
242410696SDavid.Hollister@Sun.COM 	}
242510696SDavid.Hollister@Sun.COM 
242610696SDavid.Hollister@Sun.COM 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
242710696SDavid.Hollister@Sun.COM 	    wsp->walk_cbdata);
242810696SDavid.Hollister@Sun.COM 
242910696SDavid.Hollister@Sun.COM 	phyp = (pmcs_phy_t *)wsp->walk_data;
243010696SDavid.Hollister@Sun.COM 	if (phyp->children) {
243110696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)(phyp->children);
243210696SDavid.Hollister@Sun.COM 	} else {
243310696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)(phyp->sibling);
243410696SDavid.Hollister@Sun.COM 	}
243510696SDavid.Hollister@Sun.COM 
243610696SDavid.Hollister@Sun.COM 	if (wsp->walk_addr == NULL) {
243710696SDavid.Hollister@Sun.COM 		/*
243810696SDavid.Hollister@Sun.COM 		 * We reached the end of this sibling list.  Trudge back up
243910696SDavid.Hollister@Sun.COM 		 * to the parent and find the next sibling after the expander
244010696SDavid.Hollister@Sun.COM 		 * we just finished traversing, if there is one.
244110696SDavid.Hollister@Sun.COM 		 */
244210696SDavid.Hollister@Sun.COM 		nphyp = pmcs_next_sibling(phyp);
244310696SDavid.Hollister@Sun.COM 
244410696SDavid.Hollister@Sun.COM 		if (nphyp == NULL) {
244510696SDavid.Hollister@Sun.COM 			return (WALK_DONE);
244610696SDavid.Hollister@Sun.COM 		}
244710696SDavid.Hollister@Sun.COM 
244810696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)nphyp;
244910696SDavid.Hollister@Sun.COM 	}
245010696SDavid.Hollister@Sun.COM 
245110696SDavid.Hollister@Sun.COM 	return (status);
245210696SDavid.Hollister@Sun.COM }
245310696SDavid.Hollister@Sun.COM 
245410696SDavid.Hollister@Sun.COM static void
245510696SDavid.Hollister@Sun.COM phy_walk_f(mdb_walk_state_t *wsp)
245610696SDavid.Hollister@Sun.COM {
245710696SDavid.Hollister@Sun.COM 	mdb_free(wsp->walk_data, sizeof (pmcs_phy_t));
245810696SDavid.Hollister@Sun.COM }
245910696SDavid.Hollister@Sun.COM 
246010743SDavid.Hollister@Sun.COM static void
246110743SDavid.Hollister@Sun.COM display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum,
246210743SDavid.Hollister@Sun.COM     uintmax_t tag_type)
246310743SDavid.Hollister@Sun.COM {
246410743SDavid.Hollister@Sun.COM 	int		idx;
246510743SDavid.Hollister@Sun.COM 	pmcwork_t	work, *wp = &work;
246610743SDavid.Hollister@Sun.COM 	uintptr_t	_wp;
246710743SDavid.Hollister@Sun.COM 	boolean_t	printed_header = B_FALSE;
246810743SDavid.Hollister@Sun.COM 	uint32_t	mask, mask_val, match_val;
246910743SDavid.Hollister@Sun.COM 	char		*match_type;
247010743SDavid.Hollister@Sun.COM 
247110743SDavid.Hollister@Sun.COM 	if (index != UINT_MAX) {
247210743SDavid.Hollister@Sun.COM 		match_type = "index";
247310743SDavid.Hollister@Sun.COM 		mask = PMCS_TAG_INDEX_MASK;
247410743SDavid.Hollister@Sun.COM 		mask_val = index << PMCS_TAG_INDEX_SHIFT;
247510743SDavid.Hollister@Sun.COM 		match_val = index;
247610743SDavid.Hollister@Sun.COM 	} else if (snum != UINT_MAX) {
247710743SDavid.Hollister@Sun.COM 		match_type = "serial number";
247810743SDavid.Hollister@Sun.COM 		mask = PMCS_TAG_SERNO_MASK;
247910743SDavid.Hollister@Sun.COM 		mask_val = snum << PMCS_TAG_SERNO_SHIFT;
248010743SDavid.Hollister@Sun.COM 		match_val = snum;
248110743SDavid.Hollister@Sun.COM 	} else {
248210743SDavid.Hollister@Sun.COM 		switch (tag_type) {
248310743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_NONE:
248410743SDavid.Hollister@Sun.COM 			match_type = "tag type NONE";
248510743SDavid.Hollister@Sun.COM 			break;
248610743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_CBACK:
248710743SDavid.Hollister@Sun.COM 			match_type = "tag type CBACK";
248810743SDavid.Hollister@Sun.COM 			break;
248910743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_WAIT:
249010743SDavid.Hollister@Sun.COM 			match_type = "tag type WAIT";
249110743SDavid.Hollister@Sun.COM 			break;
249210743SDavid.Hollister@Sun.COM 		}
249310743SDavid.Hollister@Sun.COM 		mask = PMCS_TAG_TYPE_MASK;
249410743SDavid.Hollister@Sun.COM 		mask_val = tag_type << PMCS_TAG_TYPE_SHIFT;
249510743SDavid.Hollister@Sun.COM 		match_val = tag_type;
249610743SDavid.Hollister@Sun.COM 	}
249710743SDavid.Hollister@Sun.COM 
249810743SDavid.Hollister@Sun.COM 	_wp = (uintptr_t)ss.work;
249910743SDavid.Hollister@Sun.COM 
250010743SDavid.Hollister@Sun.COM 	for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
250110743SDavid.Hollister@Sun.COM 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
250210743SDavid.Hollister@Sun.COM 			NOREAD(pmcwork_t, _wp);
250310743SDavid.Hollister@Sun.COM 			continue;
250410743SDavid.Hollister@Sun.COM 		}
250510743SDavid.Hollister@Sun.COM 
250610743SDavid.Hollister@Sun.COM 		if ((work.htag & mask) != mask_val) {
250710743SDavid.Hollister@Sun.COM 			continue;
250810743SDavid.Hollister@Sun.COM 		}
250910743SDavid.Hollister@Sun.COM 
251010743SDavid.Hollister@Sun.COM 		if (printed_header == B_FALSE) {
251110743SDavid.Hollister@Sun.COM 			if (tag_type) {
251210743SDavid.Hollister@Sun.COM 				mdb_printf("\nWork structures matching %s\n\n",
251310743SDavid.Hollister@Sun.COM 				    match_type, match_val);
251410743SDavid.Hollister@Sun.COM 			} else {
251510743SDavid.Hollister@Sun.COM 				mdb_printf("\nWork structures matching %s of "
251610743SDavid.Hollister@Sun.COM 				    "0x%x\n\n", match_type, match_val);
251710743SDavid.Hollister@Sun.COM 			}
251810743SDavid.Hollister@Sun.COM 			mdb_printf("%8s %10s %20s %8s %8s O D\n",
251910743SDavid.Hollister@Sun.COM 			    "HTag", "State", "Phy Path", "Target", "Timer");
252010743SDavid.Hollister@Sun.COM 			printed_header = B_TRUE;
252110743SDavid.Hollister@Sun.COM 		}
252210743SDavid.Hollister@Sun.COM 
252310743SDavid.Hollister@Sun.COM 		display_one_work(wp, 0, 0);
252410743SDavid.Hollister@Sun.COM 	}
252510743SDavid.Hollister@Sun.COM 
252610743SDavid.Hollister@Sun.COM 	if (!printed_header) {
252710743SDavid.Hollister@Sun.COM 		mdb_printf("No work structure matches found\n");
252810743SDavid.Hollister@Sun.COM 	}
252910743SDavid.Hollister@Sun.COM }
253010743SDavid.Hollister@Sun.COM 
253110743SDavid.Hollister@Sun.COM static int
253210743SDavid.Hollister@Sun.COM pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
253310743SDavid.Hollister@Sun.COM {
253410743SDavid.Hollister@Sun.COM 	struct	pmcs_hw		ss;
253510743SDavid.Hollister@Sun.COM 	uintmax_t		tag_type = UINT_MAX;
253610743SDavid.Hollister@Sun.COM 	uintmax_t		snum = UINT_MAX;
253710743SDavid.Hollister@Sun.COM 	uintmax_t		index = UINT_MAX;
253810743SDavid.Hollister@Sun.COM 	int			args = 0;
253910743SDavid.Hollister@Sun.COM 	void			*pmcs_state;
254010743SDavid.Hollister@Sun.COM 	char			*state_str;
254110743SDavid.Hollister@Sun.COM 	struct dev_info		dip;
254210743SDavid.Hollister@Sun.COM 
254310743SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
254410743SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
254510743SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
254610743SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
254710743SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
254810743SDavid.Hollister@Sun.COM 		}
254910743SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc,
255010743SDavid.Hollister@Sun.COM 		    argv, (uintptr_t)pmcs_state) == -1) {
255110743SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed");
255210743SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
255310743SDavid.Hollister@Sun.COM 		}
255410743SDavid.Hollister@Sun.COM 		return (DCMD_OK);
255510743SDavid.Hollister@Sun.COM 	}
255610743SDavid.Hollister@Sun.COM 
255710743SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv,
255810743SDavid.Hollister@Sun.COM 	    'i', MDB_OPT_UINT64, &index,
255910743SDavid.Hollister@Sun.COM 	    's', MDB_OPT_UINT64, &snum,
256010743SDavid.Hollister@Sun.COM 	    't', MDB_OPT_UINT64, &tag_type) != argc)
256110743SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
256210743SDavid.Hollister@Sun.COM 
256310743SDavid.Hollister@Sun.COM 	/*
256410743SDavid.Hollister@Sun.COM 	 * Count the number of supplied options and make sure they are
256510743SDavid.Hollister@Sun.COM 	 * within appropriate ranges.  If they're set to UINT_MAX, that means
256610743SDavid.Hollister@Sun.COM 	 * they were not supplied, in which case reset them to 0.
256710743SDavid.Hollister@Sun.COM 	 */
256810743SDavid.Hollister@Sun.COM 	if (index != UINT_MAX) {
256910743SDavid.Hollister@Sun.COM 		args++;
257010743SDavid.Hollister@Sun.COM 		if (index > PMCS_TAG_INDEX_MASK) {
257110743SDavid.Hollister@Sun.COM 			mdb_warn("Index is out of range\n");
257210743SDavid.Hollister@Sun.COM 			return (DCMD_USAGE);
257310743SDavid.Hollister@Sun.COM 		}
257410743SDavid.Hollister@Sun.COM 	}
257510743SDavid.Hollister@Sun.COM 
257610743SDavid.Hollister@Sun.COM 	if (tag_type != UINT_MAX) {
257710743SDavid.Hollister@Sun.COM 		args++;
257810743SDavid.Hollister@Sun.COM 		switch (tag_type) {
257910743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_NONE:
258010743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_CBACK:
258110743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_WAIT:
258210743SDavid.Hollister@Sun.COM 			break;
258310743SDavid.Hollister@Sun.COM 		default:
258410743SDavid.Hollister@Sun.COM 			mdb_warn("Invalid tag type\n");
258510743SDavid.Hollister@Sun.COM 			return (DCMD_USAGE);
258610743SDavid.Hollister@Sun.COM 		}
258710743SDavid.Hollister@Sun.COM 	}
258810743SDavid.Hollister@Sun.COM 
258910743SDavid.Hollister@Sun.COM 	if (snum != UINT_MAX) {
259010743SDavid.Hollister@Sun.COM 		args++;
259110743SDavid.Hollister@Sun.COM 		if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) {
259210743SDavid.Hollister@Sun.COM 			mdb_warn("Serial number is out of range\n");
259310743SDavid.Hollister@Sun.COM 			return (DCMD_USAGE);
259410743SDavid.Hollister@Sun.COM 		}
259510743SDavid.Hollister@Sun.COM 	}
259610743SDavid.Hollister@Sun.COM 
259710743SDavid.Hollister@Sun.COM 	/*
259810743SDavid.Hollister@Sun.COM 	 * Make sure 1 and only 1 option is specified
259910743SDavid.Hollister@Sun.COM 	 */
260010743SDavid.Hollister@Sun.COM 	if ((args == 0) || (args > 1)) {
260110743SDavid.Hollister@Sun.COM 		mdb_warn("Exactly one of -i, -s and -t must be specified\n");
260210743SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
260310743SDavid.Hollister@Sun.COM 	}
260410743SDavid.Hollister@Sun.COM 
260510743SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
260610743SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
260710743SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
260810743SDavid.Hollister@Sun.COM 	}
260910743SDavid.Hollister@Sun.COM 
261010743SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
261110743SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
261210743SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
261310743SDavid.Hollister@Sun.COM 	}
261410743SDavid.Hollister@Sun.COM 
261510743SDavid.Hollister@Sun.COM 	/* processing completed */
261610743SDavid.Hollister@Sun.COM 
261710743SDavid.Hollister@Sun.COM 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
261810743SDavid.Hollister@Sun.COM 	    (flags & DCMD_LOOPFIRST)) {
261910743SDavid.Hollister@Sun.COM 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
262010743SDavid.Hollister@Sun.COM 			mdb_printf("\n");
262110743SDavid.Hollister@Sun.COM 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
262210743SDavid.Hollister@Sun.COM 		    "Address", "State", "Inst", "DIP");
262310743SDavid.Hollister@Sun.COM 		mdb_printf("================================="
262410743SDavid.Hollister@Sun.COM 		    "============================================\n");
262510743SDavid.Hollister@Sun.COM 	}
262610743SDavid.Hollister@Sun.COM 
262710743SDavid.Hollister@Sun.COM 	switch (ss.state) {
262810743SDavid.Hollister@Sun.COM 	case STATE_NIL:
262910743SDavid.Hollister@Sun.COM 		state_str = "Invalid";
263010743SDavid.Hollister@Sun.COM 		break;
263110743SDavid.Hollister@Sun.COM 	case STATE_PROBING:
263210743SDavid.Hollister@Sun.COM 		state_str = "Probing";
263310743SDavid.Hollister@Sun.COM 		break;
263410743SDavid.Hollister@Sun.COM 	case STATE_RUNNING:
263510743SDavid.Hollister@Sun.COM 		state_str = "Running";
263610743SDavid.Hollister@Sun.COM 		break;
263710743SDavid.Hollister@Sun.COM 	case STATE_UNPROBING:
263810743SDavid.Hollister@Sun.COM 		state_str = "Unprobing";
263910743SDavid.Hollister@Sun.COM 		break;
264010743SDavid.Hollister@Sun.COM 	case STATE_DEAD:
264110743SDavid.Hollister@Sun.COM 		state_str = "Dead";
264210743SDavid.Hollister@Sun.COM 		break;
264311692SJesse.Butler@Sun.COM 	case STATE_IN_RESET:
264411692SJesse.Butler@Sun.COM 		state_str = "In Reset";
264511692SJesse.Butler@Sun.COM 		break;
264610743SDavid.Hollister@Sun.COM 	}
264710743SDavid.Hollister@Sun.COM 
264810743SDavid.Hollister@Sun.COM 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
264910743SDavid.Hollister@Sun.COM 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
265010743SDavid.Hollister@Sun.COM 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
265110743SDavid.Hollister@Sun.COM 	mdb_printf("\n");
265210743SDavid.Hollister@Sun.COM 
265310743SDavid.Hollister@Sun.COM 	mdb_inc_indent(4);
265410743SDavid.Hollister@Sun.COM 	display_matching_work(ss, index, snum, tag_type);
265510743SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
265610743SDavid.Hollister@Sun.COM 	mdb_printf("\n");
265710743SDavid.Hollister@Sun.COM 
265810743SDavid.Hollister@Sun.COM 	return (DCMD_OK);
265910743SDavid.Hollister@Sun.COM }
266010743SDavid.Hollister@Sun.COM 
266111694SDavid.Hollister@Sun.COM #ifndef _KMDB
266211694SDavid.Hollister@Sun.COM static int
266311694SDavid.Hollister@Sun.COM pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile)
266411694SDavid.Hollister@Sun.COM {
266511694SDavid.Hollister@Sun.COM 	uint8_t *fwlogp;
266611694SDavid.Hollister@Sun.COM 	int	ofilefd = -1;
266711694SDavid.Hollister@Sun.COM 	char	ofilename[MAXPATHLEN];
266811694SDavid.Hollister@Sun.COM 	int	rval = DCMD_OK;
266911694SDavid.Hollister@Sun.COM 
267011694SDavid.Hollister@Sun.COM 	if (ss->fwlogp == NULL) {
267111694SDavid.Hollister@Sun.COM 		mdb_warn("Firmware event log disabled for instance %d",
267211694SDavid.Hollister@Sun.COM 		    instance);
267311694SDavid.Hollister@Sun.COM 		return (DCMD_OK);
267411694SDavid.Hollister@Sun.COM 	}
267511694SDavid.Hollister@Sun.COM 
267611694SDavid.Hollister@Sun.COM 	if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) >
267711694SDavid.Hollister@Sun.COM 	    MAXPATHLEN) {
267811694SDavid.Hollister@Sun.COM 		mdb_warn("Output filename is too long for instance %d",
267911694SDavid.Hollister@Sun.COM 		    instance);
268011694SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
268111694SDavid.Hollister@Sun.COM 	}
268211694SDavid.Hollister@Sun.COM 
268311694SDavid.Hollister@Sun.COM 	fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP);
268411694SDavid.Hollister@Sun.COM 
268511694SDavid.Hollister@Sun.COM 	if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) {
268611694SDavid.Hollister@Sun.COM 		NOREAD(fwlogp, ss->fwlogp);
268711694SDavid.Hollister@Sun.COM 		rval = DCMD_ERR;
268811694SDavid.Hollister@Sun.COM 		goto cleanup;
268911694SDavid.Hollister@Sun.COM 	}
269011694SDavid.Hollister@Sun.COM 
269111694SDavid.Hollister@Sun.COM 	ofilefd = open(ofilename, O_WRONLY | O_CREAT,
269211694SDavid.Hollister@Sun.COM 	    S_IRUSR | S_IRGRP | S_IROTH);
269311694SDavid.Hollister@Sun.COM 	if (ofilefd < 0) {
269411694SDavid.Hollister@Sun.COM 		mdb_warn("Unable to open '%s' to dump instance %d event log",
269511694SDavid.Hollister@Sun.COM 		    ofilename, instance);
269611694SDavid.Hollister@Sun.COM 		rval = DCMD_ERR;
269711694SDavid.Hollister@Sun.COM 		goto cleanup;
269811694SDavid.Hollister@Sun.COM 	}
269911694SDavid.Hollister@Sun.COM 
270011694SDavid.Hollister@Sun.COM 	if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) {
270111694SDavid.Hollister@Sun.COM 		mdb_warn("Failed to write %d bytes to output file: instance %d",
270211694SDavid.Hollister@Sun.COM 		    PMCS_FWLOG_SIZE, instance);
270311694SDavid.Hollister@Sun.COM 		rval = DCMD_ERR;
270411694SDavid.Hollister@Sun.COM 		goto cleanup;
270511694SDavid.Hollister@Sun.COM 	}
270611694SDavid.Hollister@Sun.COM 
270711694SDavid.Hollister@Sun.COM 	mdb_printf("Event log for instance %d written to %s\n", instance,
270811694SDavid.Hollister@Sun.COM 	    ofilename);
270911694SDavid.Hollister@Sun.COM 
271011694SDavid.Hollister@Sun.COM cleanup:
271111694SDavid.Hollister@Sun.COM 	if (ofilefd >= 0) {
271211694SDavid.Hollister@Sun.COM 		close(ofilefd);
271311694SDavid.Hollister@Sun.COM 	}
271411694SDavid.Hollister@Sun.COM 	mdb_free(fwlogp, PMCS_FWLOG_SIZE);
271511694SDavid.Hollister@Sun.COM 	return (rval);
271611694SDavid.Hollister@Sun.COM }
271711694SDavid.Hollister@Sun.COM 
271811694SDavid.Hollister@Sun.COM static int
271911694SDavid.Hollister@Sun.COM pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
272011694SDavid.Hollister@Sun.COM {
272111694SDavid.Hollister@Sun.COM 	void		*pmcs_state;
272211694SDavid.Hollister@Sun.COM 	const char	*ofile = NULL;
272311694SDavid.Hollister@Sun.COM 	struct pmcs_hw	ss;
272411694SDavid.Hollister@Sun.COM 	struct dev_info	dip;
272511694SDavid.Hollister@Sun.COM 
272611694SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) {
272711694SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
272811694SDavid.Hollister@Sun.COM 	}
272911694SDavid.Hollister@Sun.COM 
273011694SDavid.Hollister@Sun.COM 	if (ofile == NULL) {
273111694SDavid.Hollister@Sun.COM 		mdb_printf("No output file specified\n");
273211694SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
273311694SDavid.Hollister@Sun.COM 	}
273411694SDavid.Hollister@Sun.COM 
273511694SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
273611694SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
273711694SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
273811694SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
273911694SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
274011694SDavid.Hollister@Sun.COM 		}
274111694SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc,
274211694SDavid.Hollister@Sun.COM 		    argv, (uintptr_t)pmcs_state) == -1) {
274311694SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
274411694SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
274511694SDavid.Hollister@Sun.COM 		}
274611694SDavid.Hollister@Sun.COM 		return (DCMD_OK);
274711694SDavid.Hollister@Sun.COM 	}
274811694SDavid.Hollister@Sun.COM 
274911694SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
275011694SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
275111694SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
275211694SDavid.Hollister@Sun.COM 	}
275311694SDavid.Hollister@Sun.COM 
275411694SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
275511694SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
275611694SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
275711694SDavid.Hollister@Sun.COM 	}
275811694SDavid.Hollister@Sun.COM 
275911694SDavid.Hollister@Sun.COM 	return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile));
276011694SDavid.Hollister@Sun.COM }
276111694SDavid.Hollister@Sun.COM #endif	/* _KMDB */
276211694SDavid.Hollister@Sun.COM 
276310696SDavid.Hollister@Sun.COM static int
276411048SDavid.Hollister@Sun.COM pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
276511048SDavid.Hollister@Sun.COM {
276611048SDavid.Hollister@Sun.COM 	void		*pmcs_state;
276711048SDavid.Hollister@Sun.COM 	struct pmcs_hw	ss;
276811048SDavid.Hollister@Sun.COM 	struct dev_info	dip;
276911048SDavid.Hollister@Sun.COM 	const char	*match_phy_path = NULL;
277011347SRamana.Srikanth@Sun.COM 	uint64_t 	match_sas_address = 0, tail_lines = 0;
2771*12120SDavid.Hollister@Sun.COM 	uint_t		verbose = 0;
277211048SDavid.Hollister@Sun.COM 
277311048SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
277411048SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
277511048SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
277611048SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
277711048SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
277811048SDavid.Hollister@Sun.COM 		}
277911048SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc,
278011048SDavid.Hollister@Sun.COM 		    argv, (uintptr_t)pmcs_state) == -1) {
278111048SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
278211048SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
278311048SDavid.Hollister@Sun.COM 		}
278411048SDavid.Hollister@Sun.COM 		return (DCMD_OK);
278511048SDavid.Hollister@Sun.COM 	}
278611048SDavid.Hollister@Sun.COM 
278711048SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv,
278811347SRamana.Srikanth@Sun.COM 	    'l', MDB_OPT_UINT64, &tail_lines,
278911048SDavid.Hollister@Sun.COM 	    'p', MDB_OPT_STR, &match_phy_path,
279011048SDavid.Hollister@Sun.COM 	    's', MDB_OPT_UINT64, &match_sas_address,
2791*12120SDavid.Hollister@Sun.COM 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
279211048SDavid.Hollister@Sun.COM 	    NULL) != argc) {
279311048SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
279411048SDavid.Hollister@Sun.COM 	}
279511048SDavid.Hollister@Sun.COM 
279611048SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
279711048SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
279811048SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
279911048SDavid.Hollister@Sun.COM 	}
280011048SDavid.Hollister@Sun.COM 
280111048SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
280211048SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
280311048SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
280411048SDavid.Hollister@Sun.COM 	}
280511048SDavid.Hollister@Sun.COM 
280611048SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_LOOP)) {
280711048SDavid.Hollister@Sun.COM 		return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance,
2808*12120SDavid.Hollister@Sun.COM 		    tail_lines, match_phy_path, match_sas_address, verbose));
280911048SDavid.Hollister@Sun.COM 	} else if (flags & DCMD_LOOPFIRST) {
281011347SRamana.Srikanth@Sun.COM 		return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines,
2811*12120SDavid.Hollister@Sun.COM 		    match_phy_path, match_sas_address, verbose));
281211048SDavid.Hollister@Sun.COM 	} else {
281311048SDavid.Hollister@Sun.COM 		return (DCMD_OK);
281411048SDavid.Hollister@Sun.COM 	}
281511048SDavid.Hollister@Sun.COM }
281611048SDavid.Hollister@Sun.COM 
281711048SDavid.Hollister@Sun.COM static int
281810696SDavid.Hollister@Sun.COM pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
281910696SDavid.Hollister@Sun.COM {
282011048SDavid.Hollister@Sun.COM 	struct pmcs_hw		ss;
282110696SDavid.Hollister@Sun.COM 	uint_t			verbose = FALSE;
282210696SDavid.Hollister@Sun.COM 	uint_t			phy_info = FALSE;
282310696SDavid.Hollister@Sun.COM 	uint_t			hw_info = FALSE;
282410696SDavid.Hollister@Sun.COM 	uint_t			target_info = FALSE;
282510696SDavid.Hollister@Sun.COM 	uint_t			work_info = FALSE;
282610696SDavid.Hollister@Sun.COM 	uint_t			ic_info = FALSE;
282710696SDavid.Hollister@Sun.COM 	uint_t			iport_info = FALSE;
282810696SDavid.Hollister@Sun.COM 	uint_t			waitqs_info = FALSE;
282910696SDavid.Hollister@Sun.COM 	uint_t			ibq = FALSE;
283010696SDavid.Hollister@Sun.COM 	uint_t			obq = FALSE;
283110696SDavid.Hollister@Sun.COM 	uint_t			tgt_phy_count = FALSE;
283210743SDavid.Hollister@Sun.COM 	uint_t			compq = FALSE;
283311048SDavid.Hollister@Sun.COM 	uint_t			unconfigured = FALSE;
283411334SReed.Liu@Sun.COM 	uint_t			damap_info = FALSE;
283511334SReed.Liu@Sun.COM 	uint_t			dtc_info = FALSE;
283612060SDavid.Hollister@Sun.COM 	uint_t			wserno = FALSE;
2837*12120SDavid.Hollister@Sun.COM 	uint_t			fwlog = FALSE;
283810696SDavid.Hollister@Sun.COM 	int			rv = DCMD_OK;
283910696SDavid.Hollister@Sun.COM 	void			*pmcs_state;
284010696SDavid.Hollister@Sun.COM 	char			*state_str;
284110696SDavid.Hollister@Sun.COM 	struct dev_info		dip;
284211334SReed.Liu@Sun.COM 	per_iport_setting_t	pis;
284310696SDavid.Hollister@Sun.COM 
284410696SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
284510696SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
284610696SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
284710696SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
284810696SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
284910696SDavid.Hollister@Sun.COM 		}
285010696SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv,
285110696SDavid.Hollister@Sun.COM 		    (uintptr_t)pmcs_state) == -1) {
285210696SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed");
285310696SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
285410696SDavid.Hollister@Sun.COM 		}
285510696SDavid.Hollister@Sun.COM 		return (DCMD_OK);
285610696SDavid.Hollister@Sun.COM 	}
285710696SDavid.Hollister@Sun.COM 
285810696SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv,
285910743SDavid.Hollister@Sun.COM 	    'c', MDB_OPT_SETBITS, TRUE, &compq,
286011334SReed.Liu@Sun.COM 	    'd', MDB_OPT_SETBITS, TRUE, &dtc_info,
2861*12120SDavid.Hollister@Sun.COM 	    'e', MDB_OPT_SETBITS, TRUE, &fwlog,
286210696SDavid.Hollister@Sun.COM 	    'h', MDB_OPT_SETBITS, TRUE, &hw_info,
286310696SDavid.Hollister@Sun.COM 	    'i', MDB_OPT_SETBITS, TRUE, &ic_info,
286410696SDavid.Hollister@Sun.COM 	    'I', MDB_OPT_SETBITS, TRUE, &iport_info,
286511334SReed.Liu@Sun.COM 	    'm', MDB_OPT_SETBITS, TRUE, &damap_info,
286610696SDavid.Hollister@Sun.COM 	    'p', MDB_OPT_SETBITS, TRUE, &phy_info,
286710696SDavid.Hollister@Sun.COM 	    'q', MDB_OPT_SETBITS, TRUE, &ibq,
286810696SDavid.Hollister@Sun.COM 	    'Q', MDB_OPT_SETBITS, TRUE, &obq,
286912060SDavid.Hollister@Sun.COM 	    's', MDB_OPT_SETBITS, TRUE, &wserno,
287010696SDavid.Hollister@Sun.COM 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
287110696SDavid.Hollister@Sun.COM 	    'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count,
287211048SDavid.Hollister@Sun.COM 	    'u', MDB_OPT_SETBITS, TRUE, &unconfigured,
287310696SDavid.Hollister@Sun.COM 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
287410696SDavid.Hollister@Sun.COM 	    'w', MDB_OPT_SETBITS, TRUE, &work_info,
287510696SDavid.Hollister@Sun.COM 	    'W', MDB_OPT_SETBITS, TRUE, &waitqs_info,
287610696SDavid.Hollister@Sun.COM 	    NULL) != argc)
287710696SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
287810696SDavid.Hollister@Sun.COM 
287911334SReed.Liu@Sun.COM 	/*
288011334SReed.Liu@Sun.COM 	 * The 'd' and 'm' options implicitly enable the 'I' option
288111334SReed.Liu@Sun.COM 	 */
288211334SReed.Liu@Sun.COM 	pis.pis_damap_info = damap_info;
288311334SReed.Liu@Sun.COM 	pis.pis_dtc_info = dtc_info;
288411334SReed.Liu@Sun.COM 	if (damap_info || dtc_info) {
288511334SReed.Liu@Sun.COM 		iport_info = TRUE;
288611334SReed.Liu@Sun.COM 	}
288711334SReed.Liu@Sun.COM 
288810696SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
288910696SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
289010696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
289110696SDavid.Hollister@Sun.COM 	}
289210696SDavid.Hollister@Sun.COM 
289310696SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
289410696SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
289510696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
289610696SDavid.Hollister@Sun.COM 	}
289710696SDavid.Hollister@Sun.COM 
289810696SDavid.Hollister@Sun.COM 	/* processing completed */
289910696SDavid.Hollister@Sun.COM 
290010696SDavid.Hollister@Sun.COM 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
290110696SDavid.Hollister@Sun.COM 	    (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info ||
290211048SDavid.Hollister@Sun.COM 	    work_info || waitqs_info || ibq || obq || tgt_phy_count || compq ||
2903*12120SDavid.Hollister@Sun.COM 	    unconfigured || fwlog) {
290410696SDavid.Hollister@Sun.COM 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
290510696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
290610696SDavid.Hollister@Sun.COM 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
290710696SDavid.Hollister@Sun.COM 		    "Address", "State", "Inst", "DIP");
290810696SDavid.Hollister@Sun.COM 		mdb_printf("================================="
290910696SDavid.Hollister@Sun.COM 		    "============================================\n");
291010696SDavid.Hollister@Sun.COM 	}
291110696SDavid.Hollister@Sun.COM 
291210696SDavid.Hollister@Sun.COM 	switch (ss.state) {
291310696SDavid.Hollister@Sun.COM 	case STATE_NIL:
291410696SDavid.Hollister@Sun.COM 		state_str = "Invalid";
291510696SDavid.Hollister@Sun.COM 		break;
291610696SDavid.Hollister@Sun.COM 	case STATE_PROBING:
291710696SDavid.Hollister@Sun.COM 		state_str = "Probing";
291810696SDavid.Hollister@Sun.COM 		break;
291910696SDavid.Hollister@Sun.COM 	case STATE_RUNNING:
292010696SDavid.Hollister@Sun.COM 		state_str = "Running";
292110696SDavid.Hollister@Sun.COM 		break;
292210696SDavid.Hollister@Sun.COM 	case STATE_UNPROBING:
292310696SDavid.Hollister@Sun.COM 		state_str = "Unprobing";
292410696SDavid.Hollister@Sun.COM 		break;
292510696SDavid.Hollister@Sun.COM 	case STATE_DEAD:
292610696SDavid.Hollister@Sun.COM 		state_str = "Dead";
292710696SDavid.Hollister@Sun.COM 		break;
292811692SJesse.Butler@Sun.COM 	case STATE_IN_RESET:
292911692SJesse.Butler@Sun.COM 		state_str = "In Reset";
293011692SJesse.Butler@Sun.COM 		break;
293110696SDavid.Hollister@Sun.COM 	}
293210696SDavid.Hollister@Sun.COM 
293310696SDavid.Hollister@Sun.COM 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
293410696SDavid.Hollister@Sun.COM 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
293510696SDavid.Hollister@Sun.COM 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
293610696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
293710696SDavid.Hollister@Sun.COM 
293810696SDavid.Hollister@Sun.COM 	mdb_inc_indent(4);
293910696SDavid.Hollister@Sun.COM 
294010696SDavid.Hollister@Sun.COM 	if (waitqs_info)
294110696SDavid.Hollister@Sun.COM 		display_waitqs(ss, verbose);
294210696SDavid.Hollister@Sun.COM 
294310696SDavid.Hollister@Sun.COM 	if (hw_info)
294410696SDavid.Hollister@Sun.COM 		display_hwinfo(ss, verbose);
294510696SDavid.Hollister@Sun.COM 
294610696SDavid.Hollister@Sun.COM 	if (phy_info || tgt_phy_count)
294710696SDavid.Hollister@Sun.COM 		display_phys(ss, verbose, NULL, 0, tgt_phy_count);
294810696SDavid.Hollister@Sun.COM 
294910696SDavid.Hollister@Sun.COM 	if (target_info || tgt_phy_count)
295010696SDavid.Hollister@Sun.COM 		display_targets(ss, verbose, tgt_phy_count);
295110696SDavid.Hollister@Sun.COM 
295212060SDavid.Hollister@Sun.COM 	if (work_info || wserno)
295312060SDavid.Hollister@Sun.COM 		display_work(ss, verbose, wserno);
295410696SDavid.Hollister@Sun.COM 
295510696SDavid.Hollister@Sun.COM 	if (ic_info)
295610696SDavid.Hollister@Sun.COM 		display_ic(ss, verbose);
295710696SDavid.Hollister@Sun.COM 
295810696SDavid.Hollister@Sun.COM 	if (ibq)
295910696SDavid.Hollister@Sun.COM 		display_inbound_queues(ss, verbose);
296010696SDavid.Hollister@Sun.COM 
296110696SDavid.Hollister@Sun.COM 	if (obq)
296210696SDavid.Hollister@Sun.COM 		display_outbound_queues(ss, verbose);
296310696SDavid.Hollister@Sun.COM 
296410696SDavid.Hollister@Sun.COM 	if (iport_info)
296511334SReed.Liu@Sun.COM 		display_iport(ss, addr, verbose, &pis);
296610696SDavid.Hollister@Sun.COM 
296710743SDavid.Hollister@Sun.COM 	if (compq)
296810743SDavid.Hollister@Sun.COM 		display_completion_queue(ss);
296910743SDavid.Hollister@Sun.COM 
297011048SDavid.Hollister@Sun.COM 	if (unconfigured)
297111048SDavid.Hollister@Sun.COM 		display_unconfigured_targets(addr);
297211048SDavid.Hollister@Sun.COM 
2973*12120SDavid.Hollister@Sun.COM 	if (fwlog)
2974*12120SDavid.Hollister@Sun.COM 		display_event_log(ss);
2975*12120SDavid.Hollister@Sun.COM 
297610696SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
297710696SDavid.Hollister@Sun.COM 
297810696SDavid.Hollister@Sun.COM 	return (rv);
297910696SDavid.Hollister@Sun.COM }
298010696SDavid.Hollister@Sun.COM 
298110696SDavid.Hollister@Sun.COM void
298210696SDavid.Hollister@Sun.COM pmcs_help()
298310696SDavid.Hollister@Sun.COM {
298410696SDavid.Hollister@Sun.COM 	mdb_printf("Prints summary information about each pmcs instance.\n"
298510743SDavid.Hollister@Sun.COM 	    "    -c: Dump the completion queue\n"
298611334SReed.Liu@Sun.COM 	    "    -d: Print per-iport information about device tree children\n"
2987*12120SDavid.Hollister@Sun.COM 	    "    -e: Display the in-memory firmware event log\n"
298810696SDavid.Hollister@Sun.COM 	    "    -h: Print more detailed hardware information\n"
298910696SDavid.Hollister@Sun.COM 	    "    -i: Print interrupt coalescing information\n"
299010696SDavid.Hollister@Sun.COM 	    "    -I: Print information about each iport\n"
299111334SReed.Liu@Sun.COM 	    "    -m: Print per-iport information about DAM/damap state\n"
299210696SDavid.Hollister@Sun.COM 	    "    -p: Print information about each attached PHY\n"
299310696SDavid.Hollister@Sun.COM 	    "    -q: Dump inbound queues\n"
299410696SDavid.Hollister@Sun.COM 	    "    -Q: Dump outbound queues\n"
299512060SDavid.Hollister@Sun.COM 	    "    -s: Dump all work structures sorted by serial number\n"
299611048SDavid.Hollister@Sun.COM 	    "    -t: Print information about each configured target\n"
299710696SDavid.Hollister@Sun.COM 	    "    -T: Print target and PHY count summary\n"
299811048SDavid.Hollister@Sun.COM 	    "    -u: Show SAS address of all unconfigured targets\n"
299910696SDavid.Hollister@Sun.COM 	    "    -w: Dump work structures\n"
300010696SDavid.Hollister@Sun.COM 	    "    -W: List pmcs cmds waiting on various queues\n"
300110696SDavid.Hollister@Sun.COM 	    "    -v: Add verbosity to the above options\n");
300210696SDavid.Hollister@Sun.COM }
300310696SDavid.Hollister@Sun.COM 
300410743SDavid.Hollister@Sun.COM void
300511048SDavid.Hollister@Sun.COM pmcs_log_help()
300611048SDavid.Hollister@Sun.COM {
300711048SDavid.Hollister@Sun.COM 	mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n"
300811347SRamana.Srikanth@Sun.COM 	    "    -l TAIL_LINES:          Dump the last TAIL_LINES messages\n"
300911048SDavid.Hollister@Sun.COM 	    "    -p PHY_PATH:            Dump messages matching PHY_PATH\n"
301011048SDavid.Hollister@Sun.COM 	    "    -s SAS_ADDRESS:         Dump messages matching SAS_ADDRESS\n\n"
301111048SDavid.Hollister@Sun.COM 	    "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n"
301211048SDavid.Hollister@Sun.COM 	    "       SAS_ADDRESS can be found with ::pmcs -t "
301311048SDavid.Hollister@Sun.COM 	    "(e.g. 5000c5000358c221)\n");
301411048SDavid.Hollister@Sun.COM }
301511048SDavid.Hollister@Sun.COM void
301610743SDavid.Hollister@Sun.COM pmcs_tag_help()
301710743SDavid.Hollister@Sun.COM {
301810743SDavid.Hollister@Sun.COM 	mdb_printf("Print all work structures by matching the tag.\n"
301910743SDavid.Hollister@Sun.COM 	    "    -i index:        Match tag index (0x000 - 0xfff)\n"
302010743SDavid.Hollister@Sun.COM 	    "    -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
302110743SDavid.Hollister@Sun.COM 	    "    -t tagtype:      Match tag type [NONE(1), CBACK(2), "
302210743SDavid.Hollister@Sun.COM 	    "WAIT(3)]\n");
302310743SDavid.Hollister@Sun.COM }
302410743SDavid.Hollister@Sun.COM 
302510696SDavid.Hollister@Sun.COM static const mdb_dcmd_t dcmds[] = {
3026*12120SDavid.Hollister@Sun.COM 	{ "pmcs", "?[-cdehiImpQqtTuwWv]", "print pmcs information",
302710696SDavid.Hollister@Sun.COM 	    pmcs_dcmd, pmcs_help
302810696SDavid.Hollister@Sun.COM 	},
302911048SDavid.Hollister@Sun.COM 	{ "pmcs_log",
3030*12120SDavid.Hollister@Sun.COM 	    "?[-v] [-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]",
303111048SDavid.Hollister@Sun.COM 	    "dump pmcs log file", pmcs_log, pmcs_log_help
303211048SDavid.Hollister@Sun.COM 	},
303310743SDavid.Hollister@Sun.COM 	{ "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
303410743SDavid.Hollister@Sun.COM 	    "Find work structures by tag type, serial number or index",
303510743SDavid.Hollister@Sun.COM 	    pmcs_tag, pmcs_tag_help
303610743SDavid.Hollister@Sun.COM 	},
303711694SDavid.Hollister@Sun.COM #ifndef _KMDB
303811694SDavid.Hollister@Sun.COM 	{ "pmcs_fwlog",
303911694SDavid.Hollister@Sun.COM 	    "?-o output_file",
304011694SDavid.Hollister@Sun.COM 	    "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL
304111694SDavid.Hollister@Sun.COM 	},
304211694SDavid.Hollister@Sun.COM #endif	/* _KMDB */
304310696SDavid.Hollister@Sun.COM 	{ NULL }
304410696SDavid.Hollister@Sun.COM };
304510696SDavid.Hollister@Sun.COM 
304610696SDavid.Hollister@Sun.COM static const mdb_walker_t walkers[] = {
304710696SDavid.Hollister@Sun.COM 	{ "pmcs_targets", "walk target structures",
304810696SDavid.Hollister@Sun.COM 		targets_walk_i, targets_walk_s, targets_walk_f },
304910696SDavid.Hollister@Sun.COM 	{ "pmcs_phys", "walk PHY structures",
305010696SDavid.Hollister@Sun.COM 		phy_walk_i, phy_walk_s, phy_walk_f },
305110696SDavid.Hollister@Sun.COM 	{ NULL }
305210696SDavid.Hollister@Sun.COM };
305310696SDavid.Hollister@Sun.COM 
305410696SDavid.Hollister@Sun.COM static const mdb_modinfo_t modinfo = {
305510696SDavid.Hollister@Sun.COM 	MDB_API_VERSION, dcmds, walkers
305610696SDavid.Hollister@Sun.COM };
305710696SDavid.Hollister@Sun.COM 
305810696SDavid.Hollister@Sun.COM const mdb_modinfo_t *
305910696SDavid.Hollister@Sun.COM _mdb_init(void)
306010696SDavid.Hollister@Sun.COM {
306110696SDavid.Hollister@Sun.COM 	return (&modinfo);
306210696SDavid.Hollister@Sun.COM }
3063