xref: /onnv-gate/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c (revision 11334:0e4407e73f70)
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 /*
2210696SDavid.Hollister@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2310696SDavid.Hollister@Sun.COM  * Use is subject to license terms.
2410696SDavid.Hollister@Sun.COM  */
2510696SDavid.Hollister@Sun.COM 
2610696SDavid.Hollister@Sun.COM #include <limits.h>
2710696SDavid.Hollister@Sun.COM #include <sys/mdb_modapi.h>
28*11334SReed.Liu@Sun.COM #include <mdb/mdb_ctf.h>
2910696SDavid.Hollister@Sun.COM #include <sys/sysinfo.h>
3011048SDavid.Hollister@Sun.COM #include <sys/byteorder.h>
31*11334SReed.Liu@Sun.COM #include <sys/nvpair.h>
32*11334SReed.Liu@Sun.COM #include <sys/damap.h>
3310696SDavid.Hollister@Sun.COM #include <sys/scsi/scsi.h>
3410696SDavid.Hollister@Sun.COM #include <sys/scsi/adapters/pmcs/pmcs.h>
3510696SDavid.Hollister@Sun.COM 
36*11334SReed.Liu@Sun.COM /*
37*11334SReed.Liu@Sun.COM  * We need use this to pass the settings when display_iport
38*11334SReed.Liu@Sun.COM  */
39*11334SReed.Liu@Sun.COM typedef struct per_iport_setting {
40*11334SReed.Liu@Sun.COM 	uint_t  pis_damap_info; /* -m: DAM/damap */
41*11334SReed.Liu@Sun.COM 	uint_t  pis_dtc_info; /* -d: device tree children: dev_info/path_info */
42*11334SReed.Liu@Sun.COM } per_iport_setting_t;
43*11334SReed.Liu@Sun.COM 
44*11334SReed.Liu@Sun.COM #define	MDB_RD(a, b, c)		mdb_vread(a, b, (uintptr_t)c)
45*11334SReed.Liu@Sun.COM #define	NOREAD(a, b)		mdb_warn("could not read " #a " at 0x%p", b)
4610696SDavid.Hollister@Sun.COM 
4710696SDavid.Hollister@Sun.COM static pmcs_hw_t ss;
4810696SDavid.Hollister@Sun.COM static pmcs_xscsi_t **targets = NULL;
4910696SDavid.Hollister@Sun.COM static int target_idx;
5010696SDavid.Hollister@Sun.COM 
5110696SDavid.Hollister@Sun.COM static uint32_t	sas_phys, sata_phys, exp_phys, num_expanders, empty_phys;
5210696SDavid.Hollister@Sun.COM 
5310696SDavid.Hollister@Sun.COM static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp);
5410743SDavid.Hollister@Sun.COM static void display_one_work(pmcwork_t *wp, int verbose, int idx);
5510696SDavid.Hollister@Sun.COM 
5610696SDavid.Hollister@Sun.COM static void
5710696SDavid.Hollister@Sun.COM print_sas_address(pmcs_phy_t *phy)
5810696SDavid.Hollister@Sun.COM {
5910696SDavid.Hollister@Sun.COM 	int idx;
6010696SDavid.Hollister@Sun.COM 
6110696SDavid.Hollister@Sun.COM 	for (idx = 0; idx < 8; idx++) {
6210696SDavid.Hollister@Sun.COM 		mdb_printf("%02x", phy->sas_address[idx]);
6310696SDavid.Hollister@Sun.COM 	}
6410696SDavid.Hollister@Sun.COM }
6510696SDavid.Hollister@Sun.COM 
6610696SDavid.Hollister@Sun.COM /*ARGSUSED*/
6710696SDavid.Hollister@Sun.COM static void
6810696SDavid.Hollister@Sun.COM display_ic(struct pmcs_hw m, int verbose)
6910696SDavid.Hollister@Sun.COM {
7010696SDavid.Hollister@Sun.COM 	int msec_per_tick;
7110696SDavid.Hollister@Sun.COM 
7210696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
7310696SDavid.Hollister@Sun.COM 		mdb_warn("can't read msec_per_tick");
7410696SDavid.Hollister@Sun.COM 		msec_per_tick = 0;
7510696SDavid.Hollister@Sun.COM 	}
7610696SDavid.Hollister@Sun.COM 
7710696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
7810696SDavid.Hollister@Sun.COM 	mdb_printf("Interrupt coalescing timer info\n");
7910696SDavid.Hollister@Sun.COM 	mdb_printf("-------------------------------\n");
8010696SDavid.Hollister@Sun.COM 	if (msec_per_tick == 0) {
8110696SDavid.Hollister@Sun.COM 		mdb_printf("Quantum                       : ?? ms\n");
8210696SDavid.Hollister@Sun.COM 	} else {
8310696SDavid.Hollister@Sun.COM 		mdb_printf("Quantum                       : %d ms\n",
8410696SDavid.Hollister@Sun.COM 		    m.io_intr_coal.quantum * msec_per_tick);
8510696SDavid.Hollister@Sun.COM 	}
8610696SDavid.Hollister@Sun.COM 	mdb_printf("Timer enabled                 : ");
8710696SDavid.Hollister@Sun.COM 	if (m.io_intr_coal.timer_on) {
8810696SDavid.Hollister@Sun.COM 		mdb_printf("Yes\n");
8910696SDavid.Hollister@Sun.COM 		mdb_printf("Coalescing timer value        : %d us\n",
9010696SDavid.Hollister@Sun.COM 		    m.io_intr_coal.intr_coal_timer);
9110696SDavid.Hollister@Sun.COM 	} else {
9210696SDavid.Hollister@Sun.COM 		mdb_printf("No\n");
9310696SDavid.Hollister@Sun.COM 	}
9410696SDavid.Hollister@Sun.COM 	mdb_printf("Total nsecs between interrupts: %ld\n",
9510696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.nsecs_between_intrs);
9610696SDavid.Hollister@Sun.COM 	mdb_printf("Time of last I/O interrupt    : %ld\n",
9710696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.last_io_comp);
9810696SDavid.Hollister@Sun.COM 	mdb_printf("Number of I/O interrupts      : %d\n",
9910696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.num_intrs);
10010696SDavid.Hollister@Sun.COM 	mdb_printf("Number of I/O completions     : %d\n",
10110696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.num_io_completions);
10210696SDavid.Hollister@Sun.COM 	mdb_printf("Max I/O completion interrupts : %d\n",
10310696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.max_io_completions);
10410696SDavid.Hollister@Sun.COM 	mdb_printf("Measured ECHO int latency     : %d ns\n",
10510696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.intr_latency);
10610696SDavid.Hollister@Sun.COM 	mdb_printf("Interrupt threshold           : %d\n",
10710696SDavid.Hollister@Sun.COM 	    m.io_intr_coal.intr_threshold);
10810696SDavid.Hollister@Sun.COM }
10910696SDavid.Hollister@Sun.COM 
11010696SDavid.Hollister@Sun.COM /*ARGSUSED*/
11110696SDavid.Hollister@Sun.COM static int
11210696SDavid.Hollister@Sun.COM pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv)
11310696SDavid.Hollister@Sun.COM {
11410696SDavid.Hollister@Sun.COM 	struct pmcs_phy		phy;
11510696SDavid.Hollister@Sun.COM 
11610696SDavid.Hollister@Sun.COM 	if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) !=
11710696SDavid.Hollister@Sun.COM 	    sizeof (struct pmcs_phy)) {
11810696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
11910696SDavid.Hollister@Sun.COM 	}
12010696SDavid.Hollister@Sun.COM 
12110696SDavid.Hollister@Sun.COM 	mdb_printf("%16p %2d\n", addr, phy.phynum);
12210696SDavid.Hollister@Sun.COM 
12310696SDavid.Hollister@Sun.COM 	return (0);
12410696SDavid.Hollister@Sun.COM }
12510696SDavid.Hollister@Sun.COM 
126*11334SReed.Liu@Sun.COM static int
127*11334SReed.Liu@Sun.COM display_iport_damap(dev_info_t *pdip)
128*11334SReed.Liu@Sun.COM {
129*11334SReed.Liu@Sun.COM 	int rval = DCMD_ERR;
130*11334SReed.Liu@Sun.COM 	struct dev_info dip;
131*11334SReed.Liu@Sun.COM 	scsi_hba_tran_t sht;
132*11334SReed.Liu@Sun.COM 	mdb_ctf_id_t istm_ctfid; /* impl_scsi_tgtmap_t ctf_id */
133*11334SReed.Liu@Sun.COM 	ulong_t tmd_offset = 0; /* tgtmap_dam offset to impl_scsi_tgtmap_t */
134*11334SReed.Liu@Sun.COM 	uintptr_t dam0;
135*11334SReed.Liu@Sun.COM 	uintptr_t dam1;
136*11334SReed.Liu@Sun.COM 
137*11334SReed.Liu@Sun.COM 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
138*11334SReed.Liu@Sun.COM 	    sizeof (struct dev_info)) {
139*11334SReed.Liu@Sun.COM 		return (rval);
140*11334SReed.Liu@Sun.COM 	}
141*11334SReed.Liu@Sun.COM 
142*11334SReed.Liu@Sun.COM 	if (dip.devi_driver_data == NULL) {
143*11334SReed.Liu@Sun.COM 		return (rval);
144*11334SReed.Liu@Sun.COM 	}
145*11334SReed.Liu@Sun.COM 
146*11334SReed.Liu@Sun.COM 	if (mdb_vread(&sht, sizeof (scsi_hba_tran_t),
147*11334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_driver_data) != sizeof (scsi_hba_tran_t)) {
148*11334SReed.Liu@Sun.COM 		return (rval);
149*11334SReed.Liu@Sun.COM 	}
150*11334SReed.Liu@Sun.COM 
151*11334SReed.Liu@Sun.COM 	if (sht.tran_tgtmap == NULL) {
152*11334SReed.Liu@Sun.COM 		return (rval);
153*11334SReed.Liu@Sun.COM 	}
154*11334SReed.Liu@Sun.COM 
155*11334SReed.Liu@Sun.COM 	if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid) != 0) {
156*11334SReed.Liu@Sun.COM 		return (rval);
157*11334SReed.Liu@Sun.COM 	}
158*11334SReed.Liu@Sun.COM 
159*11334SReed.Liu@Sun.COM 	if (mdb_ctf_offsetof(istm_ctfid, "tgtmap_dam", &tmd_offset) != 0) {
160*11334SReed.Liu@Sun.COM 		return (rval);
161*11334SReed.Liu@Sun.COM 	}
162*11334SReed.Liu@Sun.COM 
163*11334SReed.Liu@Sun.COM 	tmd_offset /= NBBY;
164*11334SReed.Liu@Sun.COM 	mdb_vread(&dam0, sizeof (dam0),
165*11334SReed.Liu@Sun.COM 	    (uintptr_t)(tmd_offset + (char *)sht.tran_tgtmap));
166*11334SReed.Liu@Sun.COM 	mdb_vread(&dam1, sizeof (dam1),
167*11334SReed.Liu@Sun.COM 	    (uintptr_t)(sizeof (dam0) + tmd_offset + (char *)sht.tran_tgtmap));
168*11334SReed.Liu@Sun.COM 
169*11334SReed.Liu@Sun.COM 	if (dam0 != NULL) {
170*11334SReed.Liu@Sun.COM 		rval = mdb_call_dcmd("damap", dam0, DCMD_ADDRSPEC, 0, NULL);
171*11334SReed.Liu@Sun.COM 		mdb_printf("\n");
172*11334SReed.Liu@Sun.COM 		if (rval != DCMD_OK) {
173*11334SReed.Liu@Sun.COM 			return (rval);
174*11334SReed.Liu@Sun.COM 		}
175*11334SReed.Liu@Sun.COM 	}
176*11334SReed.Liu@Sun.COM 
177*11334SReed.Liu@Sun.COM 	if (dam1 != NULL) {
178*11334SReed.Liu@Sun.COM 		rval = mdb_call_dcmd("damap", dam1, DCMD_ADDRSPEC, 0, NULL);
179*11334SReed.Liu@Sun.COM 		mdb_printf("\n");
180*11334SReed.Liu@Sun.COM 	}
181*11334SReed.Liu@Sun.COM 
182*11334SReed.Liu@Sun.COM 	return (rval);
183*11334SReed.Liu@Sun.COM }
184*11334SReed.Liu@Sun.COM 
185*11334SReed.Liu@Sun.COM /* ARGSUSED */
186*11334SReed.Liu@Sun.COM static int
187*11334SReed.Liu@Sun.COM display_iport_di_cb(uintptr_t addr, const void *wdata, void *priv)
188*11334SReed.Liu@Sun.COM {
189*11334SReed.Liu@Sun.COM 	uint_t *idx = (uint_t *)priv;
190*11334SReed.Liu@Sun.COM 	struct dev_info dip;
191*11334SReed.Liu@Sun.COM 	char devi_name[MAXNAMELEN];
192*11334SReed.Liu@Sun.COM 	char devi_addr[MAXNAMELEN];
193*11334SReed.Liu@Sun.COM 
194*11334SReed.Liu@Sun.COM 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)addr) !=
195*11334SReed.Liu@Sun.COM 	    sizeof (struct dev_info)) {
196*11334SReed.Liu@Sun.COM 		return (DCMD_ERR);
197*11334SReed.Liu@Sun.COM 	}
198*11334SReed.Liu@Sun.COM 
199*11334SReed.Liu@Sun.COM 	if (mdb_readstr(devi_name, sizeof (devi_name),
200*11334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_node_name) == -1) {
201*11334SReed.Liu@Sun.COM 		devi_name[0] = '?';
202*11334SReed.Liu@Sun.COM 		devi_name[1] = '\0';
203*11334SReed.Liu@Sun.COM 	}
204*11334SReed.Liu@Sun.COM 
205*11334SReed.Liu@Sun.COM 	if (mdb_readstr(devi_addr, sizeof (devi_addr),
206*11334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_addr) == -1) {
207*11334SReed.Liu@Sun.COM 		devi_addr[0] = '?';
208*11334SReed.Liu@Sun.COM 		devi_addr[1] = '\0';
209*11334SReed.Liu@Sun.COM 	}
210*11334SReed.Liu@Sun.COM 
211*11334SReed.Liu@Sun.COM 	mdb_printf("  %3d: @%-21s%10s@\t%p::devinfo -s\n",
212*11334SReed.Liu@Sun.COM 	    (*idx)++, devi_addr, devi_name, addr);
213*11334SReed.Liu@Sun.COM 	return (DCMD_OK);
214*11334SReed.Liu@Sun.COM }
215*11334SReed.Liu@Sun.COM 
216*11334SReed.Liu@Sun.COM /* ARGSUSED */
217*11334SReed.Liu@Sun.COM static int
218*11334SReed.Liu@Sun.COM display_iport_pi_cb(uintptr_t addr, const void *wdata, void *priv)
219*11334SReed.Liu@Sun.COM {
220*11334SReed.Liu@Sun.COM 	uint_t *idx = (uint_t *)priv;
221*11334SReed.Liu@Sun.COM 	struct mdi_pathinfo mpi;
222*11334SReed.Liu@Sun.COM 	char pi_addr[MAXNAMELEN];
223*11334SReed.Liu@Sun.COM 
224*11334SReed.Liu@Sun.COM 	if (mdb_vread(&mpi, sizeof (struct mdi_pathinfo), (uintptr_t)addr) !=
225*11334SReed.Liu@Sun.COM 	    sizeof (struct mdi_pathinfo)) {
226*11334SReed.Liu@Sun.COM 		return (DCMD_ERR);
227*11334SReed.Liu@Sun.COM 	}
228*11334SReed.Liu@Sun.COM 
229*11334SReed.Liu@Sun.COM 	if (mdb_readstr(pi_addr, sizeof (pi_addr),
230*11334SReed.Liu@Sun.COM 	    (uintptr_t)mpi.pi_addr) == -1) {
231*11334SReed.Liu@Sun.COM 		pi_addr[0] = '?';
232*11334SReed.Liu@Sun.COM 		pi_addr[1] = '\0';
233*11334SReed.Liu@Sun.COM 	}
234*11334SReed.Liu@Sun.COM 
235*11334SReed.Liu@Sun.COM 	mdb_printf("  %3d: @%-21s %p::print struct mdi_pathinfo\n",
236*11334SReed.Liu@Sun.COM 	    (*idx)++, pi_addr, addr);
237*11334SReed.Liu@Sun.COM 	return (DCMD_OK);
238*11334SReed.Liu@Sun.COM }
239*11334SReed.Liu@Sun.COM 
240*11334SReed.Liu@Sun.COM static int
241*11334SReed.Liu@Sun.COM display_iport_dtc(dev_info_t *pdip)
242*11334SReed.Liu@Sun.COM {
243*11334SReed.Liu@Sun.COM 	int rval = DCMD_ERR;
244*11334SReed.Liu@Sun.COM 	struct dev_info dip;
245*11334SReed.Liu@Sun.COM 	struct mdi_phci phci;
246*11334SReed.Liu@Sun.COM 	uint_t didx = 1;
247*11334SReed.Liu@Sun.COM 	uint_t pidx = 1;
248*11334SReed.Liu@Sun.COM 
249*11334SReed.Liu@Sun.COM 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
250*11334SReed.Liu@Sun.COM 	    sizeof (struct dev_info)) {
251*11334SReed.Liu@Sun.COM 		return (rval);
252*11334SReed.Liu@Sun.COM 	}
253*11334SReed.Liu@Sun.COM 
254*11334SReed.Liu@Sun.COM 	mdb_printf("Device tree children - dev_info:\n");
255*11334SReed.Liu@Sun.COM 	if (dip.devi_child == NULL) {
256*11334SReed.Liu@Sun.COM 		mdb_printf("\tdevi_child is NULL, no dev_info\n\n");
257*11334SReed.Liu@Sun.COM 		goto skip_di;
258*11334SReed.Liu@Sun.COM 	}
259*11334SReed.Liu@Sun.COM 
260*11334SReed.Liu@Sun.COM 	/*
261*11334SReed.Liu@Sun.COM 	 * First, we dump the iport's children dev_info node information.
262*11334SReed.Liu@Sun.COM 	 * use existing walker: devinfo_siblings
263*11334SReed.Liu@Sun.COM 	 */
264*11334SReed.Liu@Sun.COM 	mdb_printf("\t#: @unit-address               name@\tdrill-down\n");
265*11334SReed.Liu@Sun.COM 	rval = mdb_pwalk("devinfo_siblings", display_iport_di_cb,
266*11334SReed.Liu@Sun.COM 	    (void *)&didx, (uintptr_t)dip.devi_child);
267*11334SReed.Liu@Sun.COM 	mdb_printf("\n");
268*11334SReed.Liu@Sun.COM 
269*11334SReed.Liu@Sun.COM skip_di:
270*11334SReed.Liu@Sun.COM 	/*
271*11334SReed.Liu@Sun.COM 	 * Then we try to dump the iport's path_info node information.
272*11334SReed.Liu@Sun.COM 	 * use existing walker: mdipi_phci_list
273*11334SReed.Liu@Sun.COM 	 */
274*11334SReed.Liu@Sun.COM 	mdb_printf("Device tree children - path_info:\n");
275*11334SReed.Liu@Sun.COM 	if (mdb_vread(&phci, sizeof (struct mdi_phci),
276*11334SReed.Liu@Sun.COM 	    (uintptr_t)dip.devi_mdi_xhci) != sizeof (struct mdi_phci)) {
277*11334SReed.Liu@Sun.COM 		mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n");
278*11334SReed.Liu@Sun.COM 		return (rval);
279*11334SReed.Liu@Sun.COM 	}
280*11334SReed.Liu@Sun.COM 
281*11334SReed.Liu@Sun.COM 	if (phci.ph_path_head == NULL) {
282*11334SReed.Liu@Sun.COM 		mdb_printf("\tph_path_head is NULL, no path_info\n\n");
283*11334SReed.Liu@Sun.COM 		return (rval);
284*11334SReed.Liu@Sun.COM 	}
285*11334SReed.Liu@Sun.COM 
286*11334SReed.Liu@Sun.COM 	mdb_printf("\t#: @unit-address          drill-down\n");
287*11334SReed.Liu@Sun.COM 	rval = mdb_pwalk("mdipi_phci_list", display_iport_pi_cb,
288*11334SReed.Liu@Sun.COM 	    (void *)&pidx, (uintptr_t)phci.ph_path_head);
289*11334SReed.Liu@Sun.COM 	mdb_printf("\n");
290*11334SReed.Liu@Sun.COM 	return (rval);
291*11334SReed.Liu@Sun.COM }
292*11334SReed.Liu@Sun.COM 
293*11334SReed.Liu@Sun.COM static void
294*11334SReed.Liu@Sun.COM display_iport_more(dev_info_t *dip, per_iport_setting_t *pis)
295*11334SReed.Liu@Sun.COM {
296*11334SReed.Liu@Sun.COM 	if (pis->pis_damap_info) {
297*11334SReed.Liu@Sun.COM 		(void) display_iport_damap(dip);
298*11334SReed.Liu@Sun.COM 	}
299*11334SReed.Liu@Sun.COM 
300*11334SReed.Liu@Sun.COM 	if (pis->pis_dtc_info) {
301*11334SReed.Liu@Sun.COM 		(void) display_iport_dtc(dip);
302*11334SReed.Liu@Sun.COM 	}
303*11334SReed.Liu@Sun.COM }
304*11334SReed.Liu@Sun.COM 
30510696SDavid.Hollister@Sun.COM /*ARGSUSED*/
30610696SDavid.Hollister@Sun.COM static int
30710696SDavid.Hollister@Sun.COM pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv)
30810696SDavid.Hollister@Sun.COM {
30910696SDavid.Hollister@Sun.COM 	struct pmcs_iport	iport;
31010696SDavid.Hollister@Sun.COM 	uintptr_t		list_addr;
31110696SDavid.Hollister@Sun.COM 	char			*ua_state;
31210696SDavid.Hollister@Sun.COM 	char			portid[4];
31310696SDavid.Hollister@Sun.COM 	char			unit_address[34];
314*11334SReed.Liu@Sun.COM 	per_iport_setting_t	*pis = (per_iport_setting_t *)priv;
31510696SDavid.Hollister@Sun.COM 
31610696SDavid.Hollister@Sun.COM 	if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) !=
31710696SDavid.Hollister@Sun.COM 	    sizeof (struct pmcs_iport)) {
31810696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
31910696SDavid.Hollister@Sun.COM 	}
32010696SDavid.Hollister@Sun.COM 
32110696SDavid.Hollister@Sun.COM 	if (mdb_readstr(unit_address, sizeof (unit_address),
32210696SDavid.Hollister@Sun.COM 	    (uintptr_t)(iport.ua)) == -1) {
32310696SDavid.Hollister@Sun.COM 		strncpy(unit_address, "Unset", sizeof (unit_address));
32410696SDavid.Hollister@Sun.COM 	}
32510696SDavid.Hollister@Sun.COM 
32610696SDavid.Hollister@Sun.COM 	if (iport.portid == 0xffff) {
32710696SDavid.Hollister@Sun.COM 		mdb_snprintf(portid, sizeof (portid), "%s", "-");
32810696SDavid.Hollister@Sun.COM 	} else {
32910696SDavid.Hollister@Sun.COM 		mdb_snprintf(portid, sizeof (portid), "%d", iport.portid);
33010696SDavid.Hollister@Sun.COM 	}
33110696SDavid.Hollister@Sun.COM 
33210696SDavid.Hollister@Sun.COM 	switch (iport.ua_state) {
33310696SDavid.Hollister@Sun.COM 	case UA_INACTIVE:
33410696SDavid.Hollister@Sun.COM 		ua_state = "Inactive";
33510696SDavid.Hollister@Sun.COM 		break;
33610696SDavid.Hollister@Sun.COM 	case UA_PEND_ACTIVATE:
33710696SDavid.Hollister@Sun.COM 		ua_state = "PendActivate";
33810696SDavid.Hollister@Sun.COM 		break;
33910696SDavid.Hollister@Sun.COM 	case UA_ACTIVE:
34010696SDavid.Hollister@Sun.COM 		ua_state = "Active";
34110696SDavid.Hollister@Sun.COM 		break;
34210696SDavid.Hollister@Sun.COM 	case UA_PEND_DEACTIVATE:
34310696SDavid.Hollister@Sun.COM 		ua_state = "PendDeactivate";
34410696SDavid.Hollister@Sun.COM 		break;
34510696SDavid.Hollister@Sun.COM 	default:
34610696SDavid.Hollister@Sun.COM 		ua_state = "Unknown";
34710696SDavid.Hollister@Sun.COM 	}
34810696SDavid.Hollister@Sun.COM 
34910696SDavid.Hollister@Sun.COM 	if (strlen(unit_address) < 3) {
35010696SDavid.Hollister@Sun.COM 		/* Standard iport unit address */
35110696SDavid.Hollister@Sun.COM 		mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State",
35210696SDavid.Hollister@Sun.COM 		    "PortID", "NumPhys", "DIP\n");
35310696SDavid.Hollister@Sun.COM 		mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr,
35410696SDavid.Hollister@Sun.COM 		    ua_state, portid, iport.nphy, iport.dip);
35510696SDavid.Hollister@Sun.COM 	} else {
35610696SDavid.Hollister@Sun.COM 		/* Temporary iport unit address */
35710696SDavid.Hollister@Sun.COM 		mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport",
35810696SDavid.Hollister@Sun.COM 		    "UA State", "PortID", "NumPhys", "DIP\n");
35910696SDavid.Hollister@Sun.COM 		mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr,
36010696SDavid.Hollister@Sun.COM 		    ua_state, portid, iport.nphy, iport.dip);
36110696SDavid.Hollister@Sun.COM 	}
36210696SDavid.Hollister@Sun.COM 
36310696SDavid.Hollister@Sun.COM 	if (iport.nphy > 0) {
36410696SDavid.Hollister@Sun.COM 		mdb_inc_indent(4);
36510696SDavid.Hollister@Sun.COM 		mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
36610696SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
36710696SDavid.Hollister@Sun.COM 		list_addr =
36810696SDavid.Hollister@Sun.COM 		    (uintptr_t)(addr + offsetof(struct pmcs_iport, phys));
36910696SDavid.Hollister@Sun.COM 		if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL,
37010696SDavid.Hollister@Sun.COM 		    list_addr) == -1) {
37110696SDavid.Hollister@Sun.COM 			mdb_warn("pmcs iport walk failed");
37210696SDavid.Hollister@Sun.COM 		}
37310696SDavid.Hollister@Sun.COM 		mdb_dec_indent(6);
37410696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
37510696SDavid.Hollister@Sun.COM 	}
37610696SDavid.Hollister@Sun.COM 
377*11334SReed.Liu@Sun.COM 	/*
378*11334SReed.Liu@Sun.COM 	 * See if we need to show more information based on 'd' or 'm' options
379*11334SReed.Liu@Sun.COM 	 */
380*11334SReed.Liu@Sun.COM 	display_iport_more(iport.dip, pis);
381*11334SReed.Liu@Sun.COM 
38210696SDavid.Hollister@Sun.COM 	return (0);
38310696SDavid.Hollister@Sun.COM }
38410696SDavid.Hollister@Sun.COM 
38510696SDavid.Hollister@Sun.COM /*ARGSUSED*/
38610696SDavid.Hollister@Sun.COM static void
387*11334SReed.Liu@Sun.COM display_iport(struct pmcs_hw m, uintptr_t addr, int verbose,
388*11334SReed.Liu@Sun.COM     per_iport_setting_t *pis)
38910696SDavid.Hollister@Sun.COM {
39010696SDavid.Hollister@Sun.COM 	uintptr_t	list_addr;
39110696SDavid.Hollister@Sun.COM 
39210696SDavid.Hollister@Sun.COM 	if (m.iports_attached) {
39310696SDavid.Hollister@Sun.COM 		mdb_printf("Iport information:\n");
39410696SDavid.Hollister@Sun.COM 		mdb_printf("-----------------\n");
39510696SDavid.Hollister@Sun.COM 	} else {
39610696SDavid.Hollister@Sun.COM 		mdb_printf("No Iports found.\n\n");
39710696SDavid.Hollister@Sun.COM 		return;
39810696SDavid.Hollister@Sun.COM 	}
39910696SDavid.Hollister@Sun.COM 
40010696SDavid.Hollister@Sun.COM 	list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports));
40110696SDavid.Hollister@Sun.COM 
402*11334SReed.Liu@Sun.COM 	if (mdb_pwalk("list", pmcs_iport_walk_cb, pis, list_addr) == -1) {
40310696SDavid.Hollister@Sun.COM 		mdb_warn("pmcs iport walk failed");
40410696SDavid.Hollister@Sun.COM 	}
40510696SDavid.Hollister@Sun.COM 
40610696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
40710696SDavid.Hollister@Sun.COM }
40810696SDavid.Hollister@Sun.COM 
40911048SDavid.Hollister@Sun.COM /* ARGSUSED */
41011048SDavid.Hollister@Sun.COM static int
41111048SDavid.Hollister@Sun.COM pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv)
41211048SDavid.Hollister@Sun.COM {
41311048SDavid.Hollister@Sun.COM 	pmcs_phy_t phy;
41411048SDavid.Hollister@Sun.COM 
41511048SDavid.Hollister@Sun.COM 	if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) {
41611048SDavid.Hollister@Sun.COM 		mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p",
41711048SDavid.Hollister@Sun.COM 		    (void *)addr);
41811048SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
41911048SDavid.Hollister@Sun.COM 	}
42011048SDavid.Hollister@Sun.COM 
42111048SDavid.Hollister@Sun.COM 	if (phy.configured && (phy.target == NULL)) {
42211048SDavid.Hollister@Sun.COM 		mdb_printf("SAS address: ");
42311048SDavid.Hollister@Sun.COM 		print_sas_address(&phy);
42411048SDavid.Hollister@Sun.COM 		mdb_printf("  DType: ");
42511048SDavid.Hollister@Sun.COM 		switch (phy.dtype) {
42611048SDavid.Hollister@Sun.COM 		case SAS:
42711048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "SAS");
42811048SDavid.Hollister@Sun.COM 			break;
42911048SDavid.Hollister@Sun.COM 		case SATA:
43011048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "SATA");
43111048SDavid.Hollister@Sun.COM 			break;
43211048SDavid.Hollister@Sun.COM 		case EXPANDER:
43311048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "SMP");
43411048SDavid.Hollister@Sun.COM 			break;
43511048SDavid.Hollister@Sun.COM 		default:
43611048SDavid.Hollister@Sun.COM 			mdb_printf("%4s", "N/A");
43711048SDavid.Hollister@Sun.COM 			break;
43811048SDavid.Hollister@Sun.COM 		}
43911048SDavid.Hollister@Sun.COM 		mdb_printf("  Path: %s\n", phy.path);
44011048SDavid.Hollister@Sun.COM 	}
44111048SDavid.Hollister@Sun.COM 
44211048SDavid.Hollister@Sun.COM 	return (0);
44311048SDavid.Hollister@Sun.COM }
44411048SDavid.Hollister@Sun.COM 
44511048SDavid.Hollister@Sun.COM static void
44611048SDavid.Hollister@Sun.COM display_unconfigured_targets(uintptr_t addr)
44711048SDavid.Hollister@Sun.COM {
44811048SDavid.Hollister@Sun.COM 	mdb_printf("Unconfigured target SAS address:\n\n");
44911048SDavid.Hollister@Sun.COM 
45011048SDavid.Hollister@Sun.COM 	if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) {
45111048SDavid.Hollister@Sun.COM 		mdb_warn("pmcs phys walk failed");
45211048SDavid.Hollister@Sun.COM 	}
45311048SDavid.Hollister@Sun.COM }
45411048SDavid.Hollister@Sun.COM 
45510743SDavid.Hollister@Sun.COM static void
45610743SDavid.Hollister@Sun.COM display_completion_queue(struct pmcs_hw ss)
45710743SDavid.Hollister@Sun.COM {
45810743SDavid.Hollister@Sun.COM 	pmcs_iocomp_cb_t ccb, *ccbp;
45910743SDavid.Hollister@Sun.COM 	pmcwork_t work;
46010743SDavid.Hollister@Sun.COM 
46110743SDavid.Hollister@Sun.COM 	if (ss.iocomp_cb_head == NULL) {
46210743SDavid.Hollister@Sun.COM 		mdb_printf("Completion queue is empty.\n");
46310743SDavid.Hollister@Sun.COM 		return;
46410743SDavid.Hollister@Sun.COM 	}
46510743SDavid.Hollister@Sun.COM 
46610743SDavid.Hollister@Sun.COM 	ccbp = ss.iocomp_cb_head;
46710743SDavid.Hollister@Sun.COM 	mdb_printf("%8s %10s %20s %8s %8s O D\n",
46810743SDavid.Hollister@Sun.COM 	    "HTag", "State", "Phy Path", "Target", "Timer");
46910743SDavid.Hollister@Sun.COM 
47010743SDavid.Hollister@Sun.COM 	while (ccbp) {
47110743SDavid.Hollister@Sun.COM 		if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t),
47210743SDavid.Hollister@Sun.COM 		    (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) {
47310743SDavid.Hollister@Sun.COM 			mdb_warn("Unable to read completion queue entry\n");
47410743SDavid.Hollister@Sun.COM 			return;
47510743SDavid.Hollister@Sun.COM 		}
47610743SDavid.Hollister@Sun.COM 
47710743SDavid.Hollister@Sun.COM 		if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk)
47810743SDavid.Hollister@Sun.COM 		    != sizeof (pmcwork_t)) {
47910743SDavid.Hollister@Sun.COM 			mdb_warn("Unable to read work structure\n");
48010743SDavid.Hollister@Sun.COM 			return;
48110743SDavid.Hollister@Sun.COM 		}
48210743SDavid.Hollister@Sun.COM 
48310743SDavid.Hollister@Sun.COM 		/*
48410743SDavid.Hollister@Sun.COM 		 * Only print the work structure if it's still active.  If
48510743SDavid.Hollister@Sun.COM 		 * it's not, it's been completed since we started looking at
48610743SDavid.Hollister@Sun.COM 		 * it.
48710743SDavid.Hollister@Sun.COM 		 */
48810743SDavid.Hollister@Sun.COM 		if (work.state != PMCS_WORK_STATE_NIL) {
48910743SDavid.Hollister@Sun.COM 			display_one_work(&work, 0, 0);
49010743SDavid.Hollister@Sun.COM 		}
49110743SDavid.Hollister@Sun.COM 		ccbp = ccb.next;
49210743SDavid.Hollister@Sun.COM 	}
49310743SDavid.Hollister@Sun.COM }
49410743SDavid.Hollister@Sun.COM 
49510696SDavid.Hollister@Sun.COM /*ARGSUSED*/
49610696SDavid.Hollister@Sun.COM static void
49710696SDavid.Hollister@Sun.COM display_hwinfo(struct pmcs_hw m, int verbose)
49810696SDavid.Hollister@Sun.COM {
49910696SDavid.Hollister@Sun.COM 	struct pmcs_hw	*mp = &m;
50010696SDavid.Hollister@Sun.COM 	char		*fwsupport;
50110696SDavid.Hollister@Sun.COM 
50210696SDavid.Hollister@Sun.COM 	switch (PMCS_FW_TYPE(mp)) {
50310696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_RELEASED:
50410696SDavid.Hollister@Sun.COM 		fwsupport = "Released";
50510696SDavid.Hollister@Sun.COM 		break;
50610696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_DEVELOPMENT:
50710696SDavid.Hollister@Sun.COM 		fwsupport = "Development";
50810696SDavid.Hollister@Sun.COM 		break;
50910696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_ALPHA:
51010696SDavid.Hollister@Sun.COM 		fwsupport = "Alpha";
51110696SDavid.Hollister@Sun.COM 		break;
51210696SDavid.Hollister@Sun.COM 	case PMCS_FW_TYPE_BETA:
51310696SDavid.Hollister@Sun.COM 		fwsupport = "Beta";
51410696SDavid.Hollister@Sun.COM 		break;
51510696SDavid.Hollister@Sun.COM 	default:
51610696SDavid.Hollister@Sun.COM 		fwsupport = "Special";
51710696SDavid.Hollister@Sun.COM 		break;
51810696SDavid.Hollister@Sun.COM 	}
51910696SDavid.Hollister@Sun.COM 
52010696SDavid.Hollister@Sun.COM 	mdb_printf("\nHardware information:\n");
52110696SDavid.Hollister@Sun.COM 	mdb_printf("---------------------\n");
52210696SDavid.Hollister@Sun.COM 
52310696SDavid.Hollister@Sun.COM 	mdb_printf("Chip revision:    %c\n", 'A' + m.chiprev);
52410696SDavid.Hollister@Sun.COM 	mdb_printf("SAS WWID:         %"PRIx64"\n", m.sas_wwns[0]);
52510696SDavid.Hollister@Sun.COM 	mdb_printf("Firmware version: %x.%x.%x (%s)\n",
52610696SDavid.Hollister@Sun.COM 	    PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp),
52710696SDavid.Hollister@Sun.COM 	    fwsupport);
52810696SDavid.Hollister@Sun.COM 
52910696SDavid.Hollister@Sun.COM 	mdb_printf("Number of PHYs:   %d\n", m.nphy);
53010696SDavid.Hollister@Sun.COM 	mdb_printf("Maximum commands: %d\n", m.max_cmd);
53110696SDavid.Hollister@Sun.COM 	mdb_printf("Maximum devices:  %d\n", m.max_dev);
53210696SDavid.Hollister@Sun.COM 	mdb_printf("I/O queue depth:  %d\n", m.ioq_depth);
53310696SDavid.Hollister@Sun.COM 	if (m.fwlog == 0) {
53410696SDavid.Hollister@Sun.COM 		mdb_printf("Firmware logging: Disabled\n");
53510696SDavid.Hollister@Sun.COM 	} else {
53610696SDavid.Hollister@Sun.COM 		mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog);
53710696SDavid.Hollister@Sun.COM 	}
53810696SDavid.Hollister@Sun.COM }
53910696SDavid.Hollister@Sun.COM 
54010696SDavid.Hollister@Sun.COM static void
54110696SDavid.Hollister@Sun.COM display_targets(struct pmcs_hw m, int verbose, int totals_only)
54210696SDavid.Hollister@Sun.COM {
54310696SDavid.Hollister@Sun.COM 	char		*dtype;
54410696SDavid.Hollister@Sun.COM 	pmcs_xscsi_t	xs;
54510696SDavid.Hollister@Sun.COM 	pmcs_phy_t	phy;
54610696SDavid.Hollister@Sun.COM 	uint16_t	max_dev, idx;
54710696SDavid.Hollister@Sun.COM 	uint32_t	sas_targets = 0, smp_targets = 0, sata_targets = 0;
54810696SDavid.Hollister@Sun.COM 
54910696SDavid.Hollister@Sun.COM 	max_dev = m.max_dev;
55010696SDavid.Hollister@Sun.COM 
55110696SDavid.Hollister@Sun.COM 	if (targets == NULL) {
55210696SDavid.Hollister@Sun.COM 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
55310696SDavid.Hollister@Sun.COM 	}
55410696SDavid.Hollister@Sun.COM 
55510696SDavid.Hollister@Sun.COM 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
55610696SDavid.Hollister@Sun.COM 		NOREAD(targets, m.targets);
55710696SDavid.Hollister@Sun.COM 		return;
55810696SDavid.Hollister@Sun.COM 	}
55910696SDavid.Hollister@Sun.COM 
56010696SDavid.Hollister@Sun.COM 	if (!totals_only) {
56110696SDavid.Hollister@Sun.COM 		mdb_printf("\nTarget information:\n");
56210696SDavid.Hollister@Sun.COM 		mdb_printf("---------------------------------------\n");
56310696SDavid.Hollister@Sun.COM 		mdb_printf("VTGT %-16s %-16s %-5s %8s %s", "SAS Address",
56410696SDavid.Hollister@Sun.COM 		    "PHY Address", "DType", "Active", "DS");
56510696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
56610696SDavid.Hollister@Sun.COM 	}
56710696SDavid.Hollister@Sun.COM 
56810696SDavid.Hollister@Sun.COM 	for (idx = 0; idx < max_dev; idx++) {
56910696SDavid.Hollister@Sun.COM 		if (targets[idx] == NULL) {
57010696SDavid.Hollister@Sun.COM 			continue;
57110696SDavid.Hollister@Sun.COM 		}
57210696SDavid.Hollister@Sun.COM 
57310696SDavid.Hollister@Sun.COM 		if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) {
57410696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_xscsi_t, targets[idx]);
57510696SDavid.Hollister@Sun.COM 			continue;
57610696SDavid.Hollister@Sun.COM 		}
57710696SDavid.Hollister@Sun.COM 
57810696SDavid.Hollister@Sun.COM 		/*
57910755SJesse.Butler@Sun.COM 		 * It has to be new or assigned to be of interest.
58010696SDavid.Hollister@Sun.COM 		 */
58110755SJesse.Butler@Sun.COM 		if (xs.new == 0 && xs.assigned == 0) {
58210696SDavid.Hollister@Sun.COM 			continue;
58310696SDavid.Hollister@Sun.COM 		}
58410696SDavid.Hollister@Sun.COM 
58510696SDavid.Hollister@Sun.COM 		switch (xs.dtype) {
58610696SDavid.Hollister@Sun.COM 		case NOTHING:
58710696SDavid.Hollister@Sun.COM 			dtype = "None";
58810696SDavid.Hollister@Sun.COM 			break;
58910696SDavid.Hollister@Sun.COM 		case SATA:
59010696SDavid.Hollister@Sun.COM 			dtype = "SATA";
59110696SDavid.Hollister@Sun.COM 			sata_targets++;
59210696SDavid.Hollister@Sun.COM 			break;
59310696SDavid.Hollister@Sun.COM 		case SAS:
59410696SDavid.Hollister@Sun.COM 			dtype = "SAS";
59510696SDavid.Hollister@Sun.COM 			sas_targets++;
59610696SDavid.Hollister@Sun.COM 			break;
59710696SDavid.Hollister@Sun.COM 		case EXPANDER:
59810696SDavid.Hollister@Sun.COM 			dtype = "SMP";
59910696SDavid.Hollister@Sun.COM 			smp_targets++;
60010696SDavid.Hollister@Sun.COM 			break;
60110696SDavid.Hollister@Sun.COM 		}
60210696SDavid.Hollister@Sun.COM 
60310696SDavid.Hollister@Sun.COM 		if (totals_only) {
60410696SDavid.Hollister@Sun.COM 			continue;
60510696SDavid.Hollister@Sun.COM 		}
60610696SDavid.Hollister@Sun.COM 
60710696SDavid.Hollister@Sun.COM 		if (xs.phy) {
60810696SDavid.Hollister@Sun.COM 			if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) {
60910696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_phy_t, xs.phy);
61010696SDavid.Hollister@Sun.COM 				continue;
61110696SDavid.Hollister@Sun.COM 			}
61210696SDavid.Hollister@Sun.COM 			mdb_printf("%4d ", idx);
61310696SDavid.Hollister@Sun.COM 			print_sas_address(&phy);
61410696SDavid.Hollister@Sun.COM 			mdb_printf(" %16p", xs.phy);
61510696SDavid.Hollister@Sun.COM 		} else {
61610696SDavid.Hollister@Sun.COM 			mdb_printf("%4d %16s", idx, "<no phy avail>");
61710696SDavid.Hollister@Sun.COM 		}
61810696SDavid.Hollister@Sun.COM 		mdb_printf(" %5s", dtype);
61910696SDavid.Hollister@Sun.COM 		mdb_printf(" %8d", xs.actv_cnt);
62010696SDavid.Hollister@Sun.COM 		mdb_printf(" %2d", xs.dev_state);
62110696SDavid.Hollister@Sun.COM 
62210696SDavid.Hollister@Sun.COM 		if (verbose) {
62310696SDavid.Hollister@Sun.COM 			if (xs.new) {
62410696SDavid.Hollister@Sun.COM 				mdb_printf(" new");
62510755SJesse.Butler@Sun.COM 			}
62610755SJesse.Butler@Sun.COM 			if (xs.assigned) {
62710696SDavid.Hollister@Sun.COM 				mdb_printf(" assigned");
62810696SDavid.Hollister@Sun.COM 			}
62910696SDavid.Hollister@Sun.COM 			if (xs.draining) {
63010696SDavid.Hollister@Sun.COM 				mdb_printf(" draining");
63110696SDavid.Hollister@Sun.COM 			}
63210696SDavid.Hollister@Sun.COM 			if (xs.reset_wait) {
63310696SDavid.Hollister@Sun.COM 				mdb_printf(" reset_wait");
63410696SDavid.Hollister@Sun.COM 			}
63510696SDavid.Hollister@Sun.COM 			if (xs.resetting) {
63610696SDavid.Hollister@Sun.COM 				mdb_printf(" resetting");
63710696SDavid.Hollister@Sun.COM 			}
63810696SDavid.Hollister@Sun.COM 			if (xs.recover_wait) {
63910696SDavid.Hollister@Sun.COM 				mdb_printf(" recover_wait");
64010696SDavid.Hollister@Sun.COM 			}
64110696SDavid.Hollister@Sun.COM 			if (xs.recovering) {
64210696SDavid.Hollister@Sun.COM 				mdb_printf(" recovering");
64310696SDavid.Hollister@Sun.COM 			}
64410696SDavid.Hollister@Sun.COM 			if (xs.event_recovery) {
64510696SDavid.Hollister@Sun.COM 				mdb_printf(" event recovery");
64610696SDavid.Hollister@Sun.COM 			}
64710696SDavid.Hollister@Sun.COM 			if (xs.special_running) {
64810696SDavid.Hollister@Sun.COM 				mdb_printf(" special_active");
64910696SDavid.Hollister@Sun.COM 			}
65010696SDavid.Hollister@Sun.COM 			if (xs.ncq) {
65110696SDavid.Hollister@Sun.COM 				mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
65210696SDavid.Hollister@Sun.COM 				    xs.tagmap, xs.qdepth);
65310696SDavid.Hollister@Sun.COM 			} else if (xs.pio) {
65410696SDavid.Hollister@Sun.COM 				mdb_printf(" pio");
65510696SDavid.Hollister@Sun.COM 			}
65610696SDavid.Hollister@Sun.COM 		}
65710696SDavid.Hollister@Sun.COM 
65810696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
65910696SDavid.Hollister@Sun.COM 	}
66010696SDavid.Hollister@Sun.COM 
66110696SDavid.Hollister@Sun.COM 	if (!totals_only) {
66210696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
66310696SDavid.Hollister@Sun.COM 	}
66410696SDavid.Hollister@Sun.COM 
66510696SDavid.Hollister@Sun.COM 	mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
66610696SDavid.Hollister@Sun.COM 	    "Configured targets:", (sas_targets + sata_targets + smp_targets),
66710696SDavid.Hollister@Sun.COM 	    sas_targets, sata_targets, smp_targets);
66810696SDavid.Hollister@Sun.COM }
66910696SDavid.Hollister@Sun.COM 
67010743SDavid.Hollister@Sun.COM static char *
67110743SDavid.Hollister@Sun.COM work_state_to_string(uint32_t state)
67210743SDavid.Hollister@Sun.COM {
67310743SDavid.Hollister@Sun.COM 	char *state_string;
67410743SDavid.Hollister@Sun.COM 
67510743SDavid.Hollister@Sun.COM 	switch (state) {
67610743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_NIL:
67710743SDavid.Hollister@Sun.COM 		state_string = "Free";
67810743SDavid.Hollister@Sun.COM 		break;
67910743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_READY:
68010743SDavid.Hollister@Sun.COM 		state_string = "Ready";
68110743SDavid.Hollister@Sun.COM 		break;
68210743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_ONCHIP:
68310743SDavid.Hollister@Sun.COM 		state_string = "On Chip";
68410743SDavid.Hollister@Sun.COM 		break;
68510743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_INTR:
68610743SDavid.Hollister@Sun.COM 		state_string = "In Intr";
68710743SDavid.Hollister@Sun.COM 		break;
68810743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_IOCOMPQ:
68910743SDavid.Hollister@Sun.COM 		state_string = "I/O Comp";
69010743SDavid.Hollister@Sun.COM 		break;
69110743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_ABORTED:
69210743SDavid.Hollister@Sun.COM 		state_string = "I/O Aborted";
69310743SDavid.Hollister@Sun.COM 		break;
69410743SDavid.Hollister@Sun.COM 	case PMCS_WORK_STATE_TIMED_OUT:
69510743SDavid.Hollister@Sun.COM 		state_string = "I/O Timed Out";
69610743SDavid.Hollister@Sun.COM 		break;
69710743SDavid.Hollister@Sun.COM 	default:
69810743SDavid.Hollister@Sun.COM 		state_string = "INVALID";
69910743SDavid.Hollister@Sun.COM 		break;
70010743SDavid.Hollister@Sun.COM 	}
70110743SDavid.Hollister@Sun.COM 
70210743SDavid.Hollister@Sun.COM 	return (state_string);
70310743SDavid.Hollister@Sun.COM }
70410743SDavid.Hollister@Sun.COM 
70510743SDavid.Hollister@Sun.COM static void
70610743SDavid.Hollister@Sun.COM display_one_work(pmcwork_t *wp, int verbose, int idx)
70710743SDavid.Hollister@Sun.COM {
70810743SDavid.Hollister@Sun.COM 	char		*state, *last_state;
70910743SDavid.Hollister@Sun.COM 	char		*path;
71010743SDavid.Hollister@Sun.COM 	pmcs_xscsi_t	xs;
71110743SDavid.Hollister@Sun.COM 	pmcs_phy_t	phy;
71210743SDavid.Hollister@Sun.COM 	int		tgt;
71310743SDavid.Hollister@Sun.COM 
71410743SDavid.Hollister@Sun.COM 	state = work_state_to_string(wp->state);
71510743SDavid.Hollister@Sun.COM 	last_state = work_state_to_string(wp->last_state);
71610743SDavid.Hollister@Sun.COM 
71710743SDavid.Hollister@Sun.COM 	if (wp->ssp_event && wp->ssp_event != 0xffffffff) {
71810743SDavid.Hollister@Sun.COM 		mdb_printf("SSP event 0x%x", wp->ssp_event);
71910743SDavid.Hollister@Sun.COM 	}
72010743SDavid.Hollister@Sun.COM 
72110743SDavid.Hollister@Sun.COM 	tgt = -1;
72210743SDavid.Hollister@Sun.COM 	if (wp->xp) {
72310743SDavid.Hollister@Sun.COM 		if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) {
72410743SDavid.Hollister@Sun.COM 			NOREAD(pmcs_xscsi_t, wp->xp);
72510743SDavid.Hollister@Sun.COM 		} else {
72610743SDavid.Hollister@Sun.COM 			tgt = xs.target_num;
72710743SDavid.Hollister@Sun.COM 		}
72810743SDavid.Hollister@Sun.COM 	}
72910743SDavid.Hollister@Sun.COM 	if (wp->phy) {
73010743SDavid.Hollister@Sun.COM 		if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) {
73110743SDavid.Hollister@Sun.COM 			NOREAD(pmcs_phy_t, wp->phy);
73210743SDavid.Hollister@Sun.COM 		}
73310743SDavid.Hollister@Sun.COM 		path = phy.path;
73410743SDavid.Hollister@Sun.COM 	} else {
73510743SDavid.Hollister@Sun.COM 		path = "N/A";
73610743SDavid.Hollister@Sun.COM 	}
73710743SDavid.Hollister@Sun.COM 
73810743SDavid.Hollister@Sun.COM 	if (verbose) {
73910743SDavid.Hollister@Sun.COM 		mdb_printf("%4d ", idx);
74010743SDavid.Hollister@Sun.COM 	}
74110743SDavid.Hollister@Sun.COM 	if (tgt == -1) {
74210743SDavid.Hollister@Sun.COM 		mdb_printf("%08x %10s %20s      N/A %8u %1d %1d ",
74310743SDavid.Hollister@Sun.COM 		    wp->htag, state, path, wp->timer,
74410743SDavid.Hollister@Sun.COM 		    wp->onwire, wp->dead);
74510743SDavid.Hollister@Sun.COM 	} else {
74610743SDavid.Hollister@Sun.COM 		mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
74710743SDavid.Hollister@Sun.COM 		    wp->htag, state, path, tgt, wp->timer,
74810743SDavid.Hollister@Sun.COM 		    wp->onwire, wp->dead);
74910743SDavid.Hollister@Sun.COM 	}
75010743SDavid.Hollister@Sun.COM 	if (verbose) {
75110743SDavid.Hollister@Sun.COM 		mdb_printf("%08x %10s 0x%016p 0x%016p\n",
75210743SDavid.Hollister@Sun.COM 		    wp->last_htag, last_state, wp->last_phy, wp->last_xp);
75310743SDavid.Hollister@Sun.COM 	} else {
75410743SDavid.Hollister@Sun.COM 		mdb_printf("\n");
75510743SDavid.Hollister@Sun.COM 	}
75610743SDavid.Hollister@Sun.COM }
75710743SDavid.Hollister@Sun.COM 
75810696SDavid.Hollister@Sun.COM static void
75910696SDavid.Hollister@Sun.COM display_work(struct pmcs_hw m, int verbose)
76010696SDavid.Hollister@Sun.COM {
76110696SDavid.Hollister@Sun.COM 	int		idx;
76210743SDavid.Hollister@Sun.COM 	boolean_t	header_printed = B_FALSE;
76310696SDavid.Hollister@Sun.COM 	pmcwork_t	work, *wp = &work;
76410696SDavid.Hollister@Sun.COM 	uintptr_t	_wp;
76510696SDavid.Hollister@Sun.COM 
76610696SDavid.Hollister@Sun.COM 	mdb_printf("\nActive Work structure information:\n");
76710696SDavid.Hollister@Sun.COM 	mdb_printf("----------------------------------\n");
76810696SDavid.Hollister@Sun.COM 
76910696SDavid.Hollister@Sun.COM 	_wp = (uintptr_t)m.work;
77010696SDavid.Hollister@Sun.COM 
77110696SDavid.Hollister@Sun.COM 	for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
77210696SDavid.Hollister@Sun.COM 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
77310696SDavid.Hollister@Sun.COM 			NOREAD(pmcwork_t, _wp);
77410696SDavid.Hollister@Sun.COM 			continue;
77510696SDavid.Hollister@Sun.COM 		}
77610743SDavid.Hollister@Sun.COM 
77710743SDavid.Hollister@Sun.COM 		if (!verbose && (wp->htag == PMCS_TAG_TYPE_FREE)) {
77810696SDavid.Hollister@Sun.COM 			continue;
77910696SDavid.Hollister@Sun.COM 		}
78010743SDavid.Hollister@Sun.COM 
78110743SDavid.Hollister@Sun.COM 		if (header_printed == B_FALSE) {
78210743SDavid.Hollister@Sun.COM 			if (verbose) {
78310743SDavid.Hollister@Sun.COM 				mdb_printf("%4s ", "Idx");
78410743SDavid.Hollister@Sun.COM 			}
78510743SDavid.Hollister@Sun.COM 			mdb_printf("%8s %10s %20s %8s %8s O D ",
78610696SDavid.Hollister@Sun.COM 			    "HTag", "State", "Phy Path", "Target", "Timer");
78710743SDavid.Hollister@Sun.COM 			if (verbose) {
78810743SDavid.Hollister@Sun.COM 				mdb_printf("%8s %10s %18s %18s\n", "LastHTAG",
78910743SDavid.Hollister@Sun.COM 				    "LastState", "LastPHY", "LastTgt");
79010743SDavid.Hollister@Sun.COM 			} else {
79110743SDavid.Hollister@Sun.COM 				mdb_printf("\n");
79210743SDavid.Hollister@Sun.COM 			}
79310743SDavid.Hollister@Sun.COM 			header_printed = B_TRUE;
79410696SDavid.Hollister@Sun.COM 		}
79510743SDavid.Hollister@Sun.COM 
79610743SDavid.Hollister@Sun.COM 		display_one_work(wp, verbose, idx);
79710696SDavid.Hollister@Sun.COM 	}
79810696SDavid.Hollister@Sun.COM }
79910696SDavid.Hollister@Sun.COM 
80010696SDavid.Hollister@Sun.COM static void
80110743SDavid.Hollister@Sun.COM print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose)
80210696SDavid.Hollister@Sun.COM {
80310743SDavid.Hollister@Sun.COM 	int cdb_size, idx;
80410743SDavid.Hollister@Sun.COM 	struct scsi_pkt pkt;
80510743SDavid.Hollister@Sun.COM 	uchar_t cdb[256];
80610743SDavid.Hollister@Sun.COM 
80710696SDavid.Hollister@Sun.COM 	if (printhdr) {
80810743SDavid.Hollister@Sun.COM 		if (verbose) {
80910743SDavid.Hollister@Sun.COM 			mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
81010743SDavid.Hollister@Sun.COM 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
81110743SDavid.Hollister@Sun.COM 		} else {
81210743SDavid.Hollister@Sun.COM 			mdb_printf("%16s %16s %16s %8s %s\n", "Command",
81310743SDavid.Hollister@Sun.COM 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
81410743SDavid.Hollister@Sun.COM 		}
81510696SDavid.Hollister@Sun.COM 	}
81610743SDavid.Hollister@Sun.COM 
81710743SDavid.Hollister@Sun.COM 	mdb_printf("%16p %16p %16p %08x %08x ",
81810696SDavid.Hollister@Sun.COM 	    kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag);
81910743SDavid.Hollister@Sun.COM 
82010743SDavid.Hollister@Sun.COM 	/*
82110743SDavid.Hollister@Sun.COM 	 * If we're printing verbose, dump the CDB as well.
82210743SDavid.Hollister@Sun.COM 	 */
82310743SDavid.Hollister@Sun.COM 	if (verbose) {
82410743SDavid.Hollister@Sun.COM 		if (sp->cmd_pkt) {
82510743SDavid.Hollister@Sun.COM 			if (mdb_vread(&pkt, sizeof (struct scsi_pkt),
82610743SDavid.Hollister@Sun.COM 			    (uintptr_t)sp->cmd_pkt) !=
82710743SDavid.Hollister@Sun.COM 			    sizeof (struct scsi_pkt)) {
82810743SDavid.Hollister@Sun.COM 				mdb_warn("Unable to read SCSI pkt\n");
82910743SDavid.Hollister@Sun.COM 				return;
83010743SDavid.Hollister@Sun.COM 			}
83110743SDavid.Hollister@Sun.COM 			cdb_size = pkt.pkt_cdblen;
83210743SDavid.Hollister@Sun.COM 			if (mdb_vread(&cdb[0], cdb_size,
83310743SDavid.Hollister@Sun.COM 			    (uintptr_t)pkt.pkt_cdbp) != cdb_size) {
83410743SDavid.Hollister@Sun.COM 				mdb_warn("Unable to read CDB\n");
83510743SDavid.Hollister@Sun.COM 				return;
83610743SDavid.Hollister@Sun.COM 			}
83710743SDavid.Hollister@Sun.COM 
83810743SDavid.Hollister@Sun.COM 			for (idx = 0; idx < cdb_size; idx++) {
83910743SDavid.Hollister@Sun.COM 				mdb_printf("%02x ", cdb[idx]);
84010743SDavid.Hollister@Sun.COM 			}
84110743SDavid.Hollister@Sun.COM 		} else {
84210743SDavid.Hollister@Sun.COM 			mdb_printf("N/A");
84310743SDavid.Hollister@Sun.COM 		}
84410743SDavid.Hollister@Sun.COM 
84510743SDavid.Hollister@Sun.COM 		mdb_printf("\n");
84610743SDavid.Hollister@Sun.COM 	} else {
84710743SDavid.Hollister@Sun.COM 		mdb_printf("\n");
84810743SDavid.Hollister@Sun.COM 	}
84910696SDavid.Hollister@Sun.COM }
85010696SDavid.Hollister@Sun.COM 
85110696SDavid.Hollister@Sun.COM /*ARGSUSED1*/
85210696SDavid.Hollister@Sun.COM static void
85310696SDavid.Hollister@Sun.COM display_waitqs(struct pmcs_hw m, int verbose)
85410696SDavid.Hollister@Sun.COM {
85510696SDavid.Hollister@Sun.COM 	pmcs_cmd_t	*sp, s;
85610696SDavid.Hollister@Sun.COM 	pmcs_xscsi_t	xs;
85710696SDavid.Hollister@Sun.COM 	int		first, i;
85810696SDavid.Hollister@Sun.COM 	int		max_dev = m.max_dev;
85910696SDavid.Hollister@Sun.COM 
86010696SDavid.Hollister@Sun.COM 	sp = m.dq.stqh_first;
86110696SDavid.Hollister@Sun.COM 	first = 1;
86210696SDavid.Hollister@Sun.COM 	while (sp) {
86310696SDavid.Hollister@Sun.COM 		if (first) {
86410696SDavid.Hollister@Sun.COM 			mdb_printf("\nDead Command Queue:\n");
86510696SDavid.Hollister@Sun.COM 			mdb_printf("---------------------------\n");
86610696SDavid.Hollister@Sun.COM 		}
86710696SDavid.Hollister@Sun.COM 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
86810696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_cmd_t, sp);
86910696SDavid.Hollister@Sun.COM 			break;
87010696SDavid.Hollister@Sun.COM 		}
87110743SDavid.Hollister@Sun.COM 		print_spcmd(&s, sp, first, verbose);
87210696SDavid.Hollister@Sun.COM 		sp = s.cmd_next.stqe_next;
87310696SDavid.Hollister@Sun.COM 		first = 0;
87410696SDavid.Hollister@Sun.COM 	}
87510696SDavid.Hollister@Sun.COM 
87610696SDavid.Hollister@Sun.COM 	sp = m.cq.stqh_first;
87710696SDavid.Hollister@Sun.COM 	first = 1;
87810696SDavid.Hollister@Sun.COM 	while (sp) {
87910696SDavid.Hollister@Sun.COM 		if (first) {
88010696SDavid.Hollister@Sun.COM 			mdb_printf("\nCompletion Command Queue:\n");
88110696SDavid.Hollister@Sun.COM 			mdb_printf("---------------------------\n");
88210696SDavid.Hollister@Sun.COM 		}
88310696SDavid.Hollister@Sun.COM 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
88410696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_cmd_t, sp);
88510696SDavid.Hollister@Sun.COM 			break;
88610696SDavid.Hollister@Sun.COM 		}
88710743SDavid.Hollister@Sun.COM 		print_spcmd(&s, sp, first, verbose);
88810696SDavid.Hollister@Sun.COM 		sp = s.cmd_next.stqe_next;
88910696SDavid.Hollister@Sun.COM 		first = 0;
89010696SDavid.Hollister@Sun.COM 	}
89110696SDavid.Hollister@Sun.COM 
89210696SDavid.Hollister@Sun.COM 
89310696SDavid.Hollister@Sun.COM 	if (targets == NULL) {
89410696SDavid.Hollister@Sun.COM 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
89510696SDavid.Hollister@Sun.COM 	}
89610696SDavid.Hollister@Sun.COM 
89710696SDavid.Hollister@Sun.COM 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
89810696SDavid.Hollister@Sun.COM 		NOREAD(targets, m.targets);
89910696SDavid.Hollister@Sun.COM 		return;
90010696SDavid.Hollister@Sun.COM 	}
90110696SDavid.Hollister@Sun.COM 
90210696SDavid.Hollister@Sun.COM 	for (i = 0; i < max_dev; i++) {
90310696SDavid.Hollister@Sun.COM 		if (targets[i] == NULL) {
90410696SDavid.Hollister@Sun.COM 			continue;
90510696SDavid.Hollister@Sun.COM 		}
90610696SDavid.Hollister@Sun.COM 		if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) {
90710696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_xscsi_t, targets[i]);
90810696SDavid.Hollister@Sun.COM 			continue;
90910696SDavid.Hollister@Sun.COM 		}
91010696SDavid.Hollister@Sun.COM 		sp = xs.wq.stqh_first;
91110696SDavid.Hollister@Sun.COM 		first = 1;
91210696SDavid.Hollister@Sun.COM 		while (sp) {
91310696SDavid.Hollister@Sun.COM 			if (first) {
91410696SDavid.Hollister@Sun.COM 				mdb_printf("\nTarget %u Wait Queue:\n",
91510696SDavid.Hollister@Sun.COM 				    xs.target_num);
91610696SDavid.Hollister@Sun.COM 				mdb_printf("---------------------------\n");
91710696SDavid.Hollister@Sun.COM 			}
91810696SDavid.Hollister@Sun.COM 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
91910696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_cmd_t, sp);
92010696SDavid.Hollister@Sun.COM 				break;
92110696SDavid.Hollister@Sun.COM 			}
92210743SDavid.Hollister@Sun.COM 			print_spcmd(&s, sp, first, verbose);
92310696SDavid.Hollister@Sun.COM 			sp = s.cmd_next.stqe_next;
92410696SDavid.Hollister@Sun.COM 			first = 0;
92510696SDavid.Hollister@Sun.COM 		}
92610696SDavid.Hollister@Sun.COM 		sp = xs.aq.stqh_first;
92710696SDavid.Hollister@Sun.COM 		first = 1;
92810696SDavid.Hollister@Sun.COM 		while (sp) {
92910696SDavid.Hollister@Sun.COM 			if (first) {
93010696SDavid.Hollister@Sun.COM 				mdb_printf("\nTarget %u Active Queue:\n",
93110696SDavid.Hollister@Sun.COM 				    xs.target_num);
93210696SDavid.Hollister@Sun.COM 				mdb_printf("---------------------------\n");
93310696SDavid.Hollister@Sun.COM 			}
93410696SDavid.Hollister@Sun.COM 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
93510696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_cmd_t, sp);
93610696SDavid.Hollister@Sun.COM 				break;
93710696SDavid.Hollister@Sun.COM 			}
93810743SDavid.Hollister@Sun.COM 			print_spcmd(&s, sp, first, verbose);
93910696SDavid.Hollister@Sun.COM 			sp = s.cmd_next.stqe_next;
94010696SDavid.Hollister@Sun.COM 			first = 0;
94110696SDavid.Hollister@Sun.COM 		}
94210696SDavid.Hollister@Sun.COM 		sp = xs.sq.stqh_first;
94310696SDavid.Hollister@Sun.COM 		first = 1;
94410696SDavid.Hollister@Sun.COM 		while (sp) {
94510696SDavid.Hollister@Sun.COM 			if (first) {
94610696SDavid.Hollister@Sun.COM 				mdb_printf("\nTarget %u Special Queue:\n",
94710696SDavid.Hollister@Sun.COM 				    xs.target_num);
94810696SDavid.Hollister@Sun.COM 				mdb_printf("---------------------------\n");
94910696SDavid.Hollister@Sun.COM 			}
95010696SDavid.Hollister@Sun.COM 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
95110696SDavid.Hollister@Sun.COM 				NOREAD(pmcs_cmd_t, sp);
95210696SDavid.Hollister@Sun.COM 				break;
95310696SDavid.Hollister@Sun.COM 			}
95410743SDavid.Hollister@Sun.COM 			print_spcmd(&s, sp, first, verbose);
95510696SDavid.Hollister@Sun.COM 			sp = s.cmd_next.stqe_next;
95610696SDavid.Hollister@Sun.COM 			first = 0;
95710696SDavid.Hollister@Sun.COM 		}
95810696SDavid.Hollister@Sun.COM 	}
95910696SDavid.Hollister@Sun.COM }
96010696SDavid.Hollister@Sun.COM 
96110696SDavid.Hollister@Sun.COM static char *
96210696SDavid.Hollister@Sun.COM ibq_type(int qnum)
96310696SDavid.Hollister@Sun.COM {
96410696SDavid.Hollister@Sun.COM 	if (qnum < 0 || qnum >= PMCS_NIQ) {
96510696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
96610696SDavid.Hollister@Sun.COM 	}
96710696SDavid.Hollister@Sun.COM 
96810696SDavid.Hollister@Sun.COM 	if (qnum < PMCS_IQ_OTHER) {
96910696SDavid.Hollister@Sun.COM 		return ("I/O");
97010696SDavid.Hollister@Sun.COM 	}
97110696SDavid.Hollister@Sun.COM 
97210696SDavid.Hollister@Sun.COM 	return ("Other");
97310696SDavid.Hollister@Sun.COM }
97410696SDavid.Hollister@Sun.COM 
97510696SDavid.Hollister@Sun.COM static char *
97610696SDavid.Hollister@Sun.COM obq_type(int qnum)
97710696SDavid.Hollister@Sun.COM {
97810696SDavid.Hollister@Sun.COM 	switch (qnum) {
97910696SDavid.Hollister@Sun.COM 	case PMCS_OQ_IODONE:
98010696SDavid.Hollister@Sun.COM 		return ("I/O");
98110696SDavid.Hollister@Sun.COM 		break;
98210696SDavid.Hollister@Sun.COM 	case PMCS_OQ_GENERAL:
98310696SDavid.Hollister@Sun.COM 		return ("General");
98410696SDavid.Hollister@Sun.COM 		break;
98510696SDavid.Hollister@Sun.COM 	case PMCS_OQ_EVENTS:
98610696SDavid.Hollister@Sun.COM 		return ("Events");
98710696SDavid.Hollister@Sun.COM 		break;
98810696SDavid.Hollister@Sun.COM 	default:
98910696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
99010696SDavid.Hollister@Sun.COM 	}
99110696SDavid.Hollister@Sun.COM }
99210696SDavid.Hollister@Sun.COM 
99310696SDavid.Hollister@Sun.COM static char *
99410696SDavid.Hollister@Sun.COM iomb_cat(uint32_t cat)
99510696SDavid.Hollister@Sun.COM {
99610696SDavid.Hollister@Sun.COM 	switch (cat) {
99710696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_NET:
99810696SDavid.Hollister@Sun.COM 		return ("NET");
99910696SDavid.Hollister@Sun.COM 		break;
100010696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_FC:
100110696SDavid.Hollister@Sun.COM 		return ("FC");
100210696SDavid.Hollister@Sun.COM 		break;
100310696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_SAS:
100410696SDavid.Hollister@Sun.COM 		return ("SAS");
100510696SDavid.Hollister@Sun.COM 		break;
100610696SDavid.Hollister@Sun.COM 	case PMCS_IOMB_CAT_SCSI:
100710696SDavid.Hollister@Sun.COM 		return ("SCSI");
100810696SDavid.Hollister@Sun.COM 		break;
100910696SDavid.Hollister@Sun.COM 	default:
101010696SDavid.Hollister@Sun.COM 		return ("???");
101110696SDavid.Hollister@Sun.COM 	}
101210696SDavid.Hollister@Sun.COM }
101310696SDavid.Hollister@Sun.COM 
101410696SDavid.Hollister@Sun.COM static char *
101510696SDavid.Hollister@Sun.COM inbound_iomb_opcode(uint32_t opcode)
101610696SDavid.Hollister@Sun.COM {
101710696SDavid.Hollister@Sun.COM 	switch (opcode) {
101810696SDavid.Hollister@Sun.COM 	case PMCIN_ECHO:
101910696SDavid.Hollister@Sun.COM 		return ("ECHO");
102010696SDavid.Hollister@Sun.COM 		break;
102110696SDavid.Hollister@Sun.COM 	case PMCIN_GET_INFO:
102210696SDavid.Hollister@Sun.COM 		return ("GET_INFO");
102310696SDavid.Hollister@Sun.COM 		break;
102410696SDavid.Hollister@Sun.COM 	case PMCIN_GET_VPD:
102510696SDavid.Hollister@Sun.COM 		return ("GET_VPD");
102610696SDavid.Hollister@Sun.COM 		break;
102710696SDavid.Hollister@Sun.COM 	case PMCIN_PHY_START:
102810696SDavid.Hollister@Sun.COM 		return ("PHY_START");
102910696SDavid.Hollister@Sun.COM 		break;
103010696SDavid.Hollister@Sun.COM 	case PMCIN_PHY_STOP:
103110696SDavid.Hollister@Sun.COM 		return ("PHY_STOP");
103210696SDavid.Hollister@Sun.COM 		break;
103310696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_IO_START:
103410696SDavid.Hollister@Sun.COM 		return ("INI_IO_START");
103510696SDavid.Hollister@Sun.COM 		break;
103610696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_TM_START:
103710696SDavid.Hollister@Sun.COM 		return ("INI_TM_START");
103810696SDavid.Hollister@Sun.COM 		break;
103910696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_EXT_IO_START:
104010696SDavid.Hollister@Sun.COM 		return ("INI_EXT_IO_START");
104110696SDavid.Hollister@Sun.COM 		break;
104210696SDavid.Hollister@Sun.COM 	case PMCIN_DEVICE_HANDLE_ACCEPT:
104310696SDavid.Hollister@Sun.COM 		return ("DEVICE_HANDLE_ACCEPT");
104410696SDavid.Hollister@Sun.COM 		break;
104510696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_TGT_IO_START:
104610696SDavid.Hollister@Sun.COM 		return ("TGT_IO_START");
104710696SDavid.Hollister@Sun.COM 		break;
104810696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_TGT_RESPONSE_START:
104910696SDavid.Hollister@Sun.COM 		return ("TGT_RESPONSE_START");
105010696SDavid.Hollister@Sun.COM 		break;
105110696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_EDC_EXT_IO_START:
105210696SDavid.Hollister@Sun.COM 		return ("INI_EDC_EXT_IO_START");
105310696SDavid.Hollister@Sun.COM 		break;
105410696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_INI_EDC_EXT_IO_START1:
105510696SDavid.Hollister@Sun.COM 		return ("INI_EDC_EXT_IO_START1");
105610696SDavid.Hollister@Sun.COM 		break;
105710696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_TGT_EDC_IO_START:
105810696SDavid.Hollister@Sun.COM 		return ("TGT_EDC_IO_START");
105910696SDavid.Hollister@Sun.COM 		break;
106010696SDavid.Hollister@Sun.COM 	case PMCIN_SSP_ABORT:
106110696SDavid.Hollister@Sun.COM 		return ("SSP_ABORT");
106210696SDavid.Hollister@Sun.COM 		break;
106310696SDavid.Hollister@Sun.COM 	case PMCIN_DEREGISTER_DEVICE_HANDLE:
106410696SDavid.Hollister@Sun.COM 		return ("DEREGISTER_DEVICE_HANDLE");
106510696SDavid.Hollister@Sun.COM 		break;
106610696SDavid.Hollister@Sun.COM 	case PMCIN_GET_DEVICE_HANDLE:
106710696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_HANDLE");
106810696SDavid.Hollister@Sun.COM 		break;
106910696SDavid.Hollister@Sun.COM 	case PMCIN_SMP_REQUEST:
107010696SDavid.Hollister@Sun.COM 		return ("SMP_REQUEST");
107110696SDavid.Hollister@Sun.COM 		break;
107210696SDavid.Hollister@Sun.COM 	case PMCIN_SMP_RESPONSE:
107310696SDavid.Hollister@Sun.COM 		return ("SMP_RESPONSE");
107410696SDavid.Hollister@Sun.COM 		break;
107510696SDavid.Hollister@Sun.COM 	case PMCIN_SMP_ABORT:
107610696SDavid.Hollister@Sun.COM 		return ("SMP_ABORT");
107710696SDavid.Hollister@Sun.COM 		break;
107810696SDavid.Hollister@Sun.COM 	case PMCIN_ASSISTED_DISCOVERY:
107910696SDavid.Hollister@Sun.COM 		return ("ASSISTED_DISCOVERY");
108010696SDavid.Hollister@Sun.COM 		break;
108110696SDavid.Hollister@Sun.COM 	case PMCIN_REGISTER_DEVICE:
108210696SDavid.Hollister@Sun.COM 		return ("REGISTER_DEVICE");
108310696SDavid.Hollister@Sun.COM 		break;
108410696SDavid.Hollister@Sun.COM 	case PMCIN_SATA_HOST_IO_START:
108510696SDavid.Hollister@Sun.COM 		return ("SATA_HOST_IO_START");
108610696SDavid.Hollister@Sun.COM 		break;
108710696SDavid.Hollister@Sun.COM 	case PMCIN_SATA_ABORT:
108810696SDavid.Hollister@Sun.COM 		return ("SATA_ABORT");
108910696SDavid.Hollister@Sun.COM 		break;
109010696SDavid.Hollister@Sun.COM 	case PMCIN_LOCAL_PHY_CONTROL:
109110696SDavid.Hollister@Sun.COM 		return ("LOCAL_PHY_CONTROL");
109210696SDavid.Hollister@Sun.COM 		break;
109310696SDavid.Hollister@Sun.COM 	case PMCIN_GET_DEVICE_INFO:
109410696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_INFO");
109510696SDavid.Hollister@Sun.COM 		break;
109610696SDavid.Hollister@Sun.COM 	case PMCIN_TWI:
109710696SDavid.Hollister@Sun.COM 		return ("TWI");
109810696SDavid.Hollister@Sun.COM 		break;
109910696SDavid.Hollister@Sun.COM 	case PMCIN_FW_FLASH_UPDATE:
110010696SDavid.Hollister@Sun.COM 		return ("FW_FLASH_UPDATE");
110110696SDavid.Hollister@Sun.COM 		break;
110210696SDavid.Hollister@Sun.COM 	case PMCIN_SET_VPD:
110310696SDavid.Hollister@Sun.COM 		return ("SET_VPD");
110410696SDavid.Hollister@Sun.COM 		break;
110510696SDavid.Hollister@Sun.COM 	case PMCIN_GPIO:
110610696SDavid.Hollister@Sun.COM 		return ("GPIO");
110710696SDavid.Hollister@Sun.COM 		break;
110810696SDavid.Hollister@Sun.COM 	case PMCIN_SAS_DIAG_MODE_START_END:
110910696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_MODE_START_END");
111010696SDavid.Hollister@Sun.COM 		break;
111110696SDavid.Hollister@Sun.COM 	case PMCIN_SAS_DIAG_EXECUTE:
111210696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_EXECUTE");
111310696SDavid.Hollister@Sun.COM 		break;
111410696SDavid.Hollister@Sun.COM 	case PMCIN_SAW_HW_EVENT_ACK:
111510696SDavid.Hollister@Sun.COM 		return ("SAS_HW_EVENT_ACK");
111610696SDavid.Hollister@Sun.COM 		break;
111710696SDavid.Hollister@Sun.COM 	case PMCIN_GET_TIME_STAMP:
111810696SDavid.Hollister@Sun.COM 		return ("GET_TIME_STAMP");
111910696SDavid.Hollister@Sun.COM 		break;
112010696SDavid.Hollister@Sun.COM 	case PMCIN_PORT_CONTROL:
112110696SDavid.Hollister@Sun.COM 		return ("PORT_CONTROL");
112210696SDavid.Hollister@Sun.COM 		break;
112310696SDavid.Hollister@Sun.COM 	case PMCIN_GET_NVMD_DATA:
112410696SDavid.Hollister@Sun.COM 		return ("GET_NVMD_DATA");
112510696SDavid.Hollister@Sun.COM 		break;
112610696SDavid.Hollister@Sun.COM 	case PMCIN_SET_NVMD_DATA:
112710696SDavid.Hollister@Sun.COM 		return ("SET_NVMD_DATA");
112810696SDavid.Hollister@Sun.COM 		break;
112910696SDavid.Hollister@Sun.COM 	case PMCIN_SET_DEVICE_STATE:
113010696SDavid.Hollister@Sun.COM 		return ("SET_DEVICE_STATE");
113110696SDavid.Hollister@Sun.COM 		break;
113210696SDavid.Hollister@Sun.COM 	case PMCIN_GET_DEVICE_STATE:
113310696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_STATE");
113410696SDavid.Hollister@Sun.COM 		break;
113510696SDavid.Hollister@Sun.COM 	default:
113610696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
113710696SDavid.Hollister@Sun.COM 		break;
113810696SDavid.Hollister@Sun.COM 	}
113910696SDavid.Hollister@Sun.COM }
114010696SDavid.Hollister@Sun.COM 
114110696SDavid.Hollister@Sun.COM static char *
114210696SDavid.Hollister@Sun.COM outbound_iomb_opcode(uint32_t opcode)
114310696SDavid.Hollister@Sun.COM {
114410696SDavid.Hollister@Sun.COM 	switch (opcode) {
114510696SDavid.Hollister@Sun.COM 	case PMCOUT_ECHO:
114610696SDavid.Hollister@Sun.COM 		return ("ECHO");
114710696SDavid.Hollister@Sun.COM 		break;
114810696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_INFO:
114910696SDavid.Hollister@Sun.COM 		return ("GET_INFO");
115010696SDavid.Hollister@Sun.COM 		break;
115110696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_VPD:
115210696SDavid.Hollister@Sun.COM 		return ("GET_VPD");
115310696SDavid.Hollister@Sun.COM 		break;
115410696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_HW_EVENT:
115510696SDavid.Hollister@Sun.COM 		return ("SAS_HW_EVENT");
115610696SDavid.Hollister@Sun.COM 		break;
115710696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_COMPLETION:
115810696SDavid.Hollister@Sun.COM 		return ("SSP_COMPLETION");
115910696SDavid.Hollister@Sun.COM 		break;
116010696SDavid.Hollister@Sun.COM 	case PMCOUT_SMP_COMPLETION:
116110696SDavid.Hollister@Sun.COM 		return ("SMP_COMPLETION");
116210696SDavid.Hollister@Sun.COM 		break;
116310696SDavid.Hollister@Sun.COM 	case PMCOUT_LOCAL_PHY_CONTROL:
116410696SDavid.Hollister@Sun.COM 		return ("LOCAL_PHY_CONTROL");
116510696SDavid.Hollister@Sun.COM 		break;
116610696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT:
116710696SDavid.Hollister@Sun.COM 		return ("SAS_ASSISTED_DISCOVERY_SENT");
116810696SDavid.Hollister@Sun.COM 		break;
116910696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT:
117010696SDavid.Hollister@Sun.COM 		return ("SATA_ASSISTED_DISCOVERY_SENT");
117110696SDavid.Hollister@Sun.COM 		break;
117210696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_REGISTRATION:
117310696SDavid.Hollister@Sun.COM 		return ("DEVICE_REGISTRATION");
117410696SDavid.Hollister@Sun.COM 		break;
117510696SDavid.Hollister@Sun.COM 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
117610696SDavid.Hollister@Sun.COM 		return ("DEREGISTER_DEVICE_HANDLE");
117710696SDavid.Hollister@Sun.COM 		break;
117810696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_DEVICE_HANDLE:
117910696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_HANDLE");
118010696SDavid.Hollister@Sun.COM 		break;
118110696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_COMPLETION:
118210696SDavid.Hollister@Sun.COM 		return ("SATA_COMPLETION");
118310696SDavid.Hollister@Sun.COM 		break;
118410696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_EVENT:
118510696SDavid.Hollister@Sun.COM 		return ("SATA_EVENT");
118610696SDavid.Hollister@Sun.COM 		break;
118710696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_EVENT:
118810696SDavid.Hollister@Sun.COM 		return ("SSP_EVENT");
118910696SDavid.Hollister@Sun.COM 		break;
119010696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
119110696SDavid.Hollister@Sun.COM 		return ("DEVICE_HANDLE_ARRIVED");
119210696SDavid.Hollister@Sun.COM 		break;
119310696SDavid.Hollister@Sun.COM 	case PMCOUT_SMP_REQUEST_RECEIVED:
119410696SDavid.Hollister@Sun.COM 		return ("SMP_REQUEST_RECEIVED");
119510696SDavid.Hollister@Sun.COM 		break;
119610696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_REQUEST_RECEIVED:
119710696SDavid.Hollister@Sun.COM 		return ("SSP_REQUEST_RECEIVED");
119810696SDavid.Hollister@Sun.COM 		break;
119910696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_INFO:
120010696SDavid.Hollister@Sun.COM 		return ("DEVICE_INFO");
120110696SDavid.Hollister@Sun.COM 		break;
120210696SDavid.Hollister@Sun.COM 	case PMCOUT_FW_FLASH_UPDATE:
120310696SDavid.Hollister@Sun.COM 		return ("FW_FLASH_UPDATE");
120410696SDavid.Hollister@Sun.COM 		break;
120510696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_VPD:
120610696SDavid.Hollister@Sun.COM 		return ("SET_VPD");
120710696SDavid.Hollister@Sun.COM 		break;
120810696SDavid.Hollister@Sun.COM 	case PMCOUT_GPIO:
120910696SDavid.Hollister@Sun.COM 		return ("GPIO");
121010696SDavid.Hollister@Sun.COM 		break;
121110696SDavid.Hollister@Sun.COM 	case PMCOUT_GPIO_EVENT:
121210696SDavid.Hollister@Sun.COM 		return ("GPIO_EVENT");
121310696SDavid.Hollister@Sun.COM 		break;
121410696SDavid.Hollister@Sun.COM 	case PMCOUT_GENERAL_EVENT:
121510696SDavid.Hollister@Sun.COM 		return ("GENERAL_EVENT");
121610696SDavid.Hollister@Sun.COM 		break;
121710696SDavid.Hollister@Sun.COM 	case PMCOUT_TWI:
121810696SDavid.Hollister@Sun.COM 		return ("TWI");
121910696SDavid.Hollister@Sun.COM 		break;
122010696SDavid.Hollister@Sun.COM 	case PMCOUT_SSP_ABORT:
122110696SDavid.Hollister@Sun.COM 		return ("SSP_ABORT");
122210696SDavid.Hollister@Sun.COM 		break;
122310696SDavid.Hollister@Sun.COM 	case PMCOUT_SATA_ABORT:
122410696SDavid.Hollister@Sun.COM 		return ("SATA_ABORT");
122510696SDavid.Hollister@Sun.COM 		break;
122610696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_DIAG_MODE_START_END:
122710696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_MODE_START_END");
122810696SDavid.Hollister@Sun.COM 		break;
122910696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_DIAG_EXECUTE:
123010696SDavid.Hollister@Sun.COM 		return ("SAS_DIAG_EXECUTE");
123110696SDavid.Hollister@Sun.COM 		break;
123210696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_TIME_STAMP:
123310696SDavid.Hollister@Sun.COM 		return ("GET_TIME_STAMP");
123410696SDavid.Hollister@Sun.COM 		break;
123510696SDavid.Hollister@Sun.COM 	case PMCOUT_SAS_HW_EVENT_ACK_ACK:
123610696SDavid.Hollister@Sun.COM 		return ("SAS_HW_EVENT_ACK_ACK");
123710696SDavid.Hollister@Sun.COM 		break;
123810696SDavid.Hollister@Sun.COM 	case PMCOUT_PORT_CONTROL:
123910696SDavid.Hollister@Sun.COM 		return ("PORT_CONTROL");
124010696SDavid.Hollister@Sun.COM 		break;
124110696SDavid.Hollister@Sun.COM 	case PMCOUT_SKIP_ENTRIES:
124210696SDavid.Hollister@Sun.COM 		return ("SKIP_ENTRIES");
124310696SDavid.Hollister@Sun.COM 		break;
124410696SDavid.Hollister@Sun.COM 	case PMCOUT_SMP_ABORT:
124510696SDavid.Hollister@Sun.COM 		return ("SMP_ABORT");
124610696SDavid.Hollister@Sun.COM 		break;
124710696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_NVMD_DATA:
124810696SDavid.Hollister@Sun.COM 		return ("GET_NVMD_DATA");
124910696SDavid.Hollister@Sun.COM 		break;
125010696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_NVMD_DATA:
125110696SDavid.Hollister@Sun.COM 		return ("SET_NVMD_DATA");
125210696SDavid.Hollister@Sun.COM 		break;
125310696SDavid.Hollister@Sun.COM 	case PMCOUT_DEVICE_HANDLE_REMOVED:
125410696SDavid.Hollister@Sun.COM 		return ("DEVICE_HANDLE_REMOVED");
125510696SDavid.Hollister@Sun.COM 		break;
125610696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_DEVICE_STATE:
125710696SDavid.Hollister@Sun.COM 		return ("SET_DEVICE_STATE");
125810696SDavid.Hollister@Sun.COM 		break;
125910696SDavid.Hollister@Sun.COM 	case PMCOUT_GET_DEVICE_STATE:
126010696SDavid.Hollister@Sun.COM 		return ("GET_DEVICE_STATE");
126110696SDavid.Hollister@Sun.COM 		break;
126210696SDavid.Hollister@Sun.COM 	case PMCOUT_SET_DEVICE_INFO:
126310696SDavid.Hollister@Sun.COM 		return ("SET_DEVICE_INFO");
126410696SDavid.Hollister@Sun.COM 		break;
126510696SDavid.Hollister@Sun.COM 	default:
126610696SDavid.Hollister@Sun.COM 		return ("UNKNOWN");
126710696SDavid.Hollister@Sun.COM 		break;
126810696SDavid.Hollister@Sun.COM 	}
126910696SDavid.Hollister@Sun.COM }
127010696SDavid.Hollister@Sun.COM 
127110696SDavid.Hollister@Sun.COM static void
127210696SDavid.Hollister@Sun.COM dump_one_qentry_outbound(uint32_t *qentryp, int idx)
127310696SDavid.Hollister@Sun.COM {
127410696SDavid.Hollister@Sun.COM 	int qeidx;
127510696SDavid.Hollister@Sun.COM 	uint32_t word0 = LE_32(*qentryp);
127610696SDavid.Hollister@Sun.COM 
127710696SDavid.Hollister@Sun.COM 	mdb_printf("Entry #%02d\n", idx);
127810696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
127910696SDavid.Hollister@Sun.COM 
128010696SDavid.Hollister@Sun.COM 	mdb_printf("Header: 0x%08x (", word0);
128110696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_VALID) {
128210696SDavid.Hollister@Sun.COM 		mdb_printf("VALID, ");
128310696SDavid.Hollister@Sun.COM 	}
128410696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_HIPRI) {
128510696SDavid.Hollister@Sun.COM 		mdb_printf("HIPRI, ");
128610696SDavid.Hollister@Sun.COM 	}
128710696SDavid.Hollister@Sun.COM 	mdb_printf("OBID=%d, ",
128810696SDavid.Hollister@Sun.COM 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
128910696SDavid.Hollister@Sun.COM 	mdb_printf("CAT=%s, ",
129010696SDavid.Hollister@Sun.COM 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
129110696SDavid.Hollister@Sun.COM 	mdb_printf("OPCODE=%s",
129210696SDavid.Hollister@Sun.COM 	    outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
129310696SDavid.Hollister@Sun.COM 	mdb_printf(")\n");
129410696SDavid.Hollister@Sun.COM 
129510696SDavid.Hollister@Sun.COM 	mdb_printf("Remaining Payload:\n");
129610696SDavid.Hollister@Sun.COM 
129710696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
129810696SDavid.Hollister@Sun.COM 	for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
129910696SDavid.Hollister@Sun.COM 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
130010696SDavid.Hollister@Sun.COM 	}
130110696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
130210696SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
130310696SDavid.Hollister@Sun.COM }
130410696SDavid.Hollister@Sun.COM 
130510696SDavid.Hollister@Sun.COM static void
130610696SDavid.Hollister@Sun.COM display_outbound_queues(struct pmcs_hw ss, uint_t verbose)
130710696SDavid.Hollister@Sun.COM {
130810696SDavid.Hollister@Sun.COM 	int		idx, qidx;
130910696SDavid.Hollister@Sun.COM 	uintptr_t	obqp;
131010696SDavid.Hollister@Sun.COM 	uint32_t	*cip;
131110696SDavid.Hollister@Sun.COM 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
131210696SDavid.Hollister@Sun.COM 	uint32_t	last_consumed, oqpi;
131310696SDavid.Hollister@Sun.COM 
131410696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
131510696SDavid.Hollister@Sun.COM 	mdb_printf("Outbound Queues\n");
131610696SDavid.Hollister@Sun.COM 	mdb_printf("---------------\n");
131710696SDavid.Hollister@Sun.COM 
131810696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
131910696SDavid.Hollister@Sun.COM 
132010696SDavid.Hollister@Sun.COM 	for (qidx = 0; qidx < PMCS_NOQ; qidx++) {
132110696SDavid.Hollister@Sun.COM 		obqp = (uintptr_t)ss.oqp[qidx];
132210696SDavid.Hollister@Sun.COM 
132310696SDavid.Hollister@Sun.COM 		if (obqp == NULL) {
132410696SDavid.Hollister@Sun.COM 			mdb_printf("No outbound queue ptr for queue #%d\n",
132510696SDavid.Hollister@Sun.COM 			    qidx);
132610696SDavid.Hollister@Sun.COM 			continue;
132710696SDavid.Hollister@Sun.COM 		}
132810696SDavid.Hollister@Sun.COM 
132910696SDavid.Hollister@Sun.COM 		mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx,
133010696SDavid.Hollister@Sun.COM 		    obq_type(qidx));
133110696SDavid.Hollister@Sun.COM 		/*
133210696SDavid.Hollister@Sun.COM 		 * Chip is the producer, so read the actual producer index
133310696SDavid.Hollister@Sun.COM 		 * and not the driver's version
133410696SDavid.Hollister@Sun.COM 		 */
133510696SDavid.Hollister@Sun.COM 		cip = (uint32_t *)((void *)ss.cip);
133610696SDavid.Hollister@Sun.COM 		if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET +
133710696SDavid.Hollister@Sun.COM 		    (qidx * 4)) == -1) {
133810696SDavid.Hollister@Sun.COM 			mdb_warn("Couldn't read oqpi\n");
133910696SDavid.Hollister@Sun.COM 			break;
134010696SDavid.Hollister@Sun.COM 		}
134110696SDavid.Hollister@Sun.COM 
134210696SDavid.Hollister@Sun.COM 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
134310696SDavid.Hollister@Sun.COM 		    LE_32(oqpi), ss.oqci[qidx]);
134410696SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
134510696SDavid.Hollister@Sun.COM 
134610696SDavid.Hollister@Sun.COM 		if (ss.oqci[qidx] == 0) {
134710696SDavid.Hollister@Sun.COM 			last_consumed = ss.ioq_depth - 1;
134810696SDavid.Hollister@Sun.COM 		} else {
134910696SDavid.Hollister@Sun.COM 			last_consumed = ss.oqci[qidx] - 1;
135010696SDavid.Hollister@Sun.COM 		}
135110696SDavid.Hollister@Sun.COM 
135210696SDavid.Hollister@Sun.COM 
135310696SDavid.Hollister@Sun.COM 		if (!verbose) {
135410696SDavid.Hollister@Sun.COM 			mdb_printf("Last processed entry:\n");
135510696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
135610696SDavid.Hollister@Sun.COM 			    (obqp + (PMCS_QENTRY_SIZE * last_consumed)))
135710696SDavid.Hollister@Sun.COM 			    == -1) {
135810696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
135910696SDavid.Hollister@Sun.COM 				    (obqp + (PMCS_QENTRY_SIZE *
136010696SDavid.Hollister@Sun.COM 				    last_consumed)));
136110696SDavid.Hollister@Sun.COM 				break;
136210696SDavid.Hollister@Sun.COM 			}
136310696SDavid.Hollister@Sun.COM 			dump_one_qentry_outbound(qentryp, last_consumed);
136410696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
136510696SDavid.Hollister@Sun.COM 			mdb_dec_indent(2);
136610696SDavid.Hollister@Sun.COM 			continue;
136710696SDavid.Hollister@Sun.COM 		}
136810696SDavid.Hollister@Sun.COM 
136910696SDavid.Hollister@Sun.COM 		for (idx = 0; idx < ss.ioq_depth; idx++) {
137010696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
137110696SDavid.Hollister@Sun.COM 			    (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
137210696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
137310696SDavid.Hollister@Sun.COM 				    (obqp + (PMCS_QENTRY_SIZE * idx)));
137410696SDavid.Hollister@Sun.COM 				break;
137510696SDavid.Hollister@Sun.COM 			}
137610696SDavid.Hollister@Sun.COM 			dump_one_qentry_outbound(qentryp, idx);
137710696SDavid.Hollister@Sun.COM 		}
137810696SDavid.Hollister@Sun.COM 
137910696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
138010696SDavid.Hollister@Sun.COM 		mdb_dec_indent(2);
138110696SDavid.Hollister@Sun.COM 	}
138210696SDavid.Hollister@Sun.COM 
138310696SDavid.Hollister@Sun.COM 	mdb_dec_indent(2);
138410696SDavid.Hollister@Sun.COM 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
138510696SDavid.Hollister@Sun.COM }
138610696SDavid.Hollister@Sun.COM 
138710696SDavid.Hollister@Sun.COM static void
138810696SDavid.Hollister@Sun.COM dump_one_qentry_inbound(uint32_t *qentryp, int idx)
138910696SDavid.Hollister@Sun.COM {
139010696SDavid.Hollister@Sun.COM 	int qeidx;
139110696SDavid.Hollister@Sun.COM 	uint32_t word0 = LE_32(*qentryp);
139210696SDavid.Hollister@Sun.COM 
139310696SDavid.Hollister@Sun.COM 	mdb_printf("Entry #%02d\n", idx);
139410696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
139510696SDavid.Hollister@Sun.COM 
139610696SDavid.Hollister@Sun.COM 	mdb_printf("Header: 0x%08x (", word0);
139710696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_VALID) {
139810696SDavid.Hollister@Sun.COM 		mdb_printf("VALID, ");
139910696SDavid.Hollister@Sun.COM 	}
140010696SDavid.Hollister@Sun.COM 	if (word0 & PMCS_IOMB_HIPRI) {
140110696SDavid.Hollister@Sun.COM 		mdb_printf("HIPRI, ");
140210696SDavid.Hollister@Sun.COM 	}
140310696SDavid.Hollister@Sun.COM 	mdb_printf("OBID=%d, ",
140410696SDavid.Hollister@Sun.COM 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
140510696SDavid.Hollister@Sun.COM 	mdb_printf("CAT=%s, ",
140610696SDavid.Hollister@Sun.COM 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
140710696SDavid.Hollister@Sun.COM 	mdb_printf("OPCODE=%s",
140810696SDavid.Hollister@Sun.COM 	    inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
140910696SDavid.Hollister@Sun.COM 	mdb_printf(")\n");
141010696SDavid.Hollister@Sun.COM 
141110696SDavid.Hollister@Sun.COM 	mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1)));
141210696SDavid.Hollister@Sun.COM 	mdb_printf("Remaining Payload:\n");
141310696SDavid.Hollister@Sun.COM 
141410696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
141510696SDavid.Hollister@Sun.COM 	for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
141610696SDavid.Hollister@Sun.COM 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
141710696SDavid.Hollister@Sun.COM 	}
141810696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
141910696SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
142010696SDavid.Hollister@Sun.COM }
142110696SDavid.Hollister@Sun.COM 
142210696SDavid.Hollister@Sun.COM static void
142310696SDavid.Hollister@Sun.COM display_inbound_queues(struct pmcs_hw ss, uint_t verbose)
142410696SDavid.Hollister@Sun.COM {
142510696SDavid.Hollister@Sun.COM 	int		idx, qidx, iqci, last_consumed;
142610696SDavid.Hollister@Sun.COM 	uintptr_t	ibqp;
142710696SDavid.Hollister@Sun.COM 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
142810696SDavid.Hollister@Sun.COM 	uint32_t	*cip;
142910696SDavid.Hollister@Sun.COM 
143010696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
143110696SDavid.Hollister@Sun.COM 	mdb_printf("Inbound Queues\n");
143210696SDavid.Hollister@Sun.COM 	mdb_printf("--------------\n");
143310696SDavid.Hollister@Sun.COM 
143410696SDavid.Hollister@Sun.COM 	mdb_inc_indent(2);
143510696SDavid.Hollister@Sun.COM 
143610696SDavid.Hollister@Sun.COM 	for (qidx = 0; qidx < PMCS_NIQ; qidx++) {
143710696SDavid.Hollister@Sun.COM 		ibqp = (uintptr_t)ss.iqp[qidx];
143810696SDavid.Hollister@Sun.COM 
143910696SDavid.Hollister@Sun.COM 		if (ibqp == NULL) {
144010696SDavid.Hollister@Sun.COM 			mdb_printf("No inbound queue ptr for queue #%d\n",
144110696SDavid.Hollister@Sun.COM 			    qidx);
144210696SDavid.Hollister@Sun.COM 			continue;
144310696SDavid.Hollister@Sun.COM 		}
144410696SDavid.Hollister@Sun.COM 
144510696SDavid.Hollister@Sun.COM 		mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx,
144610696SDavid.Hollister@Sun.COM 		    ibq_type(qidx));
144710696SDavid.Hollister@Sun.COM 
144810696SDavid.Hollister@Sun.COM 		cip = (uint32_t *)((void *)ss.cip);
144910696SDavid.Hollister@Sun.COM 		if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) {
145010696SDavid.Hollister@Sun.COM 			mdb_warn("Couldn't read iqci\n");
145110696SDavid.Hollister@Sun.COM 			break;
145210696SDavid.Hollister@Sun.COM 		}
145310696SDavid.Hollister@Sun.COM 		iqci = LE_32(iqci);
145410696SDavid.Hollister@Sun.COM 
145510696SDavid.Hollister@Sun.COM 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
145610696SDavid.Hollister@Sun.COM 		    ss.shadow_iqpi[qidx], iqci);
145710696SDavid.Hollister@Sun.COM 		mdb_inc_indent(2);
145810696SDavid.Hollister@Sun.COM 
145910696SDavid.Hollister@Sun.COM 		if (iqci == 0) {
146010696SDavid.Hollister@Sun.COM 			last_consumed = ss.ioq_depth - 1;
146110696SDavid.Hollister@Sun.COM 		} else {
146210696SDavid.Hollister@Sun.COM 			last_consumed = iqci - 1;
146310696SDavid.Hollister@Sun.COM 		}
146410696SDavid.Hollister@Sun.COM 
146510696SDavid.Hollister@Sun.COM 		if (!verbose) {
146610696SDavid.Hollister@Sun.COM 			mdb_printf("Last processed entry:\n");
146710696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
146810696SDavid.Hollister@Sun.COM 			    (ibqp + (PMCS_QENTRY_SIZE * last_consumed)))
146910696SDavid.Hollister@Sun.COM 			    == -1) {
147010696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
147110696SDavid.Hollister@Sun.COM 				    (ibqp + (PMCS_QENTRY_SIZE *
147210696SDavid.Hollister@Sun.COM 				    last_consumed)));
147310696SDavid.Hollister@Sun.COM 				break;
147410696SDavid.Hollister@Sun.COM 			}
147510696SDavid.Hollister@Sun.COM 			dump_one_qentry_inbound(qentryp, last_consumed);
147610696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
147710696SDavid.Hollister@Sun.COM 			mdb_dec_indent(2);
147810696SDavid.Hollister@Sun.COM 			continue;
147910696SDavid.Hollister@Sun.COM 		}
148010696SDavid.Hollister@Sun.COM 
148110696SDavid.Hollister@Sun.COM 		for (idx = 0; idx < ss.ioq_depth; idx++) {
148210696SDavid.Hollister@Sun.COM 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
148310696SDavid.Hollister@Sun.COM 			    (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
148410696SDavid.Hollister@Sun.COM 				mdb_warn("Couldn't read queue entry at 0x%p\n",
148510696SDavid.Hollister@Sun.COM 				    (ibqp + (PMCS_QENTRY_SIZE * idx)));
148610696SDavid.Hollister@Sun.COM 				break;
148710696SDavid.Hollister@Sun.COM 			}
148810696SDavid.Hollister@Sun.COM 			dump_one_qentry_inbound(qentryp, idx);
148910696SDavid.Hollister@Sun.COM 		}
149010696SDavid.Hollister@Sun.COM 
149110696SDavid.Hollister@Sun.COM 		mdb_printf("\n");
149210696SDavid.Hollister@Sun.COM 		mdb_dec_indent(2);
149310696SDavid.Hollister@Sun.COM 	}
149410696SDavid.Hollister@Sun.COM 
149510696SDavid.Hollister@Sun.COM 	mdb_dec_indent(2);
149610696SDavid.Hollister@Sun.COM 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
149710696SDavid.Hollister@Sun.COM }
149810696SDavid.Hollister@Sun.COM 
149910696SDavid.Hollister@Sun.COM static void
150010696SDavid.Hollister@Sun.COM display_phy(struct pmcs_phy phy, int verbose, int totals_only)
150110696SDavid.Hollister@Sun.COM {
150210696SDavid.Hollister@Sun.COM 	char		*dtype, *speed;
150310696SDavid.Hollister@Sun.COM 	char		*yes = "Yes";
150410696SDavid.Hollister@Sun.COM 	char		*no = "No";
150510696SDavid.Hollister@Sun.COM 	char		*cfgd = no;
150610696SDavid.Hollister@Sun.COM 	char		*apend = no;
150710696SDavid.Hollister@Sun.COM 	char		*asent = no;
150810696SDavid.Hollister@Sun.COM 	char		*dead = no;
150910696SDavid.Hollister@Sun.COM 	char		*changed = no;
151010696SDavid.Hollister@Sun.COM 
151110696SDavid.Hollister@Sun.COM 	switch (phy.dtype) {
151210696SDavid.Hollister@Sun.COM 	case NOTHING:
151310696SDavid.Hollister@Sun.COM 		dtype = "None";
151410696SDavid.Hollister@Sun.COM 		break;
151510696SDavid.Hollister@Sun.COM 	case SATA:
151610696SDavid.Hollister@Sun.COM 		dtype = "SATA";
151710696SDavid.Hollister@Sun.COM 		if (phy.configured) {
151810696SDavid.Hollister@Sun.COM 			++sata_phys;
151910696SDavid.Hollister@Sun.COM 		}
152010696SDavid.Hollister@Sun.COM 		break;
152110696SDavid.Hollister@Sun.COM 	case SAS:
152210696SDavid.Hollister@Sun.COM 		dtype = "SAS";
152310696SDavid.Hollister@Sun.COM 		if (phy.configured) {
152410696SDavid.Hollister@Sun.COM 			++sas_phys;
152510696SDavid.Hollister@Sun.COM 		}
152610696SDavid.Hollister@Sun.COM 		break;
152710696SDavid.Hollister@Sun.COM 	case EXPANDER:
152810696SDavid.Hollister@Sun.COM 		dtype = "EXP";
152910696SDavid.Hollister@Sun.COM 		if (phy.configured) {
153010696SDavid.Hollister@Sun.COM 			++exp_phys;
153110696SDavid.Hollister@Sun.COM 		}
153210696SDavid.Hollister@Sun.COM 		break;
153310696SDavid.Hollister@Sun.COM 	}
153410696SDavid.Hollister@Sun.COM 
153510696SDavid.Hollister@Sun.COM 	if (phy.dtype == NOTHING) {
153610696SDavid.Hollister@Sun.COM 		empty_phys++;
153710696SDavid.Hollister@Sun.COM 	} else if ((phy.dtype == EXPANDER) && phy.configured) {
153810696SDavid.Hollister@Sun.COM 		num_expanders++;
153910696SDavid.Hollister@Sun.COM 	}
154010696SDavid.Hollister@Sun.COM 
154110696SDavid.Hollister@Sun.COM 	if (totals_only) {
154210696SDavid.Hollister@Sun.COM 		return;
154310696SDavid.Hollister@Sun.COM 	}
154410696SDavid.Hollister@Sun.COM 
154510696SDavid.Hollister@Sun.COM 	switch (phy.link_rate) {
154610696SDavid.Hollister@Sun.COM 	case SAS_LINK_RATE_1_5GBIT:
154710696SDavid.Hollister@Sun.COM 		speed = "1.5Gb/s";
154810696SDavid.Hollister@Sun.COM 		break;
154910696SDavid.Hollister@Sun.COM 	case SAS_LINK_RATE_3GBIT:
155010696SDavid.Hollister@Sun.COM 		speed = "3 Gb/s";
155110696SDavid.Hollister@Sun.COM 		break;
155210696SDavid.Hollister@Sun.COM 	case SAS_LINK_RATE_6GBIT:
155310696SDavid.Hollister@Sun.COM 		speed = "6 Gb/s";
155410696SDavid.Hollister@Sun.COM 		break;
155510696SDavid.Hollister@Sun.COM 	default:
155610696SDavid.Hollister@Sun.COM 		speed = "N/A";
155710696SDavid.Hollister@Sun.COM 		break;
155810696SDavid.Hollister@Sun.COM 	}
155910696SDavid.Hollister@Sun.COM 
156010696SDavid.Hollister@Sun.COM 	if ((phy.dtype != NOTHING) || verbose) {
156110696SDavid.Hollister@Sun.COM 		print_sas_address(&phy);
156210696SDavid.Hollister@Sun.COM 
156310696SDavid.Hollister@Sun.COM 		if (phy.device_id != PMCS_INVALID_DEVICE_ID) {
156410696SDavid.Hollister@Sun.COM 			mdb_printf(" %3d %4d %6s %4s ",
156510696SDavid.Hollister@Sun.COM 			    phy.device_id, phy.phynum, speed, dtype);
156610696SDavid.Hollister@Sun.COM 		} else {
156710696SDavid.Hollister@Sun.COM 			mdb_printf(" N/A %4d %6s %4s ",
156810696SDavid.Hollister@Sun.COM 			    phy.phynum, speed, dtype);
156910696SDavid.Hollister@Sun.COM 		}
157010696SDavid.Hollister@Sun.COM 
157110696SDavid.Hollister@Sun.COM 		if (verbose) {
157210696SDavid.Hollister@Sun.COM 			if (phy.abort_sent) {
157310696SDavid.Hollister@Sun.COM 				asent = yes;
157410696SDavid.Hollister@Sun.COM 			}
157510696SDavid.Hollister@Sun.COM 			if (phy.abort_pending) {
157610696SDavid.Hollister@Sun.COM 				apend = yes;
157710696SDavid.Hollister@Sun.COM 			}
157810696SDavid.Hollister@Sun.COM 			if (phy.configured) {
157910696SDavid.Hollister@Sun.COM 				cfgd = yes;
158010696SDavid.Hollister@Sun.COM 			}
158110696SDavid.Hollister@Sun.COM 			if (phy.dead) {
158210696SDavid.Hollister@Sun.COM 				dead = yes;
158310696SDavid.Hollister@Sun.COM 			}
158410696SDavid.Hollister@Sun.COM 			if (phy.changed) {
158510696SDavid.Hollister@Sun.COM 				changed = yes;
158610696SDavid.Hollister@Sun.COM 			}
158710696SDavid.Hollister@Sun.COM 
158810696SDavid.Hollister@Sun.COM 			mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d "
158910696SDavid.Hollister@Sun.COM 			    "0x%p ", cfgd, apend, asent,
159010696SDavid.Hollister@Sun.COM 			    changed, dead, phy.ref_count, phy.phy_lock);
159110696SDavid.Hollister@Sun.COM 		}
159210696SDavid.Hollister@Sun.COM 
159310696SDavid.Hollister@Sun.COM 		mdb_printf("Path: %s\n", phy.path);
159410696SDavid.Hollister@Sun.COM 	}
159510696SDavid.Hollister@Sun.COM }
159610696SDavid.Hollister@Sun.COM 
159710696SDavid.Hollister@Sun.COM static void
159810696SDavid.Hollister@Sun.COM display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level,
159910696SDavid.Hollister@Sun.COM     int totals_only)
160010696SDavid.Hollister@Sun.COM {
160110696SDavid.Hollister@Sun.COM 	pmcs_phy_t	phy;
160210696SDavid.Hollister@Sun.COM 	pmcs_phy_t	*pphy = parent;
160310696SDavid.Hollister@Sun.COM 
160410696SDavid.Hollister@Sun.COM 	mdb_inc_indent(3);
160510696SDavid.Hollister@Sun.COM 
160610696SDavid.Hollister@Sun.COM 	if (parent == NULL) {
160710696SDavid.Hollister@Sun.COM 		pphy = (pmcs_phy_t *)ss.root_phys;
160810696SDavid.Hollister@Sun.COM 	} else {
160910696SDavid.Hollister@Sun.COM 		pphy = (pmcs_phy_t *)parent;
161010696SDavid.Hollister@Sun.COM 	}
161110696SDavid.Hollister@Sun.COM 
161210696SDavid.Hollister@Sun.COM 	if (level == 0) {
161310696SDavid.Hollister@Sun.COM 		sas_phys = 0;
161410696SDavid.Hollister@Sun.COM 		sata_phys = 0;
161510696SDavid.Hollister@Sun.COM 		exp_phys = 0;
161610696SDavid.Hollister@Sun.COM 		num_expanders = 0;
161710696SDavid.Hollister@Sun.COM 		empty_phys = 0;
161810696SDavid.Hollister@Sun.COM 	}
161910696SDavid.Hollister@Sun.COM 
162010696SDavid.Hollister@Sun.COM 	if (!totals_only) {
162110696SDavid.Hollister@Sun.COM 		if (level == 0) {
162210696SDavid.Hollister@Sun.COM 			mdb_printf("PHY information\n");
162310696SDavid.Hollister@Sun.COM 		}
162410696SDavid.Hollister@Sun.COM 		mdb_printf("--------\n");
162510696SDavid.Hollister@Sun.COM 		mdb_printf("Level %2d\n", level);
162610696SDavid.Hollister@Sun.COM 		mdb_printf("--------\n");
162710696SDavid.Hollister@Sun.COM 		mdb_printf("SAS Address      Hdl Phy#  Speed Type ");
162810696SDavid.Hollister@Sun.COM 
162910696SDavid.Hollister@Sun.COM 		if (verbose) {
163010696SDavid.Hollister@Sun.COM 			mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref Lock\n");
163110696SDavid.Hollister@Sun.COM 		} else {
163210696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
163310696SDavid.Hollister@Sun.COM 		}
163410696SDavid.Hollister@Sun.COM 	}
163510696SDavid.Hollister@Sun.COM 
163610696SDavid.Hollister@Sun.COM 	while (pphy) {
163710696SDavid.Hollister@Sun.COM 		if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) {
163810696SDavid.Hollister@Sun.COM 			NOREAD(pmcs_phy_t, phy);
163910696SDavid.Hollister@Sun.COM 			break;
164010696SDavid.Hollister@Sun.COM 		}
164110696SDavid.Hollister@Sun.COM 
164210696SDavid.Hollister@Sun.COM 		display_phy(phy, verbose, totals_only);
164310696SDavid.Hollister@Sun.COM 
164410696SDavid.Hollister@Sun.COM 		if (phy.children) {
164510696SDavid.Hollister@Sun.COM 			display_phys(ss, verbose, phy.children, level + 1,
164610696SDavid.Hollister@Sun.COM 			    totals_only);
164710696SDavid.Hollister@Sun.COM 			if (!totals_only) {
164810696SDavid.Hollister@Sun.COM 				mdb_printf("\n");
164910696SDavid.Hollister@Sun.COM 			}
165010696SDavid.Hollister@Sun.COM 		}
165110696SDavid.Hollister@Sun.COM 
165210696SDavid.Hollister@Sun.COM 		pphy = phy.sibling;
165310696SDavid.Hollister@Sun.COM 	}
165410696SDavid.Hollister@Sun.COM 
165510696SDavid.Hollister@Sun.COM 	mdb_dec_indent(3);
165610696SDavid.Hollister@Sun.COM 
165710696SDavid.Hollister@Sun.COM 	if (level == 0) {
165810696SDavid.Hollister@Sun.COM 		if (verbose) {
165910696SDavid.Hollister@Sun.COM 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
166010696SDavid.Hollister@Sun.COM 			    "(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
166110696SDavid.Hollister@Sun.COM 			    (sas_phys + sata_phys + num_expanders),
166210696SDavid.Hollister@Sun.COM 			    sas_phys, sata_phys, num_expanders,
166310696SDavid.Hollister@Sun.COM 			    (exp_phys - num_expanders), empty_phys);
166410696SDavid.Hollister@Sun.COM 		} else {
166510696SDavid.Hollister@Sun.COM 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
166610696SDavid.Hollister@Sun.COM 			    "Occupied PHYs:",
166710696SDavid.Hollister@Sun.COM 			    (sas_phys + sata_phys + num_expanders),
166810696SDavid.Hollister@Sun.COM 			    sas_phys, sata_phys, num_expanders);
166910696SDavid.Hollister@Sun.COM 		}
167010696SDavid.Hollister@Sun.COM 	}
167110696SDavid.Hollister@Sun.COM }
167210696SDavid.Hollister@Sun.COM 
167310696SDavid.Hollister@Sun.COM /*
167411048SDavid.Hollister@Sun.COM  * filter is used to indicate whether we are filtering log messages based
167511048SDavid.Hollister@Sun.COM  * on "instance".  The other filtering (based on options) depends on the
167611048SDavid.Hollister@Sun.COM  * values that are passed in for "sas_addr" and "phy_path".
167711048SDavid.Hollister@Sun.COM  *
167810696SDavid.Hollister@Sun.COM  * MAX_INST_STRLEN is the largest string size from which we will attempt
167910696SDavid.Hollister@Sun.COM  * to convert to an instance number.  The string will be formed up as
168010696SDavid.Hollister@Sun.COM  * "0t<inst>\0" so that mdb_strtoull can parse it properly.
168110696SDavid.Hollister@Sun.COM  */
168210696SDavid.Hollister@Sun.COM #define	MAX_INST_STRLEN	8
168310696SDavid.Hollister@Sun.COM 
168410696SDavid.Hollister@Sun.COM static int
168511048SDavid.Hollister@Sun.COM pmcs_dump_tracelog(boolean_t filter, int instance, const char *phy_path,
168611048SDavid.Hollister@Sun.COM     uint64_t sas_address)
168710696SDavid.Hollister@Sun.COM {
168810696SDavid.Hollister@Sun.COM 	pmcs_tbuf_t *tbuf_addr;
168910696SDavid.Hollister@Sun.COM 	uint_t tbuf_idx;
169010696SDavid.Hollister@Sun.COM 	pmcs_tbuf_t tbuf;
169110696SDavid.Hollister@Sun.COM 	boolean_t wrap, elem_filtered;
169210696SDavid.Hollister@Sun.COM 	uint_t start_idx, elems_to_print, idx, tbuf_num_elems;
169310696SDavid.Hollister@Sun.COM 	char *bufp;
169410696SDavid.Hollister@Sun.COM 	char elem_inst[MAX_INST_STRLEN], ei_idx;
169511048SDavid.Hollister@Sun.COM 	uint64_t sas_addr;
169611048SDavid.Hollister@Sun.COM 	uint8_t *sas_addressp;
169710696SDavid.Hollister@Sun.COM 
169810696SDavid.Hollister@Sun.COM 	/* Get the address of the first element */
169910696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) {
170010696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf");
170110696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
170210696SDavid.Hollister@Sun.COM 	}
170310696SDavid.Hollister@Sun.COM 
170410696SDavid.Hollister@Sun.COM 	/* Get the total number */
170510696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) {
170610696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf_num_elems");
170710696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
170810696SDavid.Hollister@Sun.COM 	}
170910696SDavid.Hollister@Sun.COM 
171010696SDavid.Hollister@Sun.COM 	/* Get the current index */
171110696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) {
171210696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf_idx");
171310696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
171410696SDavid.Hollister@Sun.COM 	}
171510696SDavid.Hollister@Sun.COM 
171610696SDavid.Hollister@Sun.COM 	/* Indicator as to whether the buffer has wrapped */
171710696SDavid.Hollister@Sun.COM 	if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) {
171810696SDavid.Hollister@Sun.COM 		mdb_warn("can't read pmcs_tbuf_wrap");
171910696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
172010696SDavid.Hollister@Sun.COM 	}
172110696SDavid.Hollister@Sun.COM 
172211048SDavid.Hollister@Sun.COM 	/*
172311048SDavid.Hollister@Sun.COM 	 * On little-endian systems, the SAS address passed in will be
172411048SDavid.Hollister@Sun.COM 	 * byte swapped.  Take care of that here.
172511048SDavid.Hollister@Sun.COM 	 */
172611048SDavid.Hollister@Sun.COM #if defined(_LITTLE_ENDIAN)
172711048SDavid.Hollister@Sun.COM 	sas_addr = ((sas_address << 56) |
172811048SDavid.Hollister@Sun.COM 	    ((sas_address << 40) & 0xff000000000000ULL) |
172911048SDavid.Hollister@Sun.COM 	    ((sas_address << 24) & 0xff0000000000ULL) |
173011048SDavid.Hollister@Sun.COM 	    ((sas_address << 8)  & 0xff00000000ULL) |
173111048SDavid.Hollister@Sun.COM 	    ((sas_address >> 8)  & 0xff000000ULL) |
173211048SDavid.Hollister@Sun.COM 	    ((sas_address >> 24) & 0xff0000ULL) |
173311048SDavid.Hollister@Sun.COM 	    ((sas_address >> 40) & 0xff00ULL) |
173411048SDavid.Hollister@Sun.COM 	    (sas_address  >> 56));
173511048SDavid.Hollister@Sun.COM #else
173611048SDavid.Hollister@Sun.COM 	sas_addr = sas_address;
173711048SDavid.Hollister@Sun.COM #endif
173811048SDavid.Hollister@Sun.COM 	sas_addressp = (uint8_t *)&sas_addr;
173911048SDavid.Hollister@Sun.COM 
174010696SDavid.Hollister@Sun.COM 	/* Figure out where we start and stop */
174110696SDavid.Hollister@Sun.COM 	if (wrap) {
174210696SDavid.Hollister@Sun.COM 		start_idx = tbuf_idx;
174310696SDavid.Hollister@Sun.COM 		elems_to_print = tbuf_num_elems;
174410696SDavid.Hollister@Sun.COM 	} else {
174510696SDavid.Hollister@Sun.COM 		start_idx = 0;
174610696SDavid.Hollister@Sun.COM 		elems_to_print = tbuf_idx;
174710696SDavid.Hollister@Sun.COM 	}
174810696SDavid.Hollister@Sun.COM 
174910696SDavid.Hollister@Sun.COM 	idx = start_idx;
175010696SDavid.Hollister@Sun.COM 
175110696SDavid.Hollister@Sun.COM 	/* Dump the buffer contents */
175210696SDavid.Hollister@Sun.COM 	while (elems_to_print != 0) {
175310696SDavid.Hollister@Sun.COM 		if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx))
175410696SDavid.Hollister@Sun.COM 		    == -1) {
175510696SDavid.Hollister@Sun.COM 			NOREAD(tbuf, (tbuf_addr + idx));
175610696SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
175710696SDavid.Hollister@Sun.COM 		}
175810696SDavid.Hollister@Sun.COM 
175911048SDavid.Hollister@Sun.COM 		/*
176011048SDavid.Hollister@Sun.COM 		 * Check for filtering on HBA instance
176111048SDavid.Hollister@Sun.COM 		 */
176210696SDavid.Hollister@Sun.COM 		elem_filtered = B_FALSE;
176310696SDavid.Hollister@Sun.COM 
176410696SDavid.Hollister@Sun.COM 		if (filter) {
176510696SDavid.Hollister@Sun.COM 			bufp = tbuf.buf;
176610696SDavid.Hollister@Sun.COM 			/* Skip the driver name */
176710696SDavid.Hollister@Sun.COM 			while (*bufp < '0' || *bufp > '9') {
176810696SDavid.Hollister@Sun.COM 				bufp++;
176910696SDavid.Hollister@Sun.COM 			}
177010696SDavid.Hollister@Sun.COM 
177110696SDavid.Hollister@Sun.COM 			ei_idx = 0;
177210696SDavid.Hollister@Sun.COM 			elem_inst[ei_idx++] = '0';
177310696SDavid.Hollister@Sun.COM 			elem_inst[ei_idx++] = 't';
177410696SDavid.Hollister@Sun.COM 			while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) {
177510696SDavid.Hollister@Sun.COM 				elem_inst[ei_idx++] = *bufp;
177610696SDavid.Hollister@Sun.COM 				bufp++;
177710696SDavid.Hollister@Sun.COM 			}
177810696SDavid.Hollister@Sun.COM 			elem_inst[ei_idx] = 0;
177910696SDavid.Hollister@Sun.COM 
178010696SDavid.Hollister@Sun.COM 			/* Get the instance */
178110696SDavid.Hollister@Sun.COM 			if ((int)mdb_strtoull(elem_inst) != instance) {
178210696SDavid.Hollister@Sun.COM 				elem_filtered = B_TRUE;
178310696SDavid.Hollister@Sun.COM 			}
178410696SDavid.Hollister@Sun.COM 		}
178510696SDavid.Hollister@Sun.COM 
178611048SDavid.Hollister@Sun.COM 		if (!elem_filtered && (phy_path || sas_address)) {
178711048SDavid.Hollister@Sun.COM 			/*
178811048SDavid.Hollister@Sun.COM 			 * This message is not being filtered by HBA instance.
178911048SDavid.Hollister@Sun.COM 			 * Now check to see if we're filtering based on
179011048SDavid.Hollister@Sun.COM 			 * PHY path or SAS address.
179111048SDavid.Hollister@Sun.COM 			 * Filtering is an "OR" operation.  So, if any of the
179211048SDavid.Hollister@Sun.COM 			 * criteria matches, this message will be printed.
179311048SDavid.Hollister@Sun.COM 			 */
179411048SDavid.Hollister@Sun.COM 			elem_filtered = B_TRUE;
179511048SDavid.Hollister@Sun.COM 
179611048SDavid.Hollister@Sun.COM 			if (phy_path != NULL) {
179711048SDavid.Hollister@Sun.COM 				if (strncmp(phy_path, tbuf.phy_path,
179811048SDavid.Hollister@Sun.COM 				    PMCS_TBUF_UA_MAX_SIZE) == 0) {
179911048SDavid.Hollister@Sun.COM 					elem_filtered = B_FALSE;
180011048SDavid.Hollister@Sun.COM 				}
180111048SDavid.Hollister@Sun.COM 			}
180211048SDavid.Hollister@Sun.COM 			if (sas_address != 0) {
180311048SDavid.Hollister@Sun.COM 				if (memcmp(sas_addressp, tbuf.phy_sas_address,
180411048SDavid.Hollister@Sun.COM 				    8) == 0) {
180511048SDavid.Hollister@Sun.COM 					elem_filtered = B_FALSE;
180611048SDavid.Hollister@Sun.COM 				}
180711048SDavid.Hollister@Sun.COM 			}
180811048SDavid.Hollister@Sun.COM 		}
180911048SDavid.Hollister@Sun.COM 
181010696SDavid.Hollister@Sun.COM 		if (!elem_filtered) {
181110696SDavid.Hollister@Sun.COM 			mdb_printf("%Y.%09ld %s\n", tbuf.timestamp, tbuf.buf);
181210696SDavid.Hollister@Sun.COM 		}
181310696SDavid.Hollister@Sun.COM 
181410696SDavid.Hollister@Sun.COM 		--elems_to_print;
181510696SDavid.Hollister@Sun.COM 		if (++idx == tbuf_num_elems) {
181610696SDavid.Hollister@Sun.COM 			idx = 0;
181710696SDavid.Hollister@Sun.COM 		}
181810696SDavid.Hollister@Sun.COM 	}
181910696SDavid.Hollister@Sun.COM 
182010696SDavid.Hollister@Sun.COM 	return (DCMD_OK);
182110696SDavid.Hollister@Sun.COM }
182210696SDavid.Hollister@Sun.COM 
182310696SDavid.Hollister@Sun.COM /*
182410696SDavid.Hollister@Sun.COM  * Walkers
182510696SDavid.Hollister@Sun.COM  */
182610696SDavid.Hollister@Sun.COM static int
182710696SDavid.Hollister@Sun.COM targets_walk_i(mdb_walk_state_t *wsp)
182810696SDavid.Hollister@Sun.COM {
182910696SDavid.Hollister@Sun.COM 	if (wsp->walk_addr == NULL) {
183010696SDavid.Hollister@Sun.COM 		mdb_warn("Can not perform global walk\n");
183110696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
183210696SDavid.Hollister@Sun.COM 	}
183310696SDavid.Hollister@Sun.COM 
183410696SDavid.Hollister@Sun.COM 	/*
183510696SDavid.Hollister@Sun.COM 	 * Address provided belongs to HBA softstate.  Get the targets pointer
183610696SDavid.Hollister@Sun.COM 	 * to begin the walk.
183710696SDavid.Hollister@Sun.COM 	 */
183810696SDavid.Hollister@Sun.COM 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
183910696SDavid.Hollister@Sun.COM 	    sizeof (pmcs_hw_t)) {
184010696SDavid.Hollister@Sun.COM 		mdb_warn("Unable to read HBA softstate\n");
184110696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
184210696SDavid.Hollister@Sun.COM 	}
184310696SDavid.Hollister@Sun.COM 
184410696SDavid.Hollister@Sun.COM 	if (targets == NULL) {
184510696SDavid.Hollister@Sun.COM 		targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP);
184610696SDavid.Hollister@Sun.COM 	}
184710696SDavid.Hollister@Sun.COM 
184810696SDavid.Hollister@Sun.COM 	if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) {
184910696SDavid.Hollister@Sun.COM 		NOREAD(targets, ss.targets);
185010696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
185110696SDavid.Hollister@Sun.COM 	}
185210696SDavid.Hollister@Sun.COM 
185310696SDavid.Hollister@Sun.COM 	target_idx = 0;
185410696SDavid.Hollister@Sun.COM 	wsp->walk_addr = (uintptr_t)(targets[0]);
185510696SDavid.Hollister@Sun.COM 	wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP);
185610696SDavid.Hollister@Sun.COM 
185710696SDavid.Hollister@Sun.COM 	return (WALK_NEXT);
185810696SDavid.Hollister@Sun.COM }
185910696SDavid.Hollister@Sun.COM 
186010696SDavid.Hollister@Sun.COM static int
186110696SDavid.Hollister@Sun.COM targets_walk_s(mdb_walk_state_t *wsp)
186210696SDavid.Hollister@Sun.COM {
186310696SDavid.Hollister@Sun.COM 	int status;
186410696SDavid.Hollister@Sun.COM 
186510696SDavid.Hollister@Sun.COM 	if (target_idx == ss.max_dev) {
186610696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
186710696SDavid.Hollister@Sun.COM 	}
186810696SDavid.Hollister@Sun.COM 
186910696SDavid.Hollister@Sun.COM 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t),
187010696SDavid.Hollister@Sun.COM 	    wsp->walk_addr) == -1) {
187110696SDavid.Hollister@Sun.COM 		mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr);
187210696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
187310696SDavid.Hollister@Sun.COM 	}
187410696SDavid.Hollister@Sun.COM 
187510696SDavid.Hollister@Sun.COM 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
187610696SDavid.Hollister@Sun.COM 	    wsp->walk_cbdata);
187710696SDavid.Hollister@Sun.COM 
187810696SDavid.Hollister@Sun.COM 	do {
187910696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)(targets[++target_idx]);
188010696SDavid.Hollister@Sun.COM 	} while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev));
188110696SDavid.Hollister@Sun.COM 
188210696SDavid.Hollister@Sun.COM 	if (target_idx == ss.max_dev) {
188310696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
188410696SDavid.Hollister@Sun.COM 	}
188510696SDavid.Hollister@Sun.COM 
188610696SDavid.Hollister@Sun.COM 	return (status);
188710696SDavid.Hollister@Sun.COM }
188810696SDavid.Hollister@Sun.COM 
188910696SDavid.Hollister@Sun.COM static void
189010696SDavid.Hollister@Sun.COM targets_walk_f(mdb_walk_state_t *wsp)
189110696SDavid.Hollister@Sun.COM {
189210696SDavid.Hollister@Sun.COM 	mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t));
189310696SDavid.Hollister@Sun.COM }
189410696SDavid.Hollister@Sun.COM 
189510696SDavid.Hollister@Sun.COM 
189610696SDavid.Hollister@Sun.COM static pmcs_phy_t *
189710696SDavid.Hollister@Sun.COM pmcs_next_sibling(pmcs_phy_t *phyp)
189810696SDavid.Hollister@Sun.COM {
189910696SDavid.Hollister@Sun.COM 	pmcs_phy_t parent;
190010696SDavid.Hollister@Sun.COM 
190110696SDavid.Hollister@Sun.COM 	/*
190210696SDavid.Hollister@Sun.COM 	 * First, if this is a root PHY, there are no more siblings
190310696SDavid.Hollister@Sun.COM 	 */
190410696SDavid.Hollister@Sun.COM 	if (phyp->level == 0) {
190510696SDavid.Hollister@Sun.COM 		return (NULL);
190610696SDavid.Hollister@Sun.COM 	}
190710696SDavid.Hollister@Sun.COM 
190810696SDavid.Hollister@Sun.COM 	/*
190910696SDavid.Hollister@Sun.COM 	 * Otherwise, next sibling is the parent's sibling
191010696SDavid.Hollister@Sun.COM 	 */
191110696SDavid.Hollister@Sun.COM 	while (phyp->level > 0) {
191210696SDavid.Hollister@Sun.COM 		if (mdb_vread(&parent, sizeof (pmcs_phy_t),
191310696SDavid.Hollister@Sun.COM 		    (uintptr_t)phyp->parent) == -1) {
191410696SDavid.Hollister@Sun.COM 			mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
191510696SDavid.Hollister@Sun.COM 			    (void *)phyp->parent);
191610696SDavid.Hollister@Sun.COM 			return (NULL);
191710696SDavid.Hollister@Sun.COM 		}
191810696SDavid.Hollister@Sun.COM 
191910696SDavid.Hollister@Sun.COM 		if (parent.sibling != NULL) {
192010696SDavid.Hollister@Sun.COM 			break;
192110696SDavid.Hollister@Sun.COM 		}
192210696SDavid.Hollister@Sun.COM 
192310696SDavid.Hollister@Sun.COM 		phyp = phyp->parent;
192410696SDavid.Hollister@Sun.COM 	}
192510696SDavid.Hollister@Sun.COM 
192610696SDavid.Hollister@Sun.COM 	return (parent.sibling);
192710696SDavid.Hollister@Sun.COM }
192810696SDavid.Hollister@Sun.COM 
192910696SDavid.Hollister@Sun.COM static int
193010696SDavid.Hollister@Sun.COM phy_walk_i(mdb_walk_state_t *wsp)
193110696SDavid.Hollister@Sun.COM {
193210696SDavid.Hollister@Sun.COM 	if (wsp->walk_addr == NULL) {
193310696SDavid.Hollister@Sun.COM 		mdb_warn("Can not perform global walk\n");
193410696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
193510696SDavid.Hollister@Sun.COM 	}
193610696SDavid.Hollister@Sun.COM 
193710696SDavid.Hollister@Sun.COM 	/*
193810696SDavid.Hollister@Sun.COM 	 * Address provided belongs to HBA softstate.  Get the targets pointer
193910696SDavid.Hollister@Sun.COM 	 * to begin the walk.
194010696SDavid.Hollister@Sun.COM 	 */
194110696SDavid.Hollister@Sun.COM 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
194210696SDavid.Hollister@Sun.COM 	    sizeof (pmcs_hw_t)) {
194310696SDavid.Hollister@Sun.COM 		mdb_warn("Unable to read HBA softstate\n");
194410696SDavid.Hollister@Sun.COM 		return (WALK_ERR);
194510696SDavid.Hollister@Sun.COM 	}
194610696SDavid.Hollister@Sun.COM 
194710696SDavid.Hollister@Sun.COM 	wsp->walk_addr = (uintptr_t)(ss.root_phys);
194810696SDavid.Hollister@Sun.COM 	wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
194910696SDavid.Hollister@Sun.COM 
195010696SDavid.Hollister@Sun.COM 	return (WALK_NEXT);
195110696SDavid.Hollister@Sun.COM }
195210696SDavid.Hollister@Sun.COM 
195310696SDavid.Hollister@Sun.COM static int
195410696SDavid.Hollister@Sun.COM phy_walk_s(mdb_walk_state_t *wsp)
195510696SDavid.Hollister@Sun.COM {
195610696SDavid.Hollister@Sun.COM 	pmcs_phy_t *phyp, *nphyp;
195710696SDavid.Hollister@Sun.COM 	int status;
195810696SDavid.Hollister@Sun.COM 
195910696SDavid.Hollister@Sun.COM 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t),
196010696SDavid.Hollister@Sun.COM 	    wsp->walk_addr) == -1) {
196110696SDavid.Hollister@Sun.COM 		mdb_warn("phy_walk_s: Failed to read PHY at %p",
196210696SDavid.Hollister@Sun.COM 		    (void *)wsp->walk_addr);
196310696SDavid.Hollister@Sun.COM 		return (WALK_DONE);
196410696SDavid.Hollister@Sun.COM 	}
196510696SDavid.Hollister@Sun.COM 
196610696SDavid.Hollister@Sun.COM 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
196710696SDavid.Hollister@Sun.COM 	    wsp->walk_cbdata);
196810696SDavid.Hollister@Sun.COM 
196910696SDavid.Hollister@Sun.COM 	phyp = (pmcs_phy_t *)wsp->walk_data;
197010696SDavid.Hollister@Sun.COM 	if (phyp->children) {
197110696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)(phyp->children);
197210696SDavid.Hollister@Sun.COM 	} else {
197310696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)(phyp->sibling);
197410696SDavid.Hollister@Sun.COM 	}
197510696SDavid.Hollister@Sun.COM 
197610696SDavid.Hollister@Sun.COM 	if (wsp->walk_addr == NULL) {
197710696SDavid.Hollister@Sun.COM 		/*
197810696SDavid.Hollister@Sun.COM 		 * We reached the end of this sibling list.  Trudge back up
197910696SDavid.Hollister@Sun.COM 		 * to the parent and find the next sibling after the expander
198010696SDavid.Hollister@Sun.COM 		 * we just finished traversing, if there is one.
198110696SDavid.Hollister@Sun.COM 		 */
198210696SDavid.Hollister@Sun.COM 		nphyp = pmcs_next_sibling(phyp);
198310696SDavid.Hollister@Sun.COM 
198410696SDavid.Hollister@Sun.COM 		if (nphyp == NULL) {
198510696SDavid.Hollister@Sun.COM 			return (WALK_DONE);
198610696SDavid.Hollister@Sun.COM 		}
198710696SDavid.Hollister@Sun.COM 
198810696SDavid.Hollister@Sun.COM 		wsp->walk_addr = (uintptr_t)nphyp;
198910696SDavid.Hollister@Sun.COM 	}
199010696SDavid.Hollister@Sun.COM 
199110696SDavid.Hollister@Sun.COM 	return (status);
199210696SDavid.Hollister@Sun.COM }
199310696SDavid.Hollister@Sun.COM 
199410696SDavid.Hollister@Sun.COM static void
199510696SDavid.Hollister@Sun.COM phy_walk_f(mdb_walk_state_t *wsp)
199610696SDavid.Hollister@Sun.COM {
199710696SDavid.Hollister@Sun.COM 	mdb_free(wsp->walk_data, sizeof (pmcs_phy_t));
199810696SDavid.Hollister@Sun.COM }
199910696SDavid.Hollister@Sun.COM 
200010743SDavid.Hollister@Sun.COM static void
200110743SDavid.Hollister@Sun.COM display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum,
200210743SDavid.Hollister@Sun.COM     uintmax_t tag_type)
200310743SDavid.Hollister@Sun.COM {
200410743SDavid.Hollister@Sun.COM 	int		idx;
200510743SDavid.Hollister@Sun.COM 	pmcwork_t	work, *wp = &work;
200610743SDavid.Hollister@Sun.COM 	uintptr_t	_wp;
200710743SDavid.Hollister@Sun.COM 	boolean_t	printed_header = B_FALSE;
200810743SDavid.Hollister@Sun.COM 	uint32_t	mask, mask_val, match_val;
200910743SDavid.Hollister@Sun.COM 	char		*match_type;
201010743SDavid.Hollister@Sun.COM 
201110743SDavid.Hollister@Sun.COM 	if (index != UINT_MAX) {
201210743SDavid.Hollister@Sun.COM 		match_type = "index";
201310743SDavid.Hollister@Sun.COM 		mask = PMCS_TAG_INDEX_MASK;
201410743SDavid.Hollister@Sun.COM 		mask_val = index << PMCS_TAG_INDEX_SHIFT;
201510743SDavid.Hollister@Sun.COM 		match_val = index;
201610743SDavid.Hollister@Sun.COM 	} else if (snum != UINT_MAX) {
201710743SDavid.Hollister@Sun.COM 		match_type = "serial number";
201810743SDavid.Hollister@Sun.COM 		mask = PMCS_TAG_SERNO_MASK;
201910743SDavid.Hollister@Sun.COM 		mask_val = snum << PMCS_TAG_SERNO_SHIFT;
202010743SDavid.Hollister@Sun.COM 		match_val = snum;
202110743SDavid.Hollister@Sun.COM 	} else {
202210743SDavid.Hollister@Sun.COM 		switch (tag_type) {
202310743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_NONE:
202410743SDavid.Hollister@Sun.COM 			match_type = "tag type NONE";
202510743SDavid.Hollister@Sun.COM 			break;
202610743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_CBACK:
202710743SDavid.Hollister@Sun.COM 			match_type = "tag type CBACK";
202810743SDavid.Hollister@Sun.COM 			break;
202910743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_WAIT:
203010743SDavid.Hollister@Sun.COM 			match_type = "tag type WAIT";
203110743SDavid.Hollister@Sun.COM 			break;
203210743SDavid.Hollister@Sun.COM 		}
203310743SDavid.Hollister@Sun.COM 		mask = PMCS_TAG_TYPE_MASK;
203410743SDavid.Hollister@Sun.COM 		mask_val = tag_type << PMCS_TAG_TYPE_SHIFT;
203510743SDavid.Hollister@Sun.COM 		match_val = tag_type;
203610743SDavid.Hollister@Sun.COM 	}
203710743SDavid.Hollister@Sun.COM 
203810743SDavid.Hollister@Sun.COM 	_wp = (uintptr_t)ss.work;
203910743SDavid.Hollister@Sun.COM 
204010743SDavid.Hollister@Sun.COM 	for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
204110743SDavid.Hollister@Sun.COM 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
204210743SDavid.Hollister@Sun.COM 			NOREAD(pmcwork_t, _wp);
204310743SDavid.Hollister@Sun.COM 			continue;
204410743SDavid.Hollister@Sun.COM 		}
204510743SDavid.Hollister@Sun.COM 
204610743SDavid.Hollister@Sun.COM 		if ((work.htag & mask) != mask_val) {
204710743SDavid.Hollister@Sun.COM 			continue;
204810743SDavid.Hollister@Sun.COM 		}
204910743SDavid.Hollister@Sun.COM 
205010743SDavid.Hollister@Sun.COM 		if (printed_header == B_FALSE) {
205110743SDavid.Hollister@Sun.COM 			if (tag_type) {
205210743SDavid.Hollister@Sun.COM 				mdb_printf("\nWork structures matching %s\n\n",
205310743SDavid.Hollister@Sun.COM 				    match_type, match_val);
205410743SDavid.Hollister@Sun.COM 			} else {
205510743SDavid.Hollister@Sun.COM 				mdb_printf("\nWork structures matching %s of "
205610743SDavid.Hollister@Sun.COM 				    "0x%x\n\n", match_type, match_val);
205710743SDavid.Hollister@Sun.COM 			}
205810743SDavid.Hollister@Sun.COM 			mdb_printf("%8s %10s %20s %8s %8s O D\n",
205910743SDavid.Hollister@Sun.COM 			    "HTag", "State", "Phy Path", "Target", "Timer");
206010743SDavid.Hollister@Sun.COM 			printed_header = B_TRUE;
206110743SDavid.Hollister@Sun.COM 		}
206210743SDavid.Hollister@Sun.COM 
206310743SDavid.Hollister@Sun.COM 		display_one_work(wp, 0, 0);
206410743SDavid.Hollister@Sun.COM 	}
206510743SDavid.Hollister@Sun.COM 
206610743SDavid.Hollister@Sun.COM 	if (!printed_header) {
206710743SDavid.Hollister@Sun.COM 		mdb_printf("No work structure matches found\n");
206810743SDavid.Hollister@Sun.COM 	}
206910743SDavid.Hollister@Sun.COM }
207010743SDavid.Hollister@Sun.COM 
207110743SDavid.Hollister@Sun.COM static int
207210743SDavid.Hollister@Sun.COM pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
207310743SDavid.Hollister@Sun.COM {
207410743SDavid.Hollister@Sun.COM 	struct	pmcs_hw		ss;
207510743SDavid.Hollister@Sun.COM 	uintmax_t		tag_type = UINT_MAX;
207610743SDavid.Hollister@Sun.COM 	uintmax_t		snum = UINT_MAX;
207710743SDavid.Hollister@Sun.COM 	uintmax_t		index = UINT_MAX;
207810743SDavid.Hollister@Sun.COM 	int			args = 0;
207910743SDavid.Hollister@Sun.COM 	void			*pmcs_state;
208010743SDavid.Hollister@Sun.COM 	char			*state_str;
208110743SDavid.Hollister@Sun.COM 	struct dev_info		dip;
208210743SDavid.Hollister@Sun.COM 
208310743SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
208410743SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
208510743SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
208610743SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
208710743SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
208810743SDavid.Hollister@Sun.COM 		}
208910743SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc,
209010743SDavid.Hollister@Sun.COM 		    argv, (uintptr_t)pmcs_state) == -1) {
209110743SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed");
209210743SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
209310743SDavid.Hollister@Sun.COM 		}
209410743SDavid.Hollister@Sun.COM 		return (DCMD_OK);
209510743SDavid.Hollister@Sun.COM 	}
209610743SDavid.Hollister@Sun.COM 
209710743SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv,
209810743SDavid.Hollister@Sun.COM 	    'i', MDB_OPT_UINT64, &index,
209910743SDavid.Hollister@Sun.COM 	    's', MDB_OPT_UINT64, &snum,
210010743SDavid.Hollister@Sun.COM 	    't', MDB_OPT_UINT64, &tag_type) != argc)
210110743SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
210210743SDavid.Hollister@Sun.COM 
210310743SDavid.Hollister@Sun.COM 	/*
210410743SDavid.Hollister@Sun.COM 	 * Count the number of supplied options and make sure they are
210510743SDavid.Hollister@Sun.COM 	 * within appropriate ranges.  If they're set to UINT_MAX, that means
210610743SDavid.Hollister@Sun.COM 	 * they were not supplied, in which case reset them to 0.
210710743SDavid.Hollister@Sun.COM 	 */
210810743SDavid.Hollister@Sun.COM 	if (index != UINT_MAX) {
210910743SDavid.Hollister@Sun.COM 		args++;
211010743SDavid.Hollister@Sun.COM 		if (index > PMCS_TAG_INDEX_MASK) {
211110743SDavid.Hollister@Sun.COM 			mdb_warn("Index is out of range\n");
211210743SDavid.Hollister@Sun.COM 			return (DCMD_USAGE);
211310743SDavid.Hollister@Sun.COM 		}
211410743SDavid.Hollister@Sun.COM 	}
211510743SDavid.Hollister@Sun.COM 
211610743SDavid.Hollister@Sun.COM 	if (tag_type != UINT_MAX) {
211710743SDavid.Hollister@Sun.COM 		args++;
211810743SDavid.Hollister@Sun.COM 		switch (tag_type) {
211910743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_NONE:
212010743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_CBACK:
212110743SDavid.Hollister@Sun.COM 		case PMCS_TAG_TYPE_WAIT:
212210743SDavid.Hollister@Sun.COM 			break;
212310743SDavid.Hollister@Sun.COM 		default:
212410743SDavid.Hollister@Sun.COM 			mdb_warn("Invalid tag type\n");
212510743SDavid.Hollister@Sun.COM 			return (DCMD_USAGE);
212610743SDavid.Hollister@Sun.COM 		}
212710743SDavid.Hollister@Sun.COM 	}
212810743SDavid.Hollister@Sun.COM 
212910743SDavid.Hollister@Sun.COM 	if (snum != UINT_MAX) {
213010743SDavid.Hollister@Sun.COM 		args++;
213110743SDavid.Hollister@Sun.COM 		if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) {
213210743SDavid.Hollister@Sun.COM 			mdb_warn("Serial number is out of range\n");
213310743SDavid.Hollister@Sun.COM 			return (DCMD_USAGE);
213410743SDavid.Hollister@Sun.COM 		}
213510743SDavid.Hollister@Sun.COM 	}
213610743SDavid.Hollister@Sun.COM 
213710743SDavid.Hollister@Sun.COM 	/*
213810743SDavid.Hollister@Sun.COM 	 * Make sure 1 and only 1 option is specified
213910743SDavid.Hollister@Sun.COM 	 */
214010743SDavid.Hollister@Sun.COM 	if ((args == 0) || (args > 1)) {
214110743SDavid.Hollister@Sun.COM 		mdb_warn("Exactly one of -i, -s and -t must be specified\n");
214210743SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
214310743SDavid.Hollister@Sun.COM 	}
214410743SDavid.Hollister@Sun.COM 
214510743SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
214610743SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
214710743SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
214810743SDavid.Hollister@Sun.COM 	}
214910743SDavid.Hollister@Sun.COM 
215010743SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
215110743SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
215210743SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
215310743SDavid.Hollister@Sun.COM 	}
215410743SDavid.Hollister@Sun.COM 
215510743SDavid.Hollister@Sun.COM 	/* processing completed */
215610743SDavid.Hollister@Sun.COM 
215710743SDavid.Hollister@Sun.COM 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
215810743SDavid.Hollister@Sun.COM 	    (flags & DCMD_LOOPFIRST)) {
215910743SDavid.Hollister@Sun.COM 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
216010743SDavid.Hollister@Sun.COM 			mdb_printf("\n");
216110743SDavid.Hollister@Sun.COM 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
216210743SDavid.Hollister@Sun.COM 		    "Address", "State", "Inst", "DIP");
216310743SDavid.Hollister@Sun.COM 		mdb_printf("================================="
216410743SDavid.Hollister@Sun.COM 		    "============================================\n");
216510743SDavid.Hollister@Sun.COM 	}
216610743SDavid.Hollister@Sun.COM 
216710743SDavid.Hollister@Sun.COM 	switch (ss.state) {
216810743SDavid.Hollister@Sun.COM 	case STATE_NIL:
216910743SDavid.Hollister@Sun.COM 		state_str = "Invalid";
217010743SDavid.Hollister@Sun.COM 		break;
217110743SDavid.Hollister@Sun.COM 	case STATE_PROBING:
217210743SDavid.Hollister@Sun.COM 		state_str = "Probing";
217310743SDavid.Hollister@Sun.COM 		break;
217410743SDavid.Hollister@Sun.COM 	case STATE_RUNNING:
217510743SDavid.Hollister@Sun.COM 		state_str = "Running";
217610743SDavid.Hollister@Sun.COM 		break;
217710743SDavid.Hollister@Sun.COM 	case STATE_UNPROBING:
217810743SDavid.Hollister@Sun.COM 		state_str = "Unprobing";
217910743SDavid.Hollister@Sun.COM 		break;
218010743SDavid.Hollister@Sun.COM 	case STATE_DEAD:
218110743SDavid.Hollister@Sun.COM 		state_str = "Dead";
218210743SDavid.Hollister@Sun.COM 		break;
218310743SDavid.Hollister@Sun.COM 	}
218410743SDavid.Hollister@Sun.COM 
218510743SDavid.Hollister@Sun.COM 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
218610743SDavid.Hollister@Sun.COM 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
218710743SDavid.Hollister@Sun.COM 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
218810743SDavid.Hollister@Sun.COM 	mdb_printf("\n");
218910743SDavid.Hollister@Sun.COM 
219010743SDavid.Hollister@Sun.COM 	mdb_inc_indent(4);
219110743SDavid.Hollister@Sun.COM 	display_matching_work(ss, index, snum, tag_type);
219210743SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
219310743SDavid.Hollister@Sun.COM 	mdb_printf("\n");
219410743SDavid.Hollister@Sun.COM 
219510743SDavid.Hollister@Sun.COM 	return (DCMD_OK);
219610743SDavid.Hollister@Sun.COM }
219710743SDavid.Hollister@Sun.COM 
219810696SDavid.Hollister@Sun.COM static int
219911048SDavid.Hollister@Sun.COM pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
220011048SDavid.Hollister@Sun.COM {
220111048SDavid.Hollister@Sun.COM 	void		*pmcs_state;
220211048SDavid.Hollister@Sun.COM 	struct pmcs_hw	ss;
220311048SDavid.Hollister@Sun.COM 	struct dev_info	dip;
220411048SDavid.Hollister@Sun.COM 	const char	*match_phy_path = NULL;
220511048SDavid.Hollister@Sun.COM 	uint64_t 	match_sas_address = 0;
220611048SDavid.Hollister@Sun.COM 
220711048SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
220811048SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
220911048SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
221011048SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
221111048SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
221211048SDavid.Hollister@Sun.COM 		}
221311048SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc,
221411048SDavid.Hollister@Sun.COM 		    argv, (uintptr_t)pmcs_state) == -1) {
221511048SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
221611048SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
221711048SDavid.Hollister@Sun.COM 		}
221811048SDavid.Hollister@Sun.COM 		return (DCMD_OK);
221911048SDavid.Hollister@Sun.COM 	}
222011048SDavid.Hollister@Sun.COM 
222111048SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv,
222211048SDavid.Hollister@Sun.COM 	    'p', MDB_OPT_STR, &match_phy_path,
222311048SDavid.Hollister@Sun.COM 	    's', MDB_OPT_UINT64, &match_sas_address,
222411048SDavid.Hollister@Sun.COM 	    NULL) != argc) {
222511048SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
222611048SDavid.Hollister@Sun.COM 	}
222711048SDavid.Hollister@Sun.COM 
222811048SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
222911048SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
223011048SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
223111048SDavid.Hollister@Sun.COM 	}
223211048SDavid.Hollister@Sun.COM 
223311048SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
223411048SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
223511048SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
223611048SDavid.Hollister@Sun.COM 	}
223711048SDavid.Hollister@Sun.COM 
223811048SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_LOOP)) {
223911048SDavid.Hollister@Sun.COM 		return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance,
224011048SDavid.Hollister@Sun.COM 		    match_phy_path, match_sas_address));
224111048SDavid.Hollister@Sun.COM 	} else if (flags & DCMD_LOOPFIRST) {
224211048SDavid.Hollister@Sun.COM 		return (pmcs_dump_tracelog(B_FALSE, 0, match_phy_path,
224311048SDavid.Hollister@Sun.COM 		    match_sas_address));
224411048SDavid.Hollister@Sun.COM 	} else {
224511048SDavid.Hollister@Sun.COM 		return (DCMD_OK);
224611048SDavid.Hollister@Sun.COM 	}
224711048SDavid.Hollister@Sun.COM }
224811048SDavid.Hollister@Sun.COM 
224911048SDavid.Hollister@Sun.COM static int
225010696SDavid.Hollister@Sun.COM pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
225110696SDavid.Hollister@Sun.COM {
225211048SDavid.Hollister@Sun.COM 	struct pmcs_hw		ss;
225310696SDavid.Hollister@Sun.COM 	uint_t			verbose = FALSE;
225410696SDavid.Hollister@Sun.COM 	uint_t			phy_info = FALSE;
225510696SDavid.Hollister@Sun.COM 	uint_t			hw_info = FALSE;
225610696SDavid.Hollister@Sun.COM 	uint_t			target_info = FALSE;
225710696SDavid.Hollister@Sun.COM 	uint_t			work_info = FALSE;
225810696SDavid.Hollister@Sun.COM 	uint_t			ic_info = FALSE;
225910696SDavid.Hollister@Sun.COM 	uint_t			iport_info = FALSE;
226010696SDavid.Hollister@Sun.COM 	uint_t			waitqs_info = FALSE;
226110696SDavid.Hollister@Sun.COM 	uint_t			ibq = FALSE;
226210696SDavid.Hollister@Sun.COM 	uint_t			obq = FALSE;
226310696SDavid.Hollister@Sun.COM 	uint_t			tgt_phy_count = FALSE;
226410743SDavid.Hollister@Sun.COM 	uint_t			compq = FALSE;
226511048SDavid.Hollister@Sun.COM 	uint_t			unconfigured = FALSE;
2266*11334SReed.Liu@Sun.COM 	uint_t			damap_info = FALSE;
2267*11334SReed.Liu@Sun.COM 	uint_t			dtc_info = FALSE;
226810696SDavid.Hollister@Sun.COM 	int			rv = DCMD_OK;
226910696SDavid.Hollister@Sun.COM 	void			*pmcs_state;
227010696SDavid.Hollister@Sun.COM 	char			*state_str;
227110696SDavid.Hollister@Sun.COM 	struct dev_info		dip;
2272*11334SReed.Liu@Sun.COM 	per_iport_setting_t	pis;
227310696SDavid.Hollister@Sun.COM 
227410696SDavid.Hollister@Sun.COM 	if (!(flags & DCMD_ADDRSPEC)) {
227510696SDavid.Hollister@Sun.COM 		pmcs_state = NULL;
227610696SDavid.Hollister@Sun.COM 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
227710696SDavid.Hollister@Sun.COM 			mdb_warn("can't read pmcs_softc_state");
227810696SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
227910696SDavid.Hollister@Sun.COM 		}
228010696SDavid.Hollister@Sun.COM 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv,
228110696SDavid.Hollister@Sun.COM 		    (uintptr_t)pmcs_state) == -1) {
228210696SDavid.Hollister@Sun.COM 			mdb_warn("mdb_pwalk_dcmd failed");
228310696SDavid.Hollister@Sun.COM 			return (DCMD_ERR);
228410696SDavid.Hollister@Sun.COM 		}
228510696SDavid.Hollister@Sun.COM 		return (DCMD_OK);
228610696SDavid.Hollister@Sun.COM 	}
228710696SDavid.Hollister@Sun.COM 
228810696SDavid.Hollister@Sun.COM 	if (mdb_getopts(argc, argv,
228910743SDavid.Hollister@Sun.COM 	    'c', MDB_OPT_SETBITS, TRUE, &compq,
2290*11334SReed.Liu@Sun.COM 	    'd', MDB_OPT_SETBITS, TRUE, &dtc_info,
229110696SDavid.Hollister@Sun.COM 	    'h', MDB_OPT_SETBITS, TRUE, &hw_info,
229210696SDavid.Hollister@Sun.COM 	    'i', MDB_OPT_SETBITS, TRUE, &ic_info,
229310696SDavid.Hollister@Sun.COM 	    'I', MDB_OPT_SETBITS, TRUE, &iport_info,
2294*11334SReed.Liu@Sun.COM 	    'm', MDB_OPT_SETBITS, TRUE, &damap_info,
229510696SDavid.Hollister@Sun.COM 	    'p', MDB_OPT_SETBITS, TRUE, &phy_info,
229610696SDavid.Hollister@Sun.COM 	    'q', MDB_OPT_SETBITS, TRUE, &ibq,
229710696SDavid.Hollister@Sun.COM 	    'Q', MDB_OPT_SETBITS, TRUE, &obq,
229810696SDavid.Hollister@Sun.COM 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
229910696SDavid.Hollister@Sun.COM 	    'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count,
230011048SDavid.Hollister@Sun.COM 	    'u', MDB_OPT_SETBITS, TRUE, &unconfigured,
230110696SDavid.Hollister@Sun.COM 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
230210696SDavid.Hollister@Sun.COM 	    'w', MDB_OPT_SETBITS, TRUE, &work_info,
230310696SDavid.Hollister@Sun.COM 	    'W', MDB_OPT_SETBITS, TRUE, &waitqs_info,
230410696SDavid.Hollister@Sun.COM 	    NULL) != argc)
230510696SDavid.Hollister@Sun.COM 		return (DCMD_USAGE);
230610696SDavid.Hollister@Sun.COM 
2307*11334SReed.Liu@Sun.COM 	/*
2308*11334SReed.Liu@Sun.COM 	 * The 'd' and 'm' options implicitly enable the 'I' option
2309*11334SReed.Liu@Sun.COM 	 */
2310*11334SReed.Liu@Sun.COM 	pis.pis_damap_info = damap_info;
2311*11334SReed.Liu@Sun.COM 	pis.pis_dtc_info = dtc_info;
2312*11334SReed.Liu@Sun.COM 	if (damap_info || dtc_info) {
2313*11334SReed.Liu@Sun.COM 		iport_info = TRUE;
2314*11334SReed.Liu@Sun.COM 	}
2315*11334SReed.Liu@Sun.COM 
231610696SDavid.Hollister@Sun.COM 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
231710696SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
231810696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
231910696SDavid.Hollister@Sun.COM 	}
232010696SDavid.Hollister@Sun.COM 
232110696SDavid.Hollister@Sun.COM 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
232210696SDavid.Hollister@Sun.COM 		NOREAD(pmcs_hw_t, addr);
232310696SDavid.Hollister@Sun.COM 		return (DCMD_ERR);
232410696SDavid.Hollister@Sun.COM 	}
232510696SDavid.Hollister@Sun.COM 
232610696SDavid.Hollister@Sun.COM 	/* processing completed */
232710696SDavid.Hollister@Sun.COM 
232810696SDavid.Hollister@Sun.COM 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
232910696SDavid.Hollister@Sun.COM 	    (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info ||
233011048SDavid.Hollister@Sun.COM 	    work_info || waitqs_info || ibq || obq || tgt_phy_count || compq ||
233111048SDavid.Hollister@Sun.COM 	    unconfigured) {
233210696SDavid.Hollister@Sun.COM 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
233310696SDavid.Hollister@Sun.COM 			mdb_printf("\n");
233410696SDavid.Hollister@Sun.COM 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
233510696SDavid.Hollister@Sun.COM 		    "Address", "State", "Inst", "DIP");
233610696SDavid.Hollister@Sun.COM 		mdb_printf("================================="
233710696SDavid.Hollister@Sun.COM 		    "============================================\n");
233810696SDavid.Hollister@Sun.COM 	}
233910696SDavid.Hollister@Sun.COM 
234010696SDavid.Hollister@Sun.COM 	switch (ss.state) {
234110696SDavid.Hollister@Sun.COM 	case STATE_NIL:
234210696SDavid.Hollister@Sun.COM 		state_str = "Invalid";
234310696SDavid.Hollister@Sun.COM 		break;
234410696SDavid.Hollister@Sun.COM 	case STATE_PROBING:
234510696SDavid.Hollister@Sun.COM 		state_str = "Probing";
234610696SDavid.Hollister@Sun.COM 		break;
234710696SDavid.Hollister@Sun.COM 	case STATE_RUNNING:
234810696SDavid.Hollister@Sun.COM 		state_str = "Running";
234910696SDavid.Hollister@Sun.COM 		break;
235010696SDavid.Hollister@Sun.COM 	case STATE_UNPROBING:
235110696SDavid.Hollister@Sun.COM 		state_str = "Unprobing";
235210696SDavid.Hollister@Sun.COM 		break;
235310696SDavid.Hollister@Sun.COM 	case STATE_DEAD:
235410696SDavid.Hollister@Sun.COM 		state_str = "Dead";
235510696SDavid.Hollister@Sun.COM 		break;
235610696SDavid.Hollister@Sun.COM 	}
235710696SDavid.Hollister@Sun.COM 
235810696SDavid.Hollister@Sun.COM 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
235910696SDavid.Hollister@Sun.COM 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
236010696SDavid.Hollister@Sun.COM 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
236110696SDavid.Hollister@Sun.COM 	mdb_printf("\n");
236210696SDavid.Hollister@Sun.COM 
236310696SDavid.Hollister@Sun.COM 	mdb_inc_indent(4);
236410696SDavid.Hollister@Sun.COM 
236510696SDavid.Hollister@Sun.COM 	if (waitqs_info)
236610696SDavid.Hollister@Sun.COM 		display_waitqs(ss, verbose);
236710696SDavid.Hollister@Sun.COM 
236810696SDavid.Hollister@Sun.COM 	if (hw_info)
236910696SDavid.Hollister@Sun.COM 		display_hwinfo(ss, verbose);
237010696SDavid.Hollister@Sun.COM 
237110696SDavid.Hollister@Sun.COM 	if (phy_info || tgt_phy_count)
237210696SDavid.Hollister@Sun.COM 		display_phys(ss, verbose, NULL, 0, tgt_phy_count);
237310696SDavid.Hollister@Sun.COM 
237410696SDavid.Hollister@Sun.COM 	if (target_info || tgt_phy_count)
237510696SDavid.Hollister@Sun.COM 		display_targets(ss, verbose, tgt_phy_count);
237610696SDavid.Hollister@Sun.COM 
237710696SDavid.Hollister@Sun.COM 	if (work_info)
237810696SDavid.Hollister@Sun.COM 		display_work(ss, verbose);
237910696SDavid.Hollister@Sun.COM 
238010696SDavid.Hollister@Sun.COM 	if (ic_info)
238110696SDavid.Hollister@Sun.COM 		display_ic(ss, verbose);
238210696SDavid.Hollister@Sun.COM 
238310696SDavid.Hollister@Sun.COM 	if (ibq)
238410696SDavid.Hollister@Sun.COM 		display_inbound_queues(ss, verbose);
238510696SDavid.Hollister@Sun.COM 
238610696SDavid.Hollister@Sun.COM 	if (obq)
238710696SDavid.Hollister@Sun.COM 		display_outbound_queues(ss, verbose);
238810696SDavid.Hollister@Sun.COM 
238910696SDavid.Hollister@Sun.COM 	if (iport_info)
2390*11334SReed.Liu@Sun.COM 		display_iport(ss, addr, verbose, &pis);
239110696SDavid.Hollister@Sun.COM 
239210743SDavid.Hollister@Sun.COM 	if (compq)
239310743SDavid.Hollister@Sun.COM 		display_completion_queue(ss);
239410743SDavid.Hollister@Sun.COM 
239511048SDavid.Hollister@Sun.COM 	if (unconfigured)
239611048SDavid.Hollister@Sun.COM 		display_unconfigured_targets(addr);
239711048SDavid.Hollister@Sun.COM 
239810696SDavid.Hollister@Sun.COM 	mdb_dec_indent(4);
239910696SDavid.Hollister@Sun.COM 
240010696SDavid.Hollister@Sun.COM 	return (rv);
240110696SDavid.Hollister@Sun.COM }
240210696SDavid.Hollister@Sun.COM 
240310696SDavid.Hollister@Sun.COM void
240410696SDavid.Hollister@Sun.COM pmcs_help()
240510696SDavid.Hollister@Sun.COM {
240610696SDavid.Hollister@Sun.COM 	mdb_printf("Prints summary information about each pmcs instance.\n"
240710743SDavid.Hollister@Sun.COM 	    "    -c: Dump the completion queue\n"
2408*11334SReed.Liu@Sun.COM 	    "    -d: Print per-iport information about device tree children\n"
240910696SDavid.Hollister@Sun.COM 	    "    -h: Print more detailed hardware information\n"
241010696SDavid.Hollister@Sun.COM 	    "    -i: Print interrupt coalescing information\n"
241110696SDavid.Hollister@Sun.COM 	    "    -I: Print information about each iport\n"
2412*11334SReed.Liu@Sun.COM 	    "    -m: Print per-iport information about DAM/damap state\n"
241310696SDavid.Hollister@Sun.COM 	    "    -p: Print information about each attached PHY\n"
241410696SDavid.Hollister@Sun.COM 	    "    -q: Dump inbound queues\n"
241510696SDavid.Hollister@Sun.COM 	    "    -Q: Dump outbound queues\n"
241611048SDavid.Hollister@Sun.COM 	    "    -t: Print information about each configured target\n"
241710696SDavid.Hollister@Sun.COM 	    "    -T: Print target and PHY count summary\n"
241811048SDavid.Hollister@Sun.COM 	    "    -u: Show SAS address of all unconfigured targets\n"
241910696SDavid.Hollister@Sun.COM 	    "    -w: Dump work structures\n"
242010696SDavid.Hollister@Sun.COM 	    "    -W: List pmcs cmds waiting on various queues\n"
242110696SDavid.Hollister@Sun.COM 	    "    -v: Add verbosity to the above options\n");
242210696SDavid.Hollister@Sun.COM }
242310696SDavid.Hollister@Sun.COM 
242410743SDavid.Hollister@Sun.COM void
242511048SDavid.Hollister@Sun.COM pmcs_log_help()
242611048SDavid.Hollister@Sun.COM {
242711048SDavid.Hollister@Sun.COM 	mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n"
242811048SDavid.Hollister@Sun.COM 	    "    -p PHY_PATH:            Dump messages matching PHY_PATH\n"
242911048SDavid.Hollister@Sun.COM 	    "    -s SAS_ADDRESS:         Dump messages matching SAS_ADDRESS\n\n"
243011048SDavid.Hollister@Sun.COM 	    "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n"
243111048SDavid.Hollister@Sun.COM 	    "       SAS_ADDRESS can be found with ::pmcs -t "
243211048SDavid.Hollister@Sun.COM 	    "(e.g. 5000c5000358c221)\n");
243311048SDavid.Hollister@Sun.COM }
243411048SDavid.Hollister@Sun.COM void
243510743SDavid.Hollister@Sun.COM pmcs_tag_help()
243610743SDavid.Hollister@Sun.COM {
243710743SDavid.Hollister@Sun.COM 	mdb_printf("Print all work structures by matching the tag.\n"
243810743SDavid.Hollister@Sun.COM 	    "    -i index:        Match tag index (0x000 - 0xfff)\n"
243910743SDavid.Hollister@Sun.COM 	    "    -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
244010743SDavid.Hollister@Sun.COM 	    "    -t tagtype:      Match tag type [NONE(1), CBACK(2), "
244110743SDavid.Hollister@Sun.COM 	    "WAIT(3)]\n");
244210743SDavid.Hollister@Sun.COM }
244310743SDavid.Hollister@Sun.COM 
244410696SDavid.Hollister@Sun.COM static const mdb_dcmd_t dcmds[] = {
2445*11334SReed.Liu@Sun.COM 	{ "pmcs", "?[-cdhiImpQqtTuwWv]", "print pmcs information",
244610696SDavid.Hollister@Sun.COM 	    pmcs_dcmd, pmcs_help
244710696SDavid.Hollister@Sun.COM 	},
244811048SDavid.Hollister@Sun.COM 	{ "pmcs_log",
244911048SDavid.Hollister@Sun.COM 	    "?[-p PHY_PATH | -s SAS_ADDRESS]",
245011048SDavid.Hollister@Sun.COM 	    "dump pmcs log file", pmcs_log, pmcs_log_help
245111048SDavid.Hollister@Sun.COM 	},
245210743SDavid.Hollister@Sun.COM 	{ "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
245310743SDavid.Hollister@Sun.COM 	    "Find work structures by tag type, serial number or index",
245410743SDavid.Hollister@Sun.COM 	    pmcs_tag, pmcs_tag_help
245510743SDavid.Hollister@Sun.COM 	},
245610696SDavid.Hollister@Sun.COM 	{ NULL }
245710696SDavid.Hollister@Sun.COM };
245810696SDavid.Hollister@Sun.COM 
245910696SDavid.Hollister@Sun.COM static const mdb_walker_t walkers[] = {
246010696SDavid.Hollister@Sun.COM 	{ "pmcs_targets", "walk target structures",
246110696SDavid.Hollister@Sun.COM 		targets_walk_i, targets_walk_s, targets_walk_f },
246210696SDavid.Hollister@Sun.COM 	{ "pmcs_phys", "walk PHY structures",
246310696SDavid.Hollister@Sun.COM 		phy_walk_i, phy_walk_s, phy_walk_f },
246410696SDavid.Hollister@Sun.COM 	{ NULL }
246510696SDavid.Hollister@Sun.COM };
246610696SDavid.Hollister@Sun.COM 
246710696SDavid.Hollister@Sun.COM static const mdb_modinfo_t modinfo = {
246810696SDavid.Hollister@Sun.COM 	MDB_API_VERSION, dcmds, walkers
246910696SDavid.Hollister@Sun.COM };
247010696SDavid.Hollister@Sun.COM 
247110696SDavid.Hollister@Sun.COM const mdb_modinfo_t *
247210696SDavid.Hollister@Sun.COM _mdb_init(void)
247310696SDavid.Hollister@Sun.COM {
247410696SDavid.Hollister@Sun.COM 	return (&modinfo);
247510696SDavid.Hollister@Sun.COM }
2476