xref: /titanic_51/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c (revision 33f5ff17089e3a43e6e730bf80384c233123dbd9)
14c06356bSdh142964 /*
24c06356bSdh142964  * CDDL HEADER START
34c06356bSdh142964  *
44c06356bSdh142964  * The contents of this file are subject to the terms of the
54c06356bSdh142964  * Common Development and Distribution License (the "License").
64c06356bSdh142964  * You may not use this file except in compliance with the License.
74c06356bSdh142964  *
84c06356bSdh142964  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c06356bSdh142964  * or http://www.opensolaris.org/os/licensing.
104c06356bSdh142964  * See the License for the specific language governing permissions
114c06356bSdh142964  * and limitations under the License.
124c06356bSdh142964  *
134c06356bSdh142964  * When distributing Covered Code, include this CDDL HEADER in each
144c06356bSdh142964  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c06356bSdh142964  * If applicable, add the following below this CDDL HEADER, with the
164c06356bSdh142964  * fields enclosed by brackets "[]" replaced with your own identifying
174c06356bSdh142964  * information: Portions Copyright [yyyy] [name of copyright owner]
184c06356bSdh142964  *
194c06356bSdh142964  * CDDL HEADER END
204c06356bSdh142964  */
214c06356bSdh142964 /*
22658280b6SDavid Hollister  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23*33f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
244c06356bSdh142964  */
254c06356bSdh142964 
264c06356bSdh142964 #include <limits.h>
274c06356bSdh142964 #include <sys/mdb_modapi.h>
28f7aef0b0SReed #include <mdb/mdb_ctf.h>
294c06356bSdh142964 #include <sys/sysinfo.h>
30c3bc407cSdh142964 #include <sys/byteorder.h>
31f7aef0b0SReed #include <sys/nvpair.h>
32f7aef0b0SReed #include <sys/damap.h>
334c06356bSdh142964 #include <sys/scsi/scsi.h>
344c06356bSdh142964 #include <sys/scsi/adapters/pmcs/pmcs.h>
359719310aSDavid Hollister #ifndef _KMDB
369719310aSDavid Hollister #include <sys/types.h>
379719310aSDavid Hollister #include <sys/stat.h>
389719310aSDavid Hollister #include <fcntl.h>
399719310aSDavid Hollister #include <unistd.h>
409719310aSDavid Hollister #endif	/* _KMDB */
414c06356bSdh142964 
42f7aef0b0SReed /*
43f7aef0b0SReed  * We need use this to pass the settings when display_iport
44f7aef0b0SReed  */
45f7aef0b0SReed typedef struct per_iport_setting {
46f7aef0b0SReed 	uint_t  pis_damap_info; /* -m: DAM/damap */
47f7aef0b0SReed 	uint_t  pis_dtc_info; /* -d: device tree children: dev_info/path_info */
48f7aef0b0SReed } per_iport_setting_t;
49f7aef0b0SReed 
50658280b6SDavid Hollister /*
51658280b6SDavid Hollister  * This structure is used for sorting work structures by the wserno
52658280b6SDavid Hollister  */
53658280b6SDavid Hollister typedef struct wserno_list {
54658280b6SDavid Hollister 	int serno;
55658280b6SDavid Hollister 	int idx;
56658280b6SDavid Hollister 	struct wserno_list *next;
57658280b6SDavid Hollister 	struct wserno_list *prev;
58658280b6SDavid Hollister } wserno_list_t;
59658280b6SDavid Hollister 
604c06356bSdh142964 #define	MDB_RD(a, b, c)		mdb_vread(a, b, (uintptr_t)c)
614c06356bSdh142964 #define	NOREAD(a, b)		mdb_warn("could not read " #a " at 0x%p", b)
624c06356bSdh142964 
634c06356bSdh142964 static pmcs_hw_t ss;
644c06356bSdh142964 static pmcs_xscsi_t **targets = NULL;
654c06356bSdh142964 static int target_idx;
664c06356bSdh142964 
674c06356bSdh142964 static uint32_t	sas_phys, sata_phys, exp_phys, num_expanders, empty_phys;
684c06356bSdh142964 
694c06356bSdh142964 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp);
7014d6cf0aSdh142964 static void display_one_work(pmcwork_t *wp, int verbose, int idx);
714c06356bSdh142964 
724c06356bSdh142964 static void
734c06356bSdh142964 print_sas_address(pmcs_phy_t *phy)
744c06356bSdh142964 {
754c06356bSdh142964 	int idx;
764c06356bSdh142964 
774c06356bSdh142964 	for (idx = 0; idx < 8; idx++) {
784c06356bSdh142964 		mdb_printf("%02x", phy->sas_address[idx]);
794c06356bSdh142964 	}
804c06356bSdh142964 }
814c06356bSdh142964 
821f81b464SDavid Hollister static void
831f81b464SDavid Hollister pmcs_fwtime_to_systime(struct pmcs_hw ss, uint32_t fw_hi, uint32_t fw_lo,
841f81b464SDavid Hollister     struct timespec *stime)
851f81b464SDavid Hollister {
861f81b464SDavid Hollister 	uint64_t fwtime;
871f81b464SDavid Hollister 	time_t secs;
881f81b464SDavid Hollister 	long nsecs;
891f81b464SDavid Hollister 	boolean_t backward_time = B_FALSE;
901f81b464SDavid Hollister 
911f81b464SDavid Hollister 	fwtime = ((uint64_t)fw_hi << 32) | fw_lo;
921f81b464SDavid Hollister 
931f81b464SDavid Hollister 	/*
941f81b464SDavid Hollister 	 * If fwtime < ss.fw_timestamp, then we need to adjust the clock
951f81b464SDavid Hollister 	 * time backwards from ss.sys_timestamp.  Otherwise, the adjustment
961f81b464SDavid Hollister 	 * goes forward in time
971f81b464SDavid Hollister 	 */
981f81b464SDavid Hollister 	if (fwtime >= ss.fw_timestamp) {
991f81b464SDavid Hollister 		fwtime -= ss.fw_timestamp;
1001f81b464SDavid Hollister 	} else {
1011f81b464SDavid Hollister 		fwtime = ss.fw_timestamp - fwtime;
1021f81b464SDavid Hollister 		backward_time = B_TRUE;
1031f81b464SDavid Hollister 	}
1041f81b464SDavid Hollister 
1051f81b464SDavid Hollister 	secs = ((time_t)fwtime / NSECS_PER_SEC);
1061f81b464SDavid Hollister 	nsecs = ((long)fwtime % NSECS_PER_SEC);
1071f81b464SDavid Hollister 
1081f81b464SDavid Hollister 	stime->tv_sec = ss.sys_timestamp.tv_sec;
1091f81b464SDavid Hollister 	stime->tv_nsec = ss.sys_timestamp.tv_nsec;
1101f81b464SDavid Hollister 
1111f81b464SDavid Hollister 	if (backward_time) {
1121f81b464SDavid Hollister 		if (stime->tv_nsec < nsecs) {
1131f81b464SDavid Hollister 			stime->tv_sec--;
1141f81b464SDavid Hollister 			stime->tv_nsec = stime->tv_nsec + NSECS_PER_SEC - nsecs;
1151f81b464SDavid Hollister 		} else {
1161f81b464SDavid Hollister 			stime->tv_nsec -= nsecs;
1171f81b464SDavid Hollister 		}
1181f81b464SDavid Hollister 		stime->tv_sec -= secs;
1191f81b464SDavid Hollister 	} else {
1201f81b464SDavid Hollister 		if (stime->tv_nsec + nsecs > NSECS_PER_SEC) {
1211f81b464SDavid Hollister 			stime->tv_sec++;
1221f81b464SDavid Hollister 		}
1231f81b464SDavid Hollister 		stime->tv_nsec = (stime->tv_nsec + nsecs) % NSECS_PER_SEC;
1241f81b464SDavid Hollister 		stime->tv_sec += secs;
1251f81b464SDavid Hollister 	}
1261f81b464SDavid Hollister }
1271f81b464SDavid Hollister 
1284c06356bSdh142964 /*ARGSUSED*/
1294c06356bSdh142964 static void
1304c06356bSdh142964 display_ic(struct pmcs_hw m, int verbose)
1314c06356bSdh142964 {
1324c06356bSdh142964 	int msec_per_tick;
1334c06356bSdh142964 
1344c06356bSdh142964 	if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
1354c06356bSdh142964 		mdb_warn("can't read msec_per_tick");
1364c06356bSdh142964 		msec_per_tick = 0;
1374c06356bSdh142964 	}
1384c06356bSdh142964 
1394c06356bSdh142964 	mdb_printf("\n");
1404c06356bSdh142964 	mdb_printf("Interrupt coalescing timer info\n");
1414c06356bSdh142964 	mdb_printf("-------------------------------\n");
1424c06356bSdh142964 	if (msec_per_tick == 0) {
1434c06356bSdh142964 		mdb_printf("Quantum                       : ?? ms\n");
1444c06356bSdh142964 	} else {
1454c06356bSdh142964 		mdb_printf("Quantum                       : %d ms\n",
1464c06356bSdh142964 		    m.io_intr_coal.quantum * msec_per_tick);
1474c06356bSdh142964 	}
1484c06356bSdh142964 	mdb_printf("Timer enabled                 : ");
1494c06356bSdh142964 	if (m.io_intr_coal.timer_on) {
1504c06356bSdh142964 		mdb_printf("Yes\n");
1514c06356bSdh142964 		mdb_printf("Coalescing timer value        : %d us\n",
1524c06356bSdh142964 		    m.io_intr_coal.intr_coal_timer);
1534c06356bSdh142964 	} else {
1544c06356bSdh142964 		mdb_printf("No\n");
1554c06356bSdh142964 	}
1564c06356bSdh142964 	mdb_printf("Total nsecs between interrupts: %ld\n",
1574c06356bSdh142964 	    m.io_intr_coal.nsecs_between_intrs);
1584c06356bSdh142964 	mdb_printf("Time of last I/O interrupt    : %ld\n",
1594c06356bSdh142964 	    m.io_intr_coal.last_io_comp);
1604c06356bSdh142964 	mdb_printf("Number of I/O interrupts      : %d\n",
1614c06356bSdh142964 	    m.io_intr_coal.num_intrs);
1624c06356bSdh142964 	mdb_printf("Number of I/O completions     : %d\n",
1634c06356bSdh142964 	    m.io_intr_coal.num_io_completions);
1644c06356bSdh142964 	mdb_printf("Max I/O completion interrupts : %d\n",
1654c06356bSdh142964 	    m.io_intr_coal.max_io_completions);
1664c06356bSdh142964 	mdb_printf("Measured ECHO int latency     : %d ns\n",
1674c06356bSdh142964 	    m.io_intr_coal.intr_latency);
1684c06356bSdh142964 	mdb_printf("Interrupt threshold           : %d\n",
1694c06356bSdh142964 	    m.io_intr_coal.intr_threshold);
1704c06356bSdh142964 }
1714c06356bSdh142964 
1724c06356bSdh142964 /*ARGSUSED*/
1734c06356bSdh142964 static int
1744c06356bSdh142964 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv)
1754c06356bSdh142964 {
1764c06356bSdh142964 	struct pmcs_phy		phy;
1774c06356bSdh142964 
1784c06356bSdh142964 	if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) !=
1794c06356bSdh142964 	    sizeof (struct pmcs_phy)) {
1804c06356bSdh142964 		return (DCMD_ERR);
1814c06356bSdh142964 	}
1824c06356bSdh142964 
1834c06356bSdh142964 	mdb_printf("%16p %2d\n", addr, phy.phynum);
1844c06356bSdh142964 
1854c06356bSdh142964 	return (0);
1864c06356bSdh142964 }
1874c06356bSdh142964 
188f7aef0b0SReed static int
189f7aef0b0SReed display_iport_damap(dev_info_t *pdip)
190f7aef0b0SReed {
191f7aef0b0SReed 	int rval = DCMD_ERR;
192f7aef0b0SReed 	struct dev_info dip;
193f7aef0b0SReed 	scsi_hba_tran_t sht;
194f7aef0b0SReed 	mdb_ctf_id_t istm_ctfid; /* impl_scsi_tgtmap_t ctf_id */
195f7aef0b0SReed 	ulong_t tmd_offset = 0; /* tgtmap_dam offset to impl_scsi_tgtmap_t */
196f7aef0b0SReed 	uintptr_t dam0;
197f7aef0b0SReed 	uintptr_t dam1;
198f7aef0b0SReed 
199f7aef0b0SReed 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
200f7aef0b0SReed 	    sizeof (struct dev_info)) {
201f7aef0b0SReed 		return (rval);
202f7aef0b0SReed 	}
203f7aef0b0SReed 
204f7aef0b0SReed 	if (dip.devi_driver_data == NULL) {
205f7aef0b0SReed 		return (rval);
206f7aef0b0SReed 	}
207f7aef0b0SReed 
208f7aef0b0SReed 	if (mdb_vread(&sht, sizeof (scsi_hba_tran_t),
209f7aef0b0SReed 	    (uintptr_t)dip.devi_driver_data) != sizeof (scsi_hba_tran_t)) {
210f7aef0b0SReed 		return (rval);
211f7aef0b0SReed 	}
212f7aef0b0SReed 
213f7aef0b0SReed 	if (sht.tran_tgtmap == NULL) {
214f7aef0b0SReed 		return (rval);
215f7aef0b0SReed 	}
216f7aef0b0SReed 
217f7aef0b0SReed 	if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid) != 0) {
218f7aef0b0SReed 		return (rval);
219f7aef0b0SReed 	}
220f7aef0b0SReed 
221f7aef0b0SReed 	if (mdb_ctf_offsetof(istm_ctfid, "tgtmap_dam", &tmd_offset) != 0) {
222f7aef0b0SReed 		return (rval);
223f7aef0b0SReed 	}
224f7aef0b0SReed 
225f7aef0b0SReed 	tmd_offset /= NBBY;
226f7aef0b0SReed 	mdb_vread(&dam0, sizeof (dam0),
227f7aef0b0SReed 	    (uintptr_t)(tmd_offset + (char *)sht.tran_tgtmap));
228f7aef0b0SReed 	mdb_vread(&dam1, sizeof (dam1),
229f7aef0b0SReed 	    (uintptr_t)(sizeof (dam0) + tmd_offset + (char *)sht.tran_tgtmap));
230f7aef0b0SReed 
231f7aef0b0SReed 	if (dam0 != NULL) {
232f7aef0b0SReed 		rval = mdb_call_dcmd("damap", dam0, DCMD_ADDRSPEC, 0, NULL);
233f7aef0b0SReed 		mdb_printf("\n");
234f7aef0b0SReed 		if (rval != DCMD_OK) {
235f7aef0b0SReed 			return (rval);
236f7aef0b0SReed 		}
237f7aef0b0SReed 	}
238f7aef0b0SReed 
239f7aef0b0SReed 	if (dam1 != NULL) {
240f7aef0b0SReed 		rval = mdb_call_dcmd("damap", dam1, DCMD_ADDRSPEC, 0, NULL);
241f7aef0b0SReed 		mdb_printf("\n");
242f7aef0b0SReed 	}
243f7aef0b0SReed 
244f7aef0b0SReed 	return (rval);
245f7aef0b0SReed }
246f7aef0b0SReed 
247f7aef0b0SReed /* ARGSUSED */
248f7aef0b0SReed static int
249f7aef0b0SReed display_iport_di_cb(uintptr_t addr, const void *wdata, void *priv)
250f7aef0b0SReed {
251f7aef0b0SReed 	uint_t *idx = (uint_t *)priv;
252f7aef0b0SReed 	struct dev_info dip;
253f7aef0b0SReed 	char devi_name[MAXNAMELEN];
254f7aef0b0SReed 	char devi_addr[MAXNAMELEN];
255f7aef0b0SReed 
256f7aef0b0SReed 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)addr) !=
257f7aef0b0SReed 	    sizeof (struct dev_info)) {
258f7aef0b0SReed 		return (DCMD_ERR);
259f7aef0b0SReed 	}
260f7aef0b0SReed 
261f7aef0b0SReed 	if (mdb_readstr(devi_name, sizeof (devi_name),
262f7aef0b0SReed 	    (uintptr_t)dip.devi_node_name) == -1) {
263f7aef0b0SReed 		devi_name[0] = '?';
264f7aef0b0SReed 		devi_name[1] = '\0';
265f7aef0b0SReed 	}
266f7aef0b0SReed 
267f7aef0b0SReed 	if (mdb_readstr(devi_addr, sizeof (devi_addr),
268f7aef0b0SReed 	    (uintptr_t)dip.devi_addr) == -1) {
269f7aef0b0SReed 		devi_addr[0] = '?';
270f7aef0b0SReed 		devi_addr[1] = '\0';
271f7aef0b0SReed 	}
272f7aef0b0SReed 
273f7aef0b0SReed 	mdb_printf("  %3d: @%-21s%10s@\t%p::devinfo -s\n",
274f7aef0b0SReed 	    (*idx)++, devi_addr, devi_name, addr);
275f7aef0b0SReed 	return (DCMD_OK);
276f7aef0b0SReed }
277f7aef0b0SReed 
278f7aef0b0SReed /* ARGSUSED */
279f7aef0b0SReed static int
280f7aef0b0SReed display_iport_pi_cb(uintptr_t addr, const void *wdata, void *priv)
281f7aef0b0SReed {
282f7aef0b0SReed 	uint_t *idx = (uint_t *)priv;
283f7aef0b0SReed 	struct mdi_pathinfo mpi;
284f7aef0b0SReed 	char pi_addr[MAXNAMELEN];
285f7aef0b0SReed 
286f7aef0b0SReed 	if (mdb_vread(&mpi, sizeof (struct mdi_pathinfo), (uintptr_t)addr) !=
287f7aef0b0SReed 	    sizeof (struct mdi_pathinfo)) {
288f7aef0b0SReed 		return (DCMD_ERR);
289f7aef0b0SReed 	}
290f7aef0b0SReed 
291f7aef0b0SReed 	if (mdb_readstr(pi_addr, sizeof (pi_addr),
292f7aef0b0SReed 	    (uintptr_t)mpi.pi_addr) == -1) {
293f7aef0b0SReed 		pi_addr[0] = '?';
294f7aef0b0SReed 		pi_addr[1] = '\0';
295f7aef0b0SReed 	}
296f7aef0b0SReed 
297f7aef0b0SReed 	mdb_printf("  %3d: @%-21s %p::print struct mdi_pathinfo\n",
298f7aef0b0SReed 	    (*idx)++, pi_addr, addr);
299f7aef0b0SReed 	return (DCMD_OK);
300f7aef0b0SReed }
301f7aef0b0SReed 
302f7aef0b0SReed static int
303f7aef0b0SReed display_iport_dtc(dev_info_t *pdip)
304f7aef0b0SReed {
305f7aef0b0SReed 	int rval = DCMD_ERR;
306f7aef0b0SReed 	struct dev_info dip;
307f7aef0b0SReed 	struct mdi_phci phci;
308f7aef0b0SReed 	uint_t didx = 1;
309f7aef0b0SReed 	uint_t pidx = 1;
310f7aef0b0SReed 
311f7aef0b0SReed 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
312f7aef0b0SReed 	    sizeof (struct dev_info)) {
313f7aef0b0SReed 		return (rval);
314f7aef0b0SReed 	}
315f7aef0b0SReed 
316f7aef0b0SReed 	mdb_printf("Device tree children - dev_info:\n");
317f7aef0b0SReed 	if (dip.devi_child == NULL) {
318f7aef0b0SReed 		mdb_printf("\tdevi_child is NULL, no dev_info\n\n");
319f7aef0b0SReed 		goto skip_di;
320f7aef0b0SReed 	}
321f7aef0b0SReed 
322f7aef0b0SReed 	/*
323f7aef0b0SReed 	 * First, we dump the iport's children dev_info node information.
324f7aef0b0SReed 	 * use existing walker: devinfo_siblings
325f7aef0b0SReed 	 */
326f7aef0b0SReed 	mdb_printf("\t#: @unit-address               name@\tdrill-down\n");
327f7aef0b0SReed 	rval = mdb_pwalk("devinfo_siblings", display_iport_di_cb,
328f7aef0b0SReed 	    (void *)&didx, (uintptr_t)dip.devi_child);
329f7aef0b0SReed 	mdb_printf("\n");
330f7aef0b0SReed 
331f7aef0b0SReed skip_di:
332f7aef0b0SReed 	/*
333f7aef0b0SReed 	 * Then we try to dump the iport's path_info node information.
334f7aef0b0SReed 	 * use existing walker: mdipi_phci_list
335f7aef0b0SReed 	 */
336f7aef0b0SReed 	mdb_printf("Device tree children - path_info:\n");
337f7aef0b0SReed 	if (mdb_vread(&phci, sizeof (struct mdi_phci),
338f7aef0b0SReed 	    (uintptr_t)dip.devi_mdi_xhci) != sizeof (struct mdi_phci)) {
339f7aef0b0SReed 		mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n");
340f7aef0b0SReed 		return (rval);
341f7aef0b0SReed 	}
342f7aef0b0SReed 
343f7aef0b0SReed 	if (phci.ph_path_head == NULL) {
344f7aef0b0SReed 		mdb_printf("\tph_path_head is NULL, no path_info\n\n");
345f7aef0b0SReed 		return (rval);
346f7aef0b0SReed 	}
347f7aef0b0SReed 
348f7aef0b0SReed 	mdb_printf("\t#: @unit-address          drill-down\n");
349f7aef0b0SReed 	rval = mdb_pwalk("mdipi_phci_list", display_iport_pi_cb,
350f7aef0b0SReed 	    (void *)&pidx, (uintptr_t)phci.ph_path_head);
351f7aef0b0SReed 	mdb_printf("\n");
352f7aef0b0SReed 	return (rval);
353f7aef0b0SReed }
354f7aef0b0SReed 
355f7aef0b0SReed static void
356f7aef0b0SReed display_iport_more(dev_info_t *dip, per_iport_setting_t *pis)
357f7aef0b0SReed {
358f7aef0b0SReed 	if (pis->pis_damap_info) {
359f7aef0b0SReed 		(void) display_iport_damap(dip);
360f7aef0b0SReed 	}
361f7aef0b0SReed 
362f7aef0b0SReed 	if (pis->pis_dtc_info) {
363f7aef0b0SReed 		(void) display_iport_dtc(dip);
364f7aef0b0SReed 	}
365f7aef0b0SReed }
366f7aef0b0SReed 
3674c06356bSdh142964 /*ARGSUSED*/
3684c06356bSdh142964 static int
3694c06356bSdh142964 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv)
3704c06356bSdh142964 {
3714c06356bSdh142964 	struct pmcs_iport	iport;
3724c06356bSdh142964 	uintptr_t		list_addr;
3734c06356bSdh142964 	char			*ua_state;
3744c06356bSdh142964 	char			portid[4];
3754c06356bSdh142964 	char			unit_address[34];
376f7aef0b0SReed 	per_iport_setting_t	*pis = (per_iport_setting_t *)priv;
3774c06356bSdh142964 
3784c06356bSdh142964 	if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) !=
3794c06356bSdh142964 	    sizeof (struct pmcs_iport)) {
3804c06356bSdh142964 		return (DCMD_ERR);
3814c06356bSdh142964 	}
3824c06356bSdh142964 
3834c06356bSdh142964 	if (mdb_readstr(unit_address, sizeof (unit_address),
3844c06356bSdh142964 	    (uintptr_t)(iport.ua)) == -1) {
3854c06356bSdh142964 		strncpy(unit_address, "Unset", sizeof (unit_address));
3864c06356bSdh142964 	}
3874c06356bSdh142964 
3884c06356bSdh142964 	if (iport.portid == 0xffff) {
3894c06356bSdh142964 		mdb_snprintf(portid, sizeof (portid), "%s", "-");
390601c90f1SSrikanth, Ramana 	} else if (iport.portid == PMCS_IPORT_INVALID_PORT_ID) {
391601c90f1SSrikanth, Ramana 		mdb_snprintf(portid, sizeof (portid), "%s", "N/A");
3924c06356bSdh142964 	} else {
3934c06356bSdh142964 		mdb_snprintf(portid, sizeof (portid), "%d", iport.portid);
3944c06356bSdh142964 	}
3954c06356bSdh142964 
3964c06356bSdh142964 	switch (iport.ua_state) {
3974c06356bSdh142964 	case UA_INACTIVE:
3984c06356bSdh142964 		ua_state = "Inactive";
3994c06356bSdh142964 		break;
4004c06356bSdh142964 	case UA_PEND_ACTIVATE:
4014c06356bSdh142964 		ua_state = "PendActivate";
4024c06356bSdh142964 		break;
4034c06356bSdh142964 	case UA_ACTIVE:
4044c06356bSdh142964 		ua_state = "Active";
4054c06356bSdh142964 		break;
4064c06356bSdh142964 	case UA_PEND_DEACTIVATE:
4074c06356bSdh142964 		ua_state = "PendDeactivate";
4084c06356bSdh142964 		break;
4094c06356bSdh142964 	default:
4104c06356bSdh142964 		ua_state = "Unknown";
4114c06356bSdh142964 	}
4124c06356bSdh142964 
4134c06356bSdh142964 	if (strlen(unit_address) < 3) {
4144c06356bSdh142964 		/* Standard iport unit address */
4154c06356bSdh142964 		mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State",
4164c06356bSdh142964 		    "PortID", "NumPhys", "DIP\n");
4174c06356bSdh142964 		mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr,
4184c06356bSdh142964 		    ua_state, portid, iport.nphy, iport.dip);
4194c06356bSdh142964 	} else {
4204c06356bSdh142964 		/* Temporary iport unit address */
4214c06356bSdh142964 		mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport",
4224c06356bSdh142964 		    "UA State", "PortID", "NumPhys", "DIP\n");
4234c06356bSdh142964 		mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr,
4244c06356bSdh142964 		    ua_state, portid, iport.nphy, iport.dip);
4254c06356bSdh142964 	}
4264c06356bSdh142964 
4274c06356bSdh142964 	if (iport.nphy > 0) {
4284c06356bSdh142964 		mdb_inc_indent(4);
4294c06356bSdh142964 		mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
4304c06356bSdh142964 		mdb_inc_indent(2);
4314c06356bSdh142964 		list_addr =
4324c06356bSdh142964 		    (uintptr_t)(addr + offsetof(struct pmcs_iport, phys));
4334c06356bSdh142964 		if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL,
4344c06356bSdh142964 		    list_addr) == -1) {
4354c06356bSdh142964 			mdb_warn("pmcs iport walk failed");
4364c06356bSdh142964 		}
4374c06356bSdh142964 		mdb_dec_indent(6);
4384c06356bSdh142964 		mdb_printf("\n");
4394c06356bSdh142964 	}
4404c06356bSdh142964 
441f7aef0b0SReed 	/*
442f7aef0b0SReed 	 * See if we need to show more information based on 'd' or 'm' options
443f7aef0b0SReed 	 */
444f7aef0b0SReed 	display_iport_more(iport.dip, pis);
445f7aef0b0SReed 
4464c06356bSdh142964 	return (0);
4474c06356bSdh142964 }
4484c06356bSdh142964 
4494c06356bSdh142964 /*ARGSUSED*/
4504c06356bSdh142964 static void
451f7aef0b0SReed display_iport(struct pmcs_hw m, uintptr_t addr, int verbose,
452f7aef0b0SReed     per_iport_setting_t *pis)
4534c06356bSdh142964 {
4544c06356bSdh142964 	uintptr_t	list_addr;
4554c06356bSdh142964 
4564c06356bSdh142964 	if (m.iports_attached) {
4574c06356bSdh142964 		mdb_printf("Iport information:\n");
4584c06356bSdh142964 		mdb_printf("-----------------\n");
4594c06356bSdh142964 	} else {
4604c06356bSdh142964 		mdb_printf("No Iports found.\n\n");
4614c06356bSdh142964 		return;
4624c06356bSdh142964 	}
4634c06356bSdh142964 
4644c06356bSdh142964 	list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports));
4654c06356bSdh142964 
466f7aef0b0SReed 	if (mdb_pwalk("list", pmcs_iport_walk_cb, pis, list_addr) == -1) {
4674c06356bSdh142964 		mdb_warn("pmcs iport walk failed");
4684c06356bSdh142964 	}
4694c06356bSdh142964 
4704c06356bSdh142964 	mdb_printf("\n");
4714c06356bSdh142964 }
4724c06356bSdh142964 
473c3bc407cSdh142964 /* ARGSUSED */
474c3bc407cSdh142964 static int
475c3bc407cSdh142964 pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv)
476c3bc407cSdh142964 {
477c3bc407cSdh142964 	pmcs_phy_t phy;
478c3bc407cSdh142964 
479c3bc407cSdh142964 	if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) {
480c3bc407cSdh142964 		mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p",
481c3bc407cSdh142964 		    (void *)addr);
482c3bc407cSdh142964 		return (DCMD_ERR);
483c3bc407cSdh142964 	}
484c3bc407cSdh142964 
485c3bc407cSdh142964 	if (phy.configured && (phy.target == NULL)) {
486c3bc407cSdh142964 		mdb_printf("SAS address: ");
487c3bc407cSdh142964 		print_sas_address(&phy);
488c3bc407cSdh142964 		mdb_printf("  DType: ");
489c3bc407cSdh142964 		switch (phy.dtype) {
490c3bc407cSdh142964 		case SAS:
491c3bc407cSdh142964 			mdb_printf("%4s", "SAS");
492c3bc407cSdh142964 			break;
493c3bc407cSdh142964 		case SATA:
494c3bc407cSdh142964 			mdb_printf("%4s", "SATA");
495c3bc407cSdh142964 			break;
496c3bc407cSdh142964 		case EXPANDER:
497c3bc407cSdh142964 			mdb_printf("%4s", "SMP");
498c3bc407cSdh142964 			break;
499c3bc407cSdh142964 		default:
500c3bc407cSdh142964 			mdb_printf("%4s", "N/A");
501c3bc407cSdh142964 			break;
502c3bc407cSdh142964 		}
503c3bc407cSdh142964 		mdb_printf("  Path: %s\n", phy.path);
504c3bc407cSdh142964 	}
505c3bc407cSdh142964 
506c3bc407cSdh142964 	return (0);
507c3bc407cSdh142964 }
508c3bc407cSdh142964 
509c3bc407cSdh142964 static void
510c3bc407cSdh142964 display_unconfigured_targets(uintptr_t addr)
511c3bc407cSdh142964 {
512c3bc407cSdh142964 	mdb_printf("Unconfigured target SAS address:\n\n");
513c3bc407cSdh142964 
514c3bc407cSdh142964 	if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) {
515c3bc407cSdh142964 		mdb_warn("pmcs phys walk failed");
516c3bc407cSdh142964 	}
517c3bc407cSdh142964 }
518c3bc407cSdh142964 
51914d6cf0aSdh142964 static void
52014d6cf0aSdh142964 display_completion_queue(struct pmcs_hw ss)
52114d6cf0aSdh142964 {
52214d6cf0aSdh142964 	pmcs_iocomp_cb_t ccb, *ccbp;
52314d6cf0aSdh142964 	pmcwork_t work;
52414d6cf0aSdh142964 
52514d6cf0aSdh142964 	if (ss.iocomp_cb_head == NULL) {
52614d6cf0aSdh142964 		mdb_printf("Completion queue is empty.\n");
52714d6cf0aSdh142964 		return;
52814d6cf0aSdh142964 	}
52914d6cf0aSdh142964 
53014d6cf0aSdh142964 	ccbp = ss.iocomp_cb_head;
53114d6cf0aSdh142964 	mdb_printf("%8s %10s %20s %8s %8s O D\n",
53214d6cf0aSdh142964 	    "HTag", "State", "Phy Path", "Target", "Timer");
53314d6cf0aSdh142964 
53414d6cf0aSdh142964 	while (ccbp) {
53514d6cf0aSdh142964 		if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t),
53614d6cf0aSdh142964 		    (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) {
53714d6cf0aSdh142964 			mdb_warn("Unable to read completion queue entry\n");
53814d6cf0aSdh142964 			return;
53914d6cf0aSdh142964 		}
54014d6cf0aSdh142964 
54114d6cf0aSdh142964 		if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk)
54214d6cf0aSdh142964 		    != sizeof (pmcwork_t)) {
54314d6cf0aSdh142964 			mdb_warn("Unable to read work structure\n");
54414d6cf0aSdh142964 			return;
54514d6cf0aSdh142964 		}
54614d6cf0aSdh142964 
54714d6cf0aSdh142964 		/*
54814d6cf0aSdh142964 		 * Only print the work structure if it's still active.  If
54914d6cf0aSdh142964 		 * it's not, it's been completed since we started looking at
55014d6cf0aSdh142964 		 * it.
55114d6cf0aSdh142964 		 */
55214d6cf0aSdh142964 		if (work.state != PMCS_WORK_STATE_NIL) {
55314d6cf0aSdh142964 			display_one_work(&work, 0, 0);
55414d6cf0aSdh142964 		}
55514d6cf0aSdh142964 		ccbp = ccb.next;
55614d6cf0aSdh142964 	}
55714d6cf0aSdh142964 }
55814d6cf0aSdh142964 
5591f81b464SDavid Hollister static void
5601f81b464SDavid Hollister display_event_log(struct pmcs_hw ss)
5611f81b464SDavid Hollister {
5621f81b464SDavid Hollister 	pmcs_fw_event_hdr_t fwhdr;
5631f81b464SDavid Hollister 	char *header_id, *entry, *fwlogp;
5641f81b464SDavid Hollister 	uint32_t total_size = PMCS_FWLOG_SIZE, log_size, index, *swapp, sidx;
5651f81b464SDavid Hollister 	pmcs_fw_event_entry_t *fw_entryp;
5661f81b464SDavid Hollister 	struct timespec systime;
5671f81b464SDavid Hollister 
5681f81b464SDavid Hollister 	if (ss.fwlogp == NULL) {
5691f81b464SDavid Hollister 		mdb_printf("There is no firmware event log.\n");
5701f81b464SDavid Hollister 		return;
5711f81b464SDavid Hollister 	}
5721f81b464SDavid Hollister 
5731f81b464SDavid Hollister 	fwlogp = (char *)ss.fwlogp;
5741f81b464SDavid Hollister 
5751f81b464SDavid Hollister 	while (total_size != 0) {
5761f81b464SDavid Hollister 		if (mdb_vread(&fwhdr, sizeof (pmcs_fw_event_hdr_t),
5771f81b464SDavid Hollister 		    (uintptr_t)fwlogp) != sizeof (pmcs_fw_event_hdr_t)) {
5781f81b464SDavid Hollister 			mdb_warn("Unable to read firmware event log header\n");
5791f81b464SDavid Hollister 			return;
5801f81b464SDavid Hollister 		}
5811f81b464SDavid Hollister 
5821f81b464SDavid Hollister 		/*
5831f81b464SDavid Hollister 		 * Firmware event log is little-endian
5841f81b464SDavid Hollister 		 */
5851f81b464SDavid Hollister 		swapp = (uint32_t *)&fwhdr;
5861f81b464SDavid Hollister 		for (sidx = 0; sidx < (sizeof (pmcs_fw_event_hdr_t) /
5871f81b464SDavid Hollister 		    sizeof (uint32_t)); sidx++) {
5881f81b464SDavid Hollister 			*swapp = LE_32(*swapp);
5891f81b464SDavid Hollister 			swapp++;
5901f81b464SDavid Hollister 		}
5911f81b464SDavid Hollister 
5921f81b464SDavid Hollister 		if (fwhdr.fw_el_signature == PMCS_FWLOG_AAP1_SIG) {
5931f81b464SDavid Hollister 			header_id = "AAP1";
5941f81b464SDavid Hollister 		} else if (fwhdr.fw_el_signature == PMCS_FWLOG_IOP_SIG) {
5951f81b464SDavid Hollister 			header_id = "IOP";
5961f81b464SDavid Hollister 		} else {
5971f81b464SDavid Hollister 			mdb_warn("Invalid firmware event log signature\n");
5981f81b464SDavid Hollister 			return;
5991f81b464SDavid Hollister 		}
6001f81b464SDavid Hollister 
6011f81b464SDavid Hollister 		mdb_printf("Event Log:    %s\n", header_id);
6021f81b464SDavid Hollister 		mdb_printf("Oldest entry: %d\n", fwhdr.fw_el_oldest_idx);
6031f81b464SDavid Hollister 		mdb_printf("Latest entry: %d\n", fwhdr.fw_el_latest_idx);
6041f81b464SDavid Hollister 
6051f81b464SDavid Hollister 		entry = mdb_alloc(fwhdr.fw_el_entry_size, UM_SLEEP);
6061f81b464SDavid Hollister 		fw_entryp = (pmcs_fw_event_entry_t *)((void *)entry);
6071f81b464SDavid Hollister 		total_size -= sizeof (pmcs_fw_event_hdr_t);
6081f81b464SDavid Hollister 		log_size = fwhdr.fw_el_buf_size;
6091f81b464SDavid Hollister 		fwlogp += fwhdr.fw_el_entry_start_offset;
6101f81b464SDavid Hollister 		swapp = (uint32_t *)((void *)entry);
6111f81b464SDavid Hollister 		index = 0;
6121f81b464SDavid Hollister 
6131f81b464SDavid Hollister 		mdb_printf("%8s %16s %32s %8s %3s %8s %8s %8s %8s",
6141f81b464SDavid Hollister 		    "Index", "Timestamp", "Time", "Seq Num", "Sev", "Word 0",
6151f81b464SDavid Hollister 		    "Word 1", "Word 2", "Word 3");
6161f81b464SDavid Hollister 		mdb_printf("\n");
6171f81b464SDavid Hollister 
6181f81b464SDavid Hollister 		while (log_size != 0) {
6191f81b464SDavid Hollister 			if (mdb_vread(entry, fwhdr.fw_el_entry_size,
6201f81b464SDavid Hollister 			    (uintptr_t)fwlogp) != fwhdr.fw_el_entry_size) {
6211f81b464SDavid Hollister 				mdb_warn("Unable to read event log entry\n");
6221f81b464SDavid Hollister 				goto bail_out;
6231f81b464SDavid Hollister 			}
6241f81b464SDavid Hollister 
6251f81b464SDavid Hollister 			for (sidx = 0; sidx < (fwhdr.fw_el_entry_size /
6261f81b464SDavid Hollister 			    sizeof (uint32_t)); sidx++) {
6271f81b464SDavid Hollister 				*(swapp + sidx) = LE_32(*(swapp + sidx));
6281f81b464SDavid Hollister 			}
6291f81b464SDavid Hollister 
6301f81b464SDavid Hollister 			if (fw_entryp->ts_upper || fw_entryp->ts_lower) {
6311f81b464SDavid Hollister 				pmcs_fwtime_to_systime(ss, fw_entryp->ts_upper,
6321f81b464SDavid Hollister 				    fw_entryp->ts_lower, &systime);
6331f81b464SDavid Hollister 				mdb_printf("%8d %08x%08x [%Y.%09ld] %8d %3d "
6341f81b464SDavid Hollister 				    "%08x %08x %08x %08x\n", index,
6351f81b464SDavid Hollister 				    fw_entryp->ts_upper, fw_entryp->ts_lower,
6361f81b464SDavid Hollister 				    systime, fw_entryp->seq_num,
6371f81b464SDavid Hollister 				    fw_entryp->severity, fw_entryp->logw0,
6381f81b464SDavid Hollister 				    fw_entryp->logw1, fw_entryp->logw2,
6391f81b464SDavid Hollister 				    fw_entryp->logw3);
6401f81b464SDavid Hollister 			}
6411f81b464SDavid Hollister 
6421f81b464SDavid Hollister 			fwlogp += fwhdr.fw_el_entry_size;
6431f81b464SDavid Hollister 			total_size -= fwhdr.fw_el_entry_size;
6441f81b464SDavid Hollister 			log_size -= fwhdr.fw_el_entry_size;
6451f81b464SDavid Hollister 			index++;
6461f81b464SDavid Hollister 		}
6471f81b464SDavid Hollister 
6481f81b464SDavid Hollister 		mdb_printf("\n");
6491f81b464SDavid Hollister 	}
6501f81b464SDavid Hollister 
6511f81b464SDavid Hollister bail_out:
6521f81b464SDavid Hollister 	mdb_free(entry, fwhdr.fw_el_entry_size);
6531f81b464SDavid Hollister }
6541f81b464SDavid Hollister 
6554c06356bSdh142964 /*ARGSUSED*/
6564c06356bSdh142964 static void
6574c06356bSdh142964 display_hwinfo(struct pmcs_hw m, int verbose)
6584c06356bSdh142964 {
6594c06356bSdh142964 	struct pmcs_hw	*mp = &m;
6604c06356bSdh142964 	char		*fwsupport;
6614c06356bSdh142964 
6624c06356bSdh142964 	switch (PMCS_FW_TYPE(mp)) {
6634c06356bSdh142964 	case PMCS_FW_TYPE_RELEASED:
6644c06356bSdh142964 		fwsupport = "Released";
6654c06356bSdh142964 		break;
6664c06356bSdh142964 	case PMCS_FW_TYPE_DEVELOPMENT:
6674c06356bSdh142964 		fwsupport = "Development";
6684c06356bSdh142964 		break;
6694c06356bSdh142964 	case PMCS_FW_TYPE_ALPHA:
6704c06356bSdh142964 		fwsupport = "Alpha";
6714c06356bSdh142964 		break;
6724c06356bSdh142964 	case PMCS_FW_TYPE_BETA:
6734c06356bSdh142964 		fwsupport = "Beta";
6744c06356bSdh142964 		break;
6754c06356bSdh142964 	default:
6764c06356bSdh142964 		fwsupport = "Special";
6774c06356bSdh142964 		break;
6784c06356bSdh142964 	}
6794c06356bSdh142964 
6804c06356bSdh142964 	mdb_printf("\nHardware information:\n");
6814c06356bSdh142964 	mdb_printf("---------------------\n");
6824c06356bSdh142964 
6834c06356bSdh142964 	mdb_printf("Chip revision:    %c\n", 'A' + m.chiprev);
6844c06356bSdh142964 	mdb_printf("SAS WWID:         %"PRIx64"\n", m.sas_wwns[0]);
6854c06356bSdh142964 	mdb_printf("Firmware version: %x.%x.%x (%s)\n",
6864c06356bSdh142964 	    PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp),
6874c06356bSdh142964 	    fwsupport);
6882ac4abe8SDavid Hollister 	mdb_printf("ILA version:      %08x\n", m.ila_ver);
6892ac4abe8SDavid Hollister 	mdb_printf("Active f/w img:   %c\n", (m.fw_active_img) ? 'A' : 'B');
6904c06356bSdh142964 
6914c06356bSdh142964 	mdb_printf("Number of PHYs:   %d\n", m.nphy);
6924c06356bSdh142964 	mdb_printf("Maximum commands: %d\n", m.max_cmd);
6934c06356bSdh142964 	mdb_printf("Maximum devices:  %d\n", m.max_dev);
6944c06356bSdh142964 	mdb_printf("I/O queue depth:  %d\n", m.ioq_depth);
695658280b6SDavid Hollister 	mdb_printf("Open retry intvl: %d usecs\n", m.open_retry_interval);
6964c06356bSdh142964 	if (m.fwlog == 0) {
6974c06356bSdh142964 		mdb_printf("Firmware logging: Disabled\n");
6984c06356bSdh142964 	} else {
6994c06356bSdh142964 		mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog);
7004c06356bSdh142964 	}
7012ac4abe8SDavid Hollister 	if (m.fwlog_file == 0) {
7022ac4abe8SDavid Hollister 		mdb_printf("Firmware logfile: Not configured\n");
7032ac4abe8SDavid Hollister 	} else {
7042ac4abe8SDavid Hollister 		mdb_printf("Firmware logfile: Configured\n");
7052ac4abe8SDavid Hollister 		mdb_inc_indent(2);
7062ac4abe8SDavid Hollister 		mdb_printf("AAP1 log file:  %s\n", m.fwlogfile_aap1);
7072ac4abe8SDavid Hollister 		mdb_printf("IOP logfile:    %s\n", m.fwlogfile_iop);
7082ac4abe8SDavid Hollister 		mdb_dec_indent(2);
7092ac4abe8SDavid Hollister 	}
7104c06356bSdh142964 }
7114c06356bSdh142964 
7124c06356bSdh142964 static void
7134c06356bSdh142964 display_targets(struct pmcs_hw m, int verbose, int totals_only)
7144c06356bSdh142964 {
7154c06356bSdh142964 	char		*dtype;
7164c06356bSdh142964 	pmcs_xscsi_t	xs;
7174c06356bSdh142964 	pmcs_phy_t	phy;
7184c06356bSdh142964 	uint16_t	max_dev, idx;
7194c06356bSdh142964 	uint32_t	sas_targets = 0, smp_targets = 0, sata_targets = 0;
7204c06356bSdh142964 
7214c06356bSdh142964 	max_dev = m.max_dev;
7224c06356bSdh142964 
7234c06356bSdh142964 	if (targets == NULL) {
7244c06356bSdh142964 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
7254c06356bSdh142964 	}
7264c06356bSdh142964 
7274c06356bSdh142964 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
7284c06356bSdh142964 		NOREAD(targets, m.targets);
7294c06356bSdh142964 		return;
7304c06356bSdh142964 	}
7314c06356bSdh142964 
7324c06356bSdh142964 	if (!totals_only) {
7334c06356bSdh142964 		mdb_printf("\nTarget information:\n");
7344c06356bSdh142964 		mdb_printf("---------------------------------------\n");
735601c90f1SSrikanth, Ramana 		mdb_printf("VTGT %-16s %-16s %-5s %4s %6s %s", "SAS Address",
736601c90f1SSrikanth, Ramana 		    "PHY Address", "DType", "Actv", "OnChip", "DS");
7374c06356bSdh142964 		mdb_printf("\n");
7384c06356bSdh142964 	}
7394c06356bSdh142964 
7404c06356bSdh142964 	for (idx = 0; idx < max_dev; idx++) {
7414c06356bSdh142964 		if (targets[idx] == NULL) {
7424c06356bSdh142964 			continue;
7434c06356bSdh142964 		}
7444c06356bSdh142964 
7454c06356bSdh142964 		if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) {
7464c06356bSdh142964 			NOREAD(pmcs_xscsi_t, targets[idx]);
7474c06356bSdh142964 			continue;
7484c06356bSdh142964 		}
7494c06356bSdh142964 
7504c06356bSdh142964 		/*
751b18a19c2SJesse Butler 		 * It has to be new or assigned to be of interest.
7524c06356bSdh142964 		 */
753b18a19c2SJesse Butler 		if (xs.new == 0 && xs.assigned == 0) {
7544c06356bSdh142964 			continue;
7554c06356bSdh142964 		}
7564c06356bSdh142964 
7574c06356bSdh142964 		switch (xs.dtype) {
7584c06356bSdh142964 		case NOTHING:
7594c06356bSdh142964 			dtype = "None";
7604c06356bSdh142964 			break;
7614c06356bSdh142964 		case SATA:
7624c06356bSdh142964 			dtype = "SATA";
7634c06356bSdh142964 			sata_targets++;
7644c06356bSdh142964 			break;
7654c06356bSdh142964 		case SAS:
7664c06356bSdh142964 			dtype = "SAS";
7674c06356bSdh142964 			sas_targets++;
7684c06356bSdh142964 			break;
7694c06356bSdh142964 		case EXPANDER:
7704c06356bSdh142964 			dtype = "SMP";
7714c06356bSdh142964 			smp_targets++;
7724c06356bSdh142964 			break;
7734c06356bSdh142964 		}
7744c06356bSdh142964 
7754c06356bSdh142964 		if (totals_only) {
7764c06356bSdh142964 			continue;
7774c06356bSdh142964 		}
7784c06356bSdh142964 
7794c06356bSdh142964 		if (xs.phy) {
7804c06356bSdh142964 			if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) {
7814c06356bSdh142964 				NOREAD(pmcs_phy_t, xs.phy);
7824c06356bSdh142964 				continue;
7834c06356bSdh142964 			}
7844c06356bSdh142964 			mdb_printf("%4d ", idx);
7854c06356bSdh142964 			print_sas_address(&phy);
7864c06356bSdh142964 			mdb_printf(" %16p", xs.phy);
7874c06356bSdh142964 		} else {
7884c06356bSdh142964 			mdb_printf("%4d %16s", idx, "<no phy avail>");
7894c06356bSdh142964 		}
7904c06356bSdh142964 		mdb_printf(" %5s", dtype);
791601c90f1SSrikanth, Ramana 		mdb_printf(" %4d", xs.actv_pkts);
792601c90f1SSrikanth, Ramana 		mdb_printf(" %6d", xs.actv_cnt);
7934c06356bSdh142964 		mdb_printf(" %2d", xs.dev_state);
7944c06356bSdh142964 
7954c06356bSdh142964 		if (verbose) {
7964c06356bSdh142964 			if (xs.new) {
7974c06356bSdh142964 				mdb_printf(" new");
798b18a19c2SJesse Butler 			}
799b18a19c2SJesse Butler 			if (xs.assigned) {
8004c06356bSdh142964 				mdb_printf(" assigned");
8014c06356bSdh142964 			}
8024c06356bSdh142964 			if (xs.draining) {
8034c06356bSdh142964 				mdb_printf(" draining");
8044c06356bSdh142964 			}
8054c06356bSdh142964 			if (xs.reset_wait) {
8064c06356bSdh142964 				mdb_printf(" reset_wait");
8074c06356bSdh142964 			}
8084c06356bSdh142964 			if (xs.resetting) {
8094c06356bSdh142964 				mdb_printf(" resetting");
8104c06356bSdh142964 			}
8114c06356bSdh142964 			if (xs.recover_wait) {
8124c06356bSdh142964 				mdb_printf(" recover_wait");
8134c06356bSdh142964 			}
8144c06356bSdh142964 			if (xs.recovering) {
8154c06356bSdh142964 				mdb_printf(" recovering");
8164c06356bSdh142964 			}
8174c06356bSdh142964 			if (xs.event_recovery) {
8184c06356bSdh142964 				mdb_printf(" event recovery");
8194c06356bSdh142964 			}
8204c06356bSdh142964 			if (xs.special_running) {
8214c06356bSdh142964 				mdb_printf(" special_active");
8224c06356bSdh142964 			}
8234c06356bSdh142964 			if (xs.ncq) {
8244c06356bSdh142964 				mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
8254c06356bSdh142964 				    xs.tagmap, xs.qdepth);
8264c06356bSdh142964 			} else if (xs.pio) {
8274c06356bSdh142964 				mdb_printf(" pio");
8284c06356bSdh142964 			}
8294c06356bSdh142964 		}
8304c06356bSdh142964 
8314c06356bSdh142964 		mdb_printf("\n");
8324c06356bSdh142964 	}
8334c06356bSdh142964 
8344c06356bSdh142964 	if (!totals_only) {
8354c06356bSdh142964 		mdb_printf("\n");
8364c06356bSdh142964 	}
8374c06356bSdh142964 
8384c06356bSdh142964 	mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
8394c06356bSdh142964 	    "Configured targets:", (sas_targets + sata_targets + smp_targets),
8404c06356bSdh142964 	    sas_targets, sata_targets, smp_targets);
8414c06356bSdh142964 }
8424c06356bSdh142964 
84314d6cf0aSdh142964 static char *
84414d6cf0aSdh142964 work_state_to_string(uint32_t state)
8454c06356bSdh142964 {
84614d6cf0aSdh142964 	char *state_string;
8474c06356bSdh142964 
84814d6cf0aSdh142964 	switch (state) {
8494c06356bSdh142964 	case PMCS_WORK_STATE_NIL:
85014d6cf0aSdh142964 		state_string = "Free";
8514c06356bSdh142964 		break;
8524c06356bSdh142964 	case PMCS_WORK_STATE_READY:
85314d6cf0aSdh142964 		state_string = "Ready";
8544c06356bSdh142964 		break;
8554c06356bSdh142964 	case PMCS_WORK_STATE_ONCHIP:
85614d6cf0aSdh142964 		state_string = "On Chip";
8574c06356bSdh142964 		break;
8584c06356bSdh142964 	case PMCS_WORK_STATE_INTR:
85914d6cf0aSdh142964 		state_string = "In Intr";
8604c06356bSdh142964 		break;
8614c06356bSdh142964 	case PMCS_WORK_STATE_IOCOMPQ:
86214d6cf0aSdh142964 		state_string = "I/O Comp";
8634c06356bSdh142964 		break;
8644c06356bSdh142964 	case PMCS_WORK_STATE_ABORTED:
86514d6cf0aSdh142964 		state_string = "I/O Aborted";
8664c06356bSdh142964 		break;
8674c06356bSdh142964 	case PMCS_WORK_STATE_TIMED_OUT:
86814d6cf0aSdh142964 		state_string = "I/O Timed Out";
8694c06356bSdh142964 		break;
8704c06356bSdh142964 	default:
87114d6cf0aSdh142964 		state_string = "INVALID";
8724c06356bSdh142964 		break;
8734c06356bSdh142964 	}
87414d6cf0aSdh142964 
87514d6cf0aSdh142964 	return (state_string);
87614d6cf0aSdh142964 }
87714d6cf0aSdh142964 
87814d6cf0aSdh142964 static void
87914d6cf0aSdh142964 display_one_work(pmcwork_t *wp, int verbose, int idx)
88014d6cf0aSdh142964 {
88114d6cf0aSdh142964 	char		*state, *last_state;
88214d6cf0aSdh142964 	char		*path;
88314d6cf0aSdh142964 	pmcs_xscsi_t	xs;
88414d6cf0aSdh142964 	pmcs_phy_t	phy;
88514d6cf0aSdh142964 	int		tgt;
88614d6cf0aSdh142964 
88714d6cf0aSdh142964 	state = work_state_to_string(wp->state);
88814d6cf0aSdh142964 	last_state = work_state_to_string(wp->last_state);
88914d6cf0aSdh142964 
8904c06356bSdh142964 	if (wp->ssp_event && wp->ssp_event != 0xffffffff) {
8914c06356bSdh142964 		mdb_printf("SSP event 0x%x", wp->ssp_event);
8924c06356bSdh142964 	}
89314d6cf0aSdh142964 
8944c06356bSdh142964 	tgt = -1;
8954c06356bSdh142964 	if (wp->xp) {
8964c06356bSdh142964 		if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) {
8974c06356bSdh142964 			NOREAD(pmcs_xscsi_t, wp->xp);
8984c06356bSdh142964 		} else {
8994c06356bSdh142964 			tgt = xs.target_num;
9004c06356bSdh142964 		}
9014c06356bSdh142964 	}
9024c06356bSdh142964 	if (wp->phy) {
9034c06356bSdh142964 		if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) {
9044c06356bSdh142964 			NOREAD(pmcs_phy_t, wp->phy);
9054c06356bSdh142964 		}
9064c06356bSdh142964 		path = phy.path;
9074c06356bSdh142964 	} else {
90814d6cf0aSdh142964 		path = "N/A";
9094c06356bSdh142964 	}
91014d6cf0aSdh142964 
91114d6cf0aSdh142964 	if (verbose) {
91214d6cf0aSdh142964 		mdb_printf("%4d ", idx);
91314d6cf0aSdh142964 	}
91414d6cf0aSdh142964 	if (tgt == -1) {
91514d6cf0aSdh142964 		mdb_printf("%08x %10s %20s      N/A %8u %1d %1d ",
91614d6cf0aSdh142964 		    wp->htag, state, path, wp->timer,
91714d6cf0aSdh142964 		    wp->onwire, wp->dead);
91814d6cf0aSdh142964 	} else {
91914d6cf0aSdh142964 		mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
9204c06356bSdh142964 		    wp->htag, state, path, tgt, wp->timer,
9214c06356bSdh142964 		    wp->onwire, wp->dead);
9224c06356bSdh142964 	}
92314d6cf0aSdh142964 	if (verbose) {
9249aed1621SDavid Hollister 		mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n",
9259aed1621SDavid Hollister 		    wp->last_htag, last_state, wp->last_phy, wp->last_xp,
9269aed1621SDavid Hollister 		    wp->last_arg);
92714d6cf0aSdh142964 	} else {
92814d6cf0aSdh142964 		mdb_printf("\n");
92914d6cf0aSdh142964 	}
9304c06356bSdh142964 }
9314c06356bSdh142964 
9324c06356bSdh142964 static void
933658280b6SDavid Hollister display_work(struct pmcs_hw m, int verbose, int wserno)
9344c06356bSdh142964 {
93514d6cf0aSdh142964 	int		idx;
93614d6cf0aSdh142964 	boolean_t	header_printed = B_FALSE;
937658280b6SDavid Hollister 	pmcwork_t	*wp;
938658280b6SDavid Hollister 	wserno_list_t	*sernop, *sp, *newsp, *sphead = NULL;
93914d6cf0aSdh142964 	uintptr_t	_wp;
940658280b6SDavid Hollister 	int		serno;
941658280b6SDavid Hollister 
942658280b6SDavid Hollister 	wp = mdb_alloc(sizeof (pmcwork_t) * m.max_cmd, UM_SLEEP);
943658280b6SDavid Hollister 	_wp = (uintptr_t)m.work;
944658280b6SDavid Hollister 	sernop = mdb_alloc(sizeof (wserno_list_t) * m.max_cmd, UM_SLEEP);
945658280b6SDavid Hollister 	bzero(sernop, sizeof (wserno_list_t) * m.max_cmd);
94614d6cf0aSdh142964 
94714d6cf0aSdh142964 	mdb_printf("\nActive Work structure information:\n");
94814d6cf0aSdh142964 	mdb_printf("----------------------------------\n");
94914d6cf0aSdh142964 
950658280b6SDavid Hollister 	/*
951658280b6SDavid Hollister 	 * Read in all the work structures
952658280b6SDavid Hollister 	 */
95314d6cf0aSdh142964 	for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
954658280b6SDavid Hollister 		if (MDB_RD(wp + idx, sizeof (pmcwork_t), _wp) == -1) {
95514d6cf0aSdh142964 			NOREAD(pmcwork_t, _wp);
95614d6cf0aSdh142964 			continue;
9574c06356bSdh142964 		}
958658280b6SDavid Hollister 	}
95914d6cf0aSdh142964 
960658280b6SDavid Hollister 	/*
961658280b6SDavid Hollister 	 * Sort by serial number?
962658280b6SDavid Hollister 	 */
963658280b6SDavid Hollister 	if (wserno) {
964658280b6SDavid Hollister 		for (idx = 0; idx < m.max_cmd; idx++) {
965658280b6SDavid Hollister 			if ((wp + idx)->htag == 0) {
966658280b6SDavid Hollister 				serno = PMCS_TAG_SERNO((wp + idx)->last_htag);
967658280b6SDavid Hollister 			} else {
968658280b6SDavid Hollister 				serno = PMCS_TAG_SERNO((wp + idx)->htag);
969658280b6SDavid Hollister 			}
970658280b6SDavid Hollister 
971658280b6SDavid Hollister 			/* Start at the beginning of the list */
972658280b6SDavid Hollister 			sp = sphead;
973658280b6SDavid Hollister 			newsp = sernop + idx;
974658280b6SDavid Hollister 			/* If this is the first entry, just add it */
975658280b6SDavid Hollister 			if (sphead == NULL) {
976658280b6SDavid Hollister 				sphead = sernop;
977658280b6SDavid Hollister 				sphead->serno = serno;
978658280b6SDavid Hollister 				sphead->idx = idx;
979658280b6SDavid Hollister 				sphead->next = NULL;
980658280b6SDavid Hollister 				sphead->prev = NULL;
981658280b6SDavid Hollister 				continue;
982658280b6SDavid Hollister 			}
983658280b6SDavid Hollister 
984658280b6SDavid Hollister 			newsp->serno = serno;
985658280b6SDavid Hollister 			newsp->idx = idx;
986658280b6SDavid Hollister 
987658280b6SDavid Hollister 			/* Find out where in the list this goes */
988658280b6SDavid Hollister 			while (sp) {
989658280b6SDavid Hollister 				/* This item goes before sp */
990658280b6SDavid Hollister 				if (serno < sp->serno) {
991658280b6SDavid Hollister 					newsp->next = sp;
992658280b6SDavid Hollister 					newsp->prev = sp->prev;
993658280b6SDavid Hollister 					if (newsp->prev == NULL) {
994658280b6SDavid Hollister 						sphead = newsp;
995658280b6SDavid Hollister 					} else {
996658280b6SDavid Hollister 						newsp->prev->next = newsp;
997658280b6SDavid Hollister 					}
998658280b6SDavid Hollister 					sp->prev = newsp;
999658280b6SDavid Hollister 					break;
1000658280b6SDavid Hollister 				}
1001658280b6SDavid Hollister 
1002658280b6SDavid Hollister 				/*
1003658280b6SDavid Hollister 				 * If sp->next is NULL, this entry goes at the
1004658280b6SDavid Hollister 				 * end of the list
1005658280b6SDavid Hollister 				 */
1006658280b6SDavid Hollister 				if (sp->next == NULL) {
1007658280b6SDavid Hollister 					sp->next = newsp;
1008658280b6SDavid Hollister 					newsp->next = NULL;
1009658280b6SDavid Hollister 					newsp->prev = sp;
1010658280b6SDavid Hollister 					break;
1011658280b6SDavid Hollister 				}
1012658280b6SDavid Hollister 
1013658280b6SDavid Hollister 				sp = sp->next;
1014658280b6SDavid Hollister 			}
1015658280b6SDavid Hollister 		}
1016658280b6SDavid Hollister 
1017658280b6SDavid Hollister 		/*
1018658280b6SDavid Hollister 		 * Now print the sorted list
1019658280b6SDavid Hollister 		 */
1020658280b6SDavid Hollister 		mdb_printf(" Idx %8s %10s %20s %8s %8s O D ",
1021658280b6SDavid Hollister 		    "HTag", "State", "Phy Path", "Target", "Timer");
1022658280b6SDavid Hollister 		mdb_printf("%8s %10s %18s %18s %18s\n", "LastHTAG",
1023658280b6SDavid Hollister 		    "LastState", "LastPHY", "LastTgt", "LastArg");
1024658280b6SDavid Hollister 
1025658280b6SDavid Hollister 		sp = sphead;
1026658280b6SDavid Hollister 		while (sp) {
1027658280b6SDavid Hollister 			display_one_work(wp + sp->idx, 1, sp->idx);
1028658280b6SDavid Hollister 			sp = sp->next;
1029658280b6SDavid Hollister 		}
1030658280b6SDavid Hollister 
1031658280b6SDavid Hollister 		goto out;
1032658280b6SDavid Hollister 	}
1033658280b6SDavid Hollister 
1034658280b6SDavid Hollister 	/*
1035658280b6SDavid Hollister 	 * Now print the list, sorted by index
1036658280b6SDavid Hollister 	 */
1037658280b6SDavid Hollister 	for (idx = 0; idx < m.max_cmd; idx++) {
1038658280b6SDavid Hollister 		if (!verbose && ((wp + idx)->htag == PMCS_TAG_TYPE_FREE)) {
103914d6cf0aSdh142964 			continue;
104014d6cf0aSdh142964 		}
104114d6cf0aSdh142964 
104214d6cf0aSdh142964 		if (header_printed == B_FALSE) {
104314d6cf0aSdh142964 			if (verbose) {
104414d6cf0aSdh142964 				mdb_printf("%4s ", "Idx");
104514d6cf0aSdh142964 			}
104614d6cf0aSdh142964 			mdb_printf("%8s %10s %20s %8s %8s O D ",
104714d6cf0aSdh142964 			    "HTag", "State", "Phy Path", "Target", "Timer");
104814d6cf0aSdh142964 			if (verbose) {
10499aed1621SDavid Hollister 				mdb_printf("%8s %10s %18s %18s %18s\n",
10509aed1621SDavid Hollister 				    "LastHTAG", "LastState", "LastPHY",
10519aed1621SDavid Hollister 				    "LastTgt", "LastArg");
105214d6cf0aSdh142964 			} else {
105314d6cf0aSdh142964 				mdb_printf("\n");
105414d6cf0aSdh142964 			}
105514d6cf0aSdh142964 			header_printed = B_TRUE;
105614d6cf0aSdh142964 		}
105714d6cf0aSdh142964 
1058658280b6SDavid Hollister 		display_one_work(wp + idx, verbose, idx);
105914d6cf0aSdh142964 	}
1060658280b6SDavid Hollister 
1061658280b6SDavid Hollister out:
1062658280b6SDavid Hollister 	mdb_free(wp, sizeof (pmcwork_t) * m.max_cmd);
1063658280b6SDavid Hollister 	mdb_free(sernop, sizeof (wserno_list_t) * m.max_cmd);
106414d6cf0aSdh142964 }
106514d6cf0aSdh142964 
106614d6cf0aSdh142964 static void
106714d6cf0aSdh142964 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose)
106814d6cf0aSdh142964 {
106914d6cf0aSdh142964 	int cdb_size, idx;
107014d6cf0aSdh142964 	struct scsi_pkt pkt;
107114d6cf0aSdh142964 	uchar_t cdb[256];
107214d6cf0aSdh142964 
107314d6cf0aSdh142964 	if (printhdr) {
107414d6cf0aSdh142964 		if (verbose) {
107514d6cf0aSdh142964 			mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
107614d6cf0aSdh142964 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
107714d6cf0aSdh142964 		} else {
107814d6cf0aSdh142964 			mdb_printf("%16s %16s %16s %8s %s\n", "Command",
107914d6cf0aSdh142964 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
108014d6cf0aSdh142964 		}
108114d6cf0aSdh142964 	}
108214d6cf0aSdh142964 
108314d6cf0aSdh142964 	mdb_printf("%16p %16p %16p %08x %08x ",
10844c06356bSdh142964 	    kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag);
108514d6cf0aSdh142964 
108614d6cf0aSdh142964 	/*
108714d6cf0aSdh142964 	 * If we're printing verbose, dump the CDB as well.
108814d6cf0aSdh142964 	 */
108914d6cf0aSdh142964 	if (verbose) {
109014d6cf0aSdh142964 		if (sp->cmd_pkt) {
109114d6cf0aSdh142964 			if (mdb_vread(&pkt, sizeof (struct scsi_pkt),
109214d6cf0aSdh142964 			    (uintptr_t)sp->cmd_pkt) !=
109314d6cf0aSdh142964 			    sizeof (struct scsi_pkt)) {
109414d6cf0aSdh142964 				mdb_warn("Unable to read SCSI pkt\n");
109514d6cf0aSdh142964 				return;
109614d6cf0aSdh142964 			}
109714d6cf0aSdh142964 			cdb_size = pkt.pkt_cdblen;
109814d6cf0aSdh142964 			if (mdb_vread(&cdb[0], cdb_size,
109914d6cf0aSdh142964 			    (uintptr_t)pkt.pkt_cdbp) != cdb_size) {
110014d6cf0aSdh142964 				mdb_warn("Unable to read CDB\n");
110114d6cf0aSdh142964 				return;
110214d6cf0aSdh142964 			}
110314d6cf0aSdh142964 
110414d6cf0aSdh142964 			for (idx = 0; idx < cdb_size; idx++) {
110514d6cf0aSdh142964 				mdb_printf("%02x ", cdb[idx]);
110614d6cf0aSdh142964 			}
110714d6cf0aSdh142964 		} else {
110814d6cf0aSdh142964 			mdb_printf("N/A");
110914d6cf0aSdh142964 		}
111014d6cf0aSdh142964 
111114d6cf0aSdh142964 		mdb_printf("\n");
111214d6cf0aSdh142964 	} else {
111314d6cf0aSdh142964 		mdb_printf("\n");
111414d6cf0aSdh142964 	}
11154c06356bSdh142964 }
11164c06356bSdh142964 
11174c06356bSdh142964 /*ARGSUSED1*/
11184c06356bSdh142964 static void
11194c06356bSdh142964 display_waitqs(struct pmcs_hw m, int verbose)
11204c06356bSdh142964 {
11214c06356bSdh142964 	pmcs_cmd_t	*sp, s;
11224c06356bSdh142964 	pmcs_xscsi_t	xs;
11234c06356bSdh142964 	int		first, i;
11244c06356bSdh142964 	int		max_dev = m.max_dev;
11254c06356bSdh142964 
11264c06356bSdh142964 	sp = m.dq.stqh_first;
11274c06356bSdh142964 	first = 1;
11284c06356bSdh142964 	while (sp) {
11294c06356bSdh142964 		if (first) {
11304c06356bSdh142964 			mdb_printf("\nDead Command Queue:\n");
11314c06356bSdh142964 			mdb_printf("---------------------------\n");
11324c06356bSdh142964 		}
11334c06356bSdh142964 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
11344c06356bSdh142964 			NOREAD(pmcs_cmd_t, sp);
11354c06356bSdh142964 			break;
11364c06356bSdh142964 		}
113714d6cf0aSdh142964 		print_spcmd(&s, sp, first, verbose);
11384c06356bSdh142964 		sp = s.cmd_next.stqe_next;
11394c06356bSdh142964 		first = 0;
11404c06356bSdh142964 	}
11414c06356bSdh142964 
11424c06356bSdh142964 	sp = m.cq.stqh_first;
11434c06356bSdh142964 	first = 1;
11444c06356bSdh142964 	while (sp) {
11454c06356bSdh142964 		if (first) {
11464c06356bSdh142964 			mdb_printf("\nCompletion Command Queue:\n");
11474c06356bSdh142964 			mdb_printf("---------------------------\n");
11484c06356bSdh142964 		}
11494c06356bSdh142964 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
11504c06356bSdh142964 			NOREAD(pmcs_cmd_t, sp);
11514c06356bSdh142964 			break;
11524c06356bSdh142964 		}
115314d6cf0aSdh142964 		print_spcmd(&s, sp, first, verbose);
11544c06356bSdh142964 		sp = s.cmd_next.stqe_next;
11554c06356bSdh142964 		first = 0;
11564c06356bSdh142964 	}
11574c06356bSdh142964 
11584c06356bSdh142964 
11594c06356bSdh142964 	if (targets == NULL) {
11604c06356bSdh142964 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
11614c06356bSdh142964 	}
11624c06356bSdh142964 
11634c06356bSdh142964 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
11644c06356bSdh142964 		NOREAD(targets, m.targets);
11654c06356bSdh142964 		return;
11664c06356bSdh142964 	}
11674c06356bSdh142964 
11684c06356bSdh142964 	for (i = 0; i < max_dev; i++) {
11694c06356bSdh142964 		if (targets[i] == NULL) {
11704c06356bSdh142964 			continue;
11714c06356bSdh142964 		}
11724c06356bSdh142964 		if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) {
11734c06356bSdh142964 			NOREAD(pmcs_xscsi_t, targets[i]);
11744c06356bSdh142964 			continue;
11754c06356bSdh142964 		}
11764c06356bSdh142964 		sp = xs.wq.stqh_first;
11774c06356bSdh142964 		first = 1;
11784c06356bSdh142964 		while (sp) {
11794c06356bSdh142964 			if (first) {
11804c06356bSdh142964 				mdb_printf("\nTarget %u Wait Queue:\n",
11814c06356bSdh142964 				    xs.target_num);
11824c06356bSdh142964 				mdb_printf("---------------------------\n");
11834c06356bSdh142964 			}
11844c06356bSdh142964 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
11854c06356bSdh142964 				NOREAD(pmcs_cmd_t, sp);
11864c06356bSdh142964 				break;
11874c06356bSdh142964 			}
118814d6cf0aSdh142964 			print_spcmd(&s, sp, first, verbose);
11894c06356bSdh142964 			sp = s.cmd_next.stqe_next;
11904c06356bSdh142964 			first = 0;
11914c06356bSdh142964 		}
11924c06356bSdh142964 		sp = xs.aq.stqh_first;
11934c06356bSdh142964 		first = 1;
11944c06356bSdh142964 		while (sp) {
11954c06356bSdh142964 			if (first) {
11964c06356bSdh142964 				mdb_printf("\nTarget %u Active Queue:\n",
11974c06356bSdh142964 				    xs.target_num);
11984c06356bSdh142964 				mdb_printf("---------------------------\n");
11994c06356bSdh142964 			}
12004c06356bSdh142964 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
12014c06356bSdh142964 				NOREAD(pmcs_cmd_t, sp);
12024c06356bSdh142964 				break;
12034c06356bSdh142964 			}
120414d6cf0aSdh142964 			print_spcmd(&s, sp, first, verbose);
12054c06356bSdh142964 			sp = s.cmd_next.stqe_next;
12064c06356bSdh142964 			first = 0;
12074c06356bSdh142964 		}
12084c06356bSdh142964 		sp = xs.sq.stqh_first;
12094c06356bSdh142964 		first = 1;
12104c06356bSdh142964 		while (sp) {
12114c06356bSdh142964 			if (first) {
12124c06356bSdh142964 				mdb_printf("\nTarget %u Special Queue:\n",
12134c06356bSdh142964 				    xs.target_num);
12144c06356bSdh142964 				mdb_printf("---------------------------\n");
12154c06356bSdh142964 			}
12164c06356bSdh142964 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
12174c06356bSdh142964 				NOREAD(pmcs_cmd_t, sp);
12184c06356bSdh142964 				break;
12194c06356bSdh142964 			}
122014d6cf0aSdh142964 			print_spcmd(&s, sp, first, verbose);
12214c06356bSdh142964 			sp = s.cmd_next.stqe_next;
12224c06356bSdh142964 			first = 0;
12234c06356bSdh142964 		}
12244c06356bSdh142964 	}
12254c06356bSdh142964 }
12264c06356bSdh142964 
12274c06356bSdh142964 static char *
12284c06356bSdh142964 ibq_type(int qnum)
12294c06356bSdh142964 {
12304c06356bSdh142964 	if (qnum < 0 || qnum >= PMCS_NIQ) {
12314c06356bSdh142964 		return ("UNKNOWN");
12324c06356bSdh142964 	}
12334c06356bSdh142964 
12344c06356bSdh142964 	if (qnum < PMCS_IQ_OTHER) {
12354c06356bSdh142964 		return ("I/O");
12364c06356bSdh142964 	}
12374c06356bSdh142964 
12384c06356bSdh142964 	return ("Other");
12394c06356bSdh142964 }
12404c06356bSdh142964 
12414c06356bSdh142964 static char *
12424c06356bSdh142964 obq_type(int qnum)
12434c06356bSdh142964 {
12444c06356bSdh142964 	switch (qnum) {
12454c06356bSdh142964 	case PMCS_OQ_IODONE:
12464c06356bSdh142964 		return ("I/O");
12474c06356bSdh142964 	case PMCS_OQ_GENERAL:
12484c06356bSdh142964 		return ("General");
12494c06356bSdh142964 	case PMCS_OQ_EVENTS:
12504c06356bSdh142964 		return ("Events");
12514c06356bSdh142964 	default:
12524c06356bSdh142964 		return ("UNKNOWN");
12534c06356bSdh142964 	}
12544c06356bSdh142964 }
12554c06356bSdh142964 
12564c06356bSdh142964 static char *
12574c06356bSdh142964 iomb_cat(uint32_t cat)
12584c06356bSdh142964 {
12594c06356bSdh142964 	switch (cat) {
12604c06356bSdh142964 	case PMCS_IOMB_CAT_NET:
12614c06356bSdh142964 		return ("NET");
12624c06356bSdh142964 	case PMCS_IOMB_CAT_FC:
12634c06356bSdh142964 		return ("FC");
12644c06356bSdh142964 	case PMCS_IOMB_CAT_SAS:
12654c06356bSdh142964 		return ("SAS");
12664c06356bSdh142964 	case PMCS_IOMB_CAT_SCSI:
12674c06356bSdh142964 		return ("SCSI");
12684c06356bSdh142964 	default:
12694c06356bSdh142964 		return ("???");
12704c06356bSdh142964 	}
12714c06356bSdh142964 }
12724c06356bSdh142964 
12734c06356bSdh142964 static char *
12749aed1621SDavid Hollister iomb_event(uint8_t event)
12759aed1621SDavid Hollister {
12769aed1621SDavid Hollister 	switch (event) {
12779aed1621SDavid Hollister 	case IOP_EVENT_PHY_STOP_STATUS:
12789aed1621SDavid Hollister 		return ("PHY STOP");
12799aed1621SDavid Hollister 	case IOP_EVENT_SAS_PHY_UP:
12809aed1621SDavid Hollister 		return ("PHY UP");
12819aed1621SDavid Hollister 	case IOP_EVENT_SATA_PHY_UP:
12829aed1621SDavid Hollister 		return ("SATA PHY UP");
12839aed1621SDavid Hollister 	case IOP_EVENT_SATA_SPINUP_HOLD:
12849aed1621SDavid Hollister 		return ("SATA SPINUP HOLD");
12859aed1621SDavid Hollister 	case IOP_EVENT_PHY_DOWN:
12869aed1621SDavid Hollister 		return ("PHY DOWN");
12879aed1621SDavid Hollister 	case IOP_EVENT_BROADCAST_CHANGE:
12889aed1621SDavid Hollister 		return ("BROADCAST CHANGE");
12899aed1621SDavid Hollister 	case IOP_EVENT_BROADCAST_SES:
12909aed1621SDavid Hollister 		return ("BROADCAST SES");
12919aed1621SDavid Hollister 	case IOP_EVENT_PHY_ERR_INBOUND_CRC:
12929aed1621SDavid Hollister 		return ("INBOUND CRC ERROR");
12939aed1621SDavid Hollister 	case IOP_EVENT_HARD_RESET_RECEIVED:
12949aed1621SDavid Hollister 		return ("HARD RESET");
12959aed1621SDavid Hollister 	case IOP_EVENT_EVENT_ID_FRAME_TIMO:
12969aed1621SDavid Hollister 		return ("IDENTIFY FRAME TIMEOUT");
12979aed1621SDavid Hollister 	case IOP_EVENT_BROADCAST_EXP:
12989aed1621SDavid Hollister 		return ("BROADCAST EXPANDER");
12999aed1621SDavid Hollister 	case IOP_EVENT_PHY_START_STATUS:
13009aed1621SDavid Hollister 		return ("PHY START");
13019aed1621SDavid Hollister 	case IOP_EVENT_PHY_ERR_INVALID_DWORD:
13029aed1621SDavid Hollister 		return ("INVALID DWORD");
13039aed1621SDavid Hollister 	case IOP_EVENT_PHY_ERR_DISPARITY_ERROR:
13049aed1621SDavid Hollister 		return ("DISPARITY ERROR");
13059aed1621SDavid Hollister 	case IOP_EVENT_PHY_ERR_CODE_VIOLATION:
13069aed1621SDavid Hollister 		return ("CODE VIOLATION");
13079aed1621SDavid Hollister 	case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN:
13089aed1621SDavid Hollister 		return ("LOSS OF DWORD SYNC");
13099aed1621SDavid Hollister 	case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD:
13109aed1621SDavid Hollister 		return ("PHY RESET FAILED");
13119aed1621SDavid Hollister 	case IOP_EVENT_PORT_RECOVERY_TIMER_TMO:
13129aed1621SDavid Hollister 		return ("PORT RECOVERY TIMEOUT");
13139aed1621SDavid Hollister 	case IOP_EVENT_PORT_RECOVER:
13149aed1621SDavid Hollister 		return ("PORT RECOVERY");
13159aed1621SDavid Hollister 	case IOP_EVENT_PORT_RESET_TIMER_TMO:
13169aed1621SDavid Hollister 		return ("PORT RESET TIMEOUT");
13179aed1621SDavid Hollister 	case IOP_EVENT_PORT_RESET_COMPLETE:
13189aed1621SDavid Hollister 		return ("PORT RESET COMPLETE");
13199aed1621SDavid Hollister 	case IOP_EVENT_BROADCAST_ASYNC_EVENT:
13209aed1621SDavid Hollister 		return ("BROADCAST ASYNC");
13219aed1621SDavid Hollister 	case IOP_EVENT_IT_NEXUS_LOSS:
13229aed1621SDavid Hollister 		return ("I/T NEXUS LOSS");
13239aed1621SDavid Hollister 	default:
13249aed1621SDavid Hollister 		return ("Unknown Event");
13259aed1621SDavid Hollister 	}
13269aed1621SDavid Hollister }
13279aed1621SDavid Hollister 
13289aed1621SDavid Hollister static char *
13294c06356bSdh142964 inbound_iomb_opcode(uint32_t opcode)
13304c06356bSdh142964 {
13314c06356bSdh142964 	switch (opcode) {
13324c06356bSdh142964 	case PMCIN_ECHO:
13334c06356bSdh142964 		return ("ECHO");
13344c06356bSdh142964 	case PMCIN_GET_INFO:
13354c06356bSdh142964 		return ("GET_INFO");
13364c06356bSdh142964 	case PMCIN_GET_VPD:
13374c06356bSdh142964 		return ("GET_VPD");
13384c06356bSdh142964 	case PMCIN_PHY_START:
13394c06356bSdh142964 		return ("PHY_START");
13404c06356bSdh142964 	case PMCIN_PHY_STOP:
13414c06356bSdh142964 		return ("PHY_STOP");
13424c06356bSdh142964 	case PMCIN_SSP_INI_IO_START:
13434c06356bSdh142964 		return ("INI_IO_START");
13444c06356bSdh142964 	case PMCIN_SSP_INI_TM_START:
13454c06356bSdh142964 		return ("INI_TM_START");
13464c06356bSdh142964 	case PMCIN_SSP_INI_EXT_IO_START:
13474c06356bSdh142964 		return ("INI_EXT_IO_START");
13484c06356bSdh142964 	case PMCIN_DEVICE_HANDLE_ACCEPT:
13494c06356bSdh142964 		return ("DEVICE_HANDLE_ACCEPT");
13504c06356bSdh142964 	case PMCIN_SSP_TGT_IO_START:
13514c06356bSdh142964 		return ("TGT_IO_START");
13524c06356bSdh142964 	case PMCIN_SSP_TGT_RESPONSE_START:
13534c06356bSdh142964 		return ("TGT_RESPONSE_START");
13544c06356bSdh142964 	case PMCIN_SSP_INI_EDC_EXT_IO_START:
13554c06356bSdh142964 		return ("INI_EDC_EXT_IO_START");
13564c06356bSdh142964 	case PMCIN_SSP_INI_EDC_EXT_IO_START1:
13574c06356bSdh142964 		return ("INI_EDC_EXT_IO_START1");
13584c06356bSdh142964 	case PMCIN_SSP_TGT_EDC_IO_START:
13594c06356bSdh142964 		return ("TGT_EDC_IO_START");
13604c06356bSdh142964 	case PMCIN_SSP_ABORT:
13614c06356bSdh142964 		return ("SSP_ABORT");
13624c06356bSdh142964 	case PMCIN_DEREGISTER_DEVICE_HANDLE:
13634c06356bSdh142964 		return ("DEREGISTER_DEVICE_HANDLE");
13644c06356bSdh142964 	case PMCIN_GET_DEVICE_HANDLE:
13654c06356bSdh142964 		return ("GET_DEVICE_HANDLE");
13664c06356bSdh142964 	case PMCIN_SMP_REQUEST:
13674c06356bSdh142964 		return ("SMP_REQUEST");
13684c06356bSdh142964 	case PMCIN_SMP_RESPONSE:
13694c06356bSdh142964 		return ("SMP_RESPONSE");
13704c06356bSdh142964 	case PMCIN_SMP_ABORT:
13714c06356bSdh142964 		return ("SMP_ABORT");
13724c06356bSdh142964 	case PMCIN_ASSISTED_DISCOVERY:
13734c06356bSdh142964 		return ("ASSISTED_DISCOVERY");
13744c06356bSdh142964 	case PMCIN_REGISTER_DEVICE:
13754c06356bSdh142964 		return ("REGISTER_DEVICE");
13764c06356bSdh142964 	case PMCIN_SATA_HOST_IO_START:
13774c06356bSdh142964 		return ("SATA_HOST_IO_START");
13784c06356bSdh142964 	case PMCIN_SATA_ABORT:
13794c06356bSdh142964 		return ("SATA_ABORT");
13804c06356bSdh142964 	case PMCIN_LOCAL_PHY_CONTROL:
13814c06356bSdh142964 		return ("LOCAL_PHY_CONTROL");
13824c06356bSdh142964 	case PMCIN_GET_DEVICE_INFO:
13834c06356bSdh142964 		return ("GET_DEVICE_INFO");
13844c06356bSdh142964 	case PMCIN_TWI:
13854c06356bSdh142964 		return ("TWI");
13864c06356bSdh142964 	case PMCIN_FW_FLASH_UPDATE:
13874c06356bSdh142964 		return ("FW_FLASH_UPDATE");
13884c06356bSdh142964 	case PMCIN_SET_VPD:
13894c06356bSdh142964 		return ("SET_VPD");
13904c06356bSdh142964 	case PMCIN_GPIO:
13914c06356bSdh142964 		return ("GPIO");
13924c06356bSdh142964 	case PMCIN_SAS_DIAG_MODE_START_END:
13934c06356bSdh142964 		return ("SAS_DIAG_MODE_START_END");
13944c06356bSdh142964 	case PMCIN_SAS_DIAG_EXECUTE:
13954c06356bSdh142964 		return ("SAS_DIAG_EXECUTE");
1396978d7443SSrikanth Suravajhala 	case PMCIN_SAS_HW_EVENT_ACK:
13974c06356bSdh142964 		return ("SAS_HW_EVENT_ACK");
13984c06356bSdh142964 	case PMCIN_GET_TIME_STAMP:
13994c06356bSdh142964 		return ("GET_TIME_STAMP");
14004c06356bSdh142964 	case PMCIN_PORT_CONTROL:
14014c06356bSdh142964 		return ("PORT_CONTROL");
14024c06356bSdh142964 	case PMCIN_GET_NVMD_DATA:
14034c06356bSdh142964 		return ("GET_NVMD_DATA");
14044c06356bSdh142964 	case PMCIN_SET_NVMD_DATA:
14054c06356bSdh142964 		return ("SET_NVMD_DATA");
14064c06356bSdh142964 	case PMCIN_SET_DEVICE_STATE:
14074c06356bSdh142964 		return ("SET_DEVICE_STATE");
14084c06356bSdh142964 	case PMCIN_GET_DEVICE_STATE:
14094c06356bSdh142964 		return ("GET_DEVICE_STATE");
14104c06356bSdh142964 	default:
14114c06356bSdh142964 		return ("UNKNOWN");
14124c06356bSdh142964 	}
14134c06356bSdh142964 }
14144c06356bSdh142964 
14154c06356bSdh142964 static char *
14164c06356bSdh142964 outbound_iomb_opcode(uint32_t opcode)
14174c06356bSdh142964 {
14184c06356bSdh142964 	switch (opcode) {
14194c06356bSdh142964 	case PMCOUT_ECHO:
14204c06356bSdh142964 		return ("ECHO");
14214c06356bSdh142964 	case PMCOUT_GET_INFO:
14224c06356bSdh142964 		return ("GET_INFO");
14234c06356bSdh142964 	case PMCOUT_GET_VPD:
14244c06356bSdh142964 		return ("GET_VPD");
14254c06356bSdh142964 	case PMCOUT_SAS_HW_EVENT:
14264c06356bSdh142964 		return ("SAS_HW_EVENT");
14274c06356bSdh142964 	case PMCOUT_SSP_COMPLETION:
14284c06356bSdh142964 		return ("SSP_COMPLETION");
14294c06356bSdh142964 	case PMCOUT_SMP_COMPLETION:
14304c06356bSdh142964 		return ("SMP_COMPLETION");
14314c06356bSdh142964 	case PMCOUT_LOCAL_PHY_CONTROL:
14324c06356bSdh142964 		return ("LOCAL_PHY_CONTROL");
14334c06356bSdh142964 	case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT:
14344c06356bSdh142964 		return ("SAS_ASSISTED_DISCOVERY_SENT");
14354c06356bSdh142964 	case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT:
14364c06356bSdh142964 		return ("SATA_ASSISTED_DISCOVERY_SENT");
14374c06356bSdh142964 	case PMCOUT_DEVICE_REGISTRATION:
14384c06356bSdh142964 		return ("DEVICE_REGISTRATION");
14394c06356bSdh142964 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
14404c06356bSdh142964 		return ("DEREGISTER_DEVICE_HANDLE");
14414c06356bSdh142964 	case PMCOUT_GET_DEVICE_HANDLE:
14424c06356bSdh142964 		return ("GET_DEVICE_HANDLE");
14434c06356bSdh142964 	case PMCOUT_SATA_COMPLETION:
14444c06356bSdh142964 		return ("SATA_COMPLETION");
14454c06356bSdh142964 	case PMCOUT_SATA_EVENT:
14464c06356bSdh142964 		return ("SATA_EVENT");
14474c06356bSdh142964 	case PMCOUT_SSP_EVENT:
14484c06356bSdh142964 		return ("SSP_EVENT");
14494c06356bSdh142964 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
14504c06356bSdh142964 		return ("DEVICE_HANDLE_ARRIVED");
14514c06356bSdh142964 	case PMCOUT_SSP_REQUEST_RECEIVED:
14524c06356bSdh142964 		return ("SSP_REQUEST_RECEIVED");
14534c06356bSdh142964 	case PMCOUT_DEVICE_INFO:
14544c06356bSdh142964 		return ("DEVICE_INFO");
14554c06356bSdh142964 	case PMCOUT_FW_FLASH_UPDATE:
14564c06356bSdh142964 		return ("FW_FLASH_UPDATE");
14574c06356bSdh142964 	case PMCOUT_SET_VPD:
14584c06356bSdh142964 		return ("SET_VPD");
14594c06356bSdh142964 	case PMCOUT_GPIO:
14604c06356bSdh142964 		return ("GPIO");
14614c06356bSdh142964 	case PMCOUT_GPIO_EVENT:
14624c06356bSdh142964 		return ("GPIO_EVENT");
14634c06356bSdh142964 	case PMCOUT_GENERAL_EVENT:
14644c06356bSdh142964 		return ("GENERAL_EVENT");
14654c06356bSdh142964 	case PMCOUT_TWI:
14664c06356bSdh142964 		return ("TWI");
14674c06356bSdh142964 	case PMCOUT_SSP_ABORT:
14684c06356bSdh142964 		return ("SSP_ABORT");
14694c06356bSdh142964 	case PMCOUT_SATA_ABORT:
14704c06356bSdh142964 		return ("SATA_ABORT");
14714c06356bSdh142964 	case PMCOUT_SAS_DIAG_MODE_START_END:
14724c06356bSdh142964 		return ("SAS_DIAG_MODE_START_END");
14734c06356bSdh142964 	case PMCOUT_SAS_DIAG_EXECUTE:
14744c06356bSdh142964 		return ("SAS_DIAG_EXECUTE");
14754c06356bSdh142964 	case PMCOUT_GET_TIME_STAMP:
14764c06356bSdh142964 		return ("GET_TIME_STAMP");
14774c06356bSdh142964 	case PMCOUT_SAS_HW_EVENT_ACK_ACK:
14784c06356bSdh142964 		return ("SAS_HW_EVENT_ACK_ACK");
14794c06356bSdh142964 	case PMCOUT_PORT_CONTROL:
14804c06356bSdh142964 		return ("PORT_CONTROL");
14814c06356bSdh142964 	case PMCOUT_SKIP_ENTRIES:
14824c06356bSdh142964 		return ("SKIP_ENTRIES");
14834c06356bSdh142964 	case PMCOUT_SMP_ABORT:
14844c06356bSdh142964 		return ("SMP_ABORT");
14854c06356bSdh142964 	case PMCOUT_GET_NVMD_DATA:
14864c06356bSdh142964 		return ("GET_NVMD_DATA");
14874c06356bSdh142964 	case PMCOUT_SET_NVMD_DATA:
14884c06356bSdh142964 		return ("SET_NVMD_DATA");
14894c06356bSdh142964 	case PMCOUT_DEVICE_HANDLE_REMOVED:
14904c06356bSdh142964 		return ("DEVICE_HANDLE_REMOVED");
14914c06356bSdh142964 	case PMCOUT_SET_DEVICE_STATE:
14924c06356bSdh142964 		return ("SET_DEVICE_STATE");
14934c06356bSdh142964 	case PMCOUT_GET_DEVICE_STATE:
14944c06356bSdh142964 		return ("GET_DEVICE_STATE");
14954c06356bSdh142964 	case PMCOUT_SET_DEVICE_INFO:
14964c06356bSdh142964 		return ("SET_DEVICE_INFO");
14974c06356bSdh142964 	default:
14984c06356bSdh142964 		return ("UNKNOWN");
14994c06356bSdh142964 	}
15004c06356bSdh142964 }
15014c06356bSdh142964 
150265e70c04SDavid Hollister static uint32_t
150365e70c04SDavid Hollister get_devid_from_ob_iomb(struct pmcs_hw ss, uint32_t *qentryp, uint16_t opcode)
150465e70c04SDavid Hollister {
150565e70c04SDavid Hollister 	uint32_t devid = PMCS_INVALID_DEVICE_ID;
150665e70c04SDavid Hollister 
150765e70c04SDavid Hollister 	switch (opcode) {
150865e70c04SDavid Hollister 	/*
150965e70c04SDavid Hollister 	 * These are obtained via the HTAG which is in word 1
151065e70c04SDavid Hollister 	 */
151165e70c04SDavid Hollister 	case PMCOUT_SSP_COMPLETION:
151265e70c04SDavid Hollister 	case PMCOUT_SMP_COMPLETION:
151365e70c04SDavid Hollister 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
151465e70c04SDavid Hollister 	case PMCOUT_GET_DEVICE_HANDLE:
151565e70c04SDavid Hollister 	case PMCOUT_SATA_COMPLETION:
151665e70c04SDavid Hollister 	case PMCOUT_SSP_ABORT:
151765e70c04SDavid Hollister 	case PMCOUT_SATA_ABORT:
151865e70c04SDavid Hollister 	case PMCOUT_SMP_ABORT:
151965e70c04SDavid Hollister 	case PMCOUT_SAS_HW_EVENT_ACK_ACK: {
152065e70c04SDavid Hollister 		uint32_t	htag;
152165e70c04SDavid Hollister 		pmcwork_t	*wp;
152265e70c04SDavid Hollister 		pmcs_phy_t	*phy;
152365e70c04SDavid Hollister 		uintptr_t	_wp, _phy;
152465e70c04SDavid Hollister 		uint16_t	index;
152565e70c04SDavid Hollister 
152665e70c04SDavid Hollister 		htag = LE_32(*(qentryp + 1));
152765e70c04SDavid Hollister 		index = htag & PMCS_TAG_INDEX_MASK;
152865e70c04SDavid Hollister 
152965e70c04SDavid Hollister 		wp = mdb_alloc(sizeof (pmcwork_t), UM_SLEEP);
153065e70c04SDavid Hollister 		_wp = (uintptr_t)ss.work + (sizeof (pmcwork_t) * index);
153165e70c04SDavid Hollister 
153265e70c04SDavid Hollister 		if (MDB_RD(wp, sizeof (pmcwork_t), _wp) == -1) {
153365e70c04SDavid Hollister 			NOREAD(pmcwork_t, _wp);
153465e70c04SDavid Hollister 			mdb_free(wp, sizeof (pmcwork_t));
153565e70c04SDavid Hollister 			break;
153665e70c04SDavid Hollister 		}
153765e70c04SDavid Hollister 
153865e70c04SDavid Hollister 		phy = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
153965e70c04SDavid Hollister 		if (wp->phy == NULL) {
154065e70c04SDavid Hollister 			_phy = (uintptr_t)wp->last_phy;
154165e70c04SDavid Hollister 		} else {
154265e70c04SDavid Hollister 			_phy = (uintptr_t)wp->phy;
154365e70c04SDavid Hollister 		}
154465e70c04SDavid Hollister 
154565e70c04SDavid Hollister 		/*
154665e70c04SDavid Hollister 		 * If we have a PHY, read it in and get it's handle
154765e70c04SDavid Hollister 		 */
154865e70c04SDavid Hollister 		if (_phy != NULL) {
154965e70c04SDavid Hollister 			if (MDB_RD(phy, sizeof (*phy), _phy) == -1) {
155065e70c04SDavid Hollister 				NOREAD(pmcs_phy_t, phy);
155165e70c04SDavid Hollister 			} else {
155265e70c04SDavid Hollister 				devid = phy->device_id;
155365e70c04SDavid Hollister 			}
155465e70c04SDavid Hollister 		}
155565e70c04SDavid Hollister 
155665e70c04SDavid Hollister 		mdb_free(phy, sizeof (pmcs_phy_t));
155765e70c04SDavid Hollister 		mdb_free(wp, sizeof (pmcwork_t));
155865e70c04SDavid Hollister 		break;
155965e70c04SDavid Hollister 	}
156065e70c04SDavid Hollister 
156165e70c04SDavid Hollister 	/*
156265e70c04SDavid Hollister 	 * The device ID is in the outbound IOMB at word 1
156365e70c04SDavid Hollister 	 */
156465e70c04SDavid Hollister 	case PMCOUT_SSP_REQUEST_RECEIVED:
156565e70c04SDavid Hollister 		devid = LE_32(*(qentryp + 1)) & PMCS_DEVICE_ID_MASK;
156665e70c04SDavid Hollister 		break;
156765e70c04SDavid Hollister 
156865e70c04SDavid Hollister 	/*
156965e70c04SDavid Hollister 	 * The device ID is in the outbound IOMB at word 2
157065e70c04SDavid Hollister 	 */
157165e70c04SDavid Hollister 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
157265e70c04SDavid Hollister 	case PMCOUT_DEVICE_HANDLE_REMOVED:
157365e70c04SDavid Hollister 		devid = LE_32(*(qentryp + 2)) & PMCS_DEVICE_ID_MASK;
157465e70c04SDavid Hollister 		break;
157565e70c04SDavid Hollister 
157665e70c04SDavid Hollister 	/*
157765e70c04SDavid Hollister 	 * In this (very rare - never seen it) state, the device ID
157865e70c04SDavid Hollister 	 * comes from the HTAG in the inbound IOMB, which would be word
157965e70c04SDavid Hollister 	 * 3 in the outbound IOMB
158065e70c04SDavid Hollister 	 */
158165e70c04SDavid Hollister 	case PMCOUT_GENERAL_EVENT:
158265e70c04SDavid Hollister 	/*
158365e70c04SDavid Hollister 	 * The device ID is in the outbound IOMB at word 3
158465e70c04SDavid Hollister 	 */
158565e70c04SDavid Hollister 	case PMCOUT_DEVICE_REGISTRATION:
158665e70c04SDavid Hollister 	case PMCOUT_DEVICE_INFO:
158765e70c04SDavid Hollister 	case PMCOUT_SET_DEVICE_STATE:
158865e70c04SDavid Hollister 	case PMCOUT_GET_DEVICE_STATE:
158965e70c04SDavid Hollister 	case PMCOUT_SET_DEVICE_INFO:
159065e70c04SDavid Hollister 		devid = LE_32(*(qentryp + 3)) & PMCS_DEVICE_ID_MASK;
159165e70c04SDavid Hollister 		break;
159265e70c04SDavid Hollister 
159365e70c04SDavid Hollister 	/*
159465e70c04SDavid Hollister 	 * Device ID is in the outbound IOMB at word 4
159565e70c04SDavid Hollister 	 */
159665e70c04SDavid Hollister 	case PMCOUT_SATA_EVENT:
159765e70c04SDavid Hollister 	case PMCOUT_SSP_EVENT:
159865e70c04SDavid Hollister 		devid = LE_32(*(qentryp + 4)) & PMCS_DEVICE_ID_MASK;
159965e70c04SDavid Hollister 		break;
160065e70c04SDavid Hollister 	}
160165e70c04SDavid Hollister 
160265e70c04SDavid Hollister 	return (devid);
160365e70c04SDavid Hollister }
160465e70c04SDavid Hollister 
160565e70c04SDavid Hollister static boolean_t
160665e70c04SDavid Hollister iomb_is_dev_hdl_specific(uint32_t word0, boolean_t inbound)
160765e70c04SDavid Hollister {
160865e70c04SDavid Hollister 	uint16_t opcode = word0 & PMCS_IOMB_OPCODE_MASK;
160965e70c04SDavid Hollister 
161065e70c04SDavid Hollister 	if (inbound) {
161165e70c04SDavid Hollister 		switch (opcode) {
161265e70c04SDavid Hollister 		case PMCIN_SSP_INI_IO_START:
161365e70c04SDavid Hollister 		case PMCIN_SSP_INI_TM_START:
161465e70c04SDavid Hollister 		case PMCIN_SSP_INI_EXT_IO_START:
161565e70c04SDavid Hollister 		case PMCIN_SSP_TGT_IO_START:
161665e70c04SDavid Hollister 		case PMCIN_SSP_TGT_RESPONSE_START:
161765e70c04SDavid Hollister 		case PMCIN_SSP_ABORT:
161865e70c04SDavid Hollister 		case PMCIN_DEREGISTER_DEVICE_HANDLE:
161965e70c04SDavid Hollister 		case PMCIN_SMP_REQUEST:
162065e70c04SDavid Hollister 		case PMCIN_SMP_RESPONSE:
162165e70c04SDavid Hollister 		case PMCIN_SMP_ABORT:
162265e70c04SDavid Hollister 		case PMCIN_ASSISTED_DISCOVERY:
162365e70c04SDavid Hollister 		case PMCIN_SATA_HOST_IO_START:
162465e70c04SDavid Hollister 		case PMCIN_SATA_ABORT:
162565e70c04SDavid Hollister 		case PMCIN_GET_DEVICE_INFO:
162665e70c04SDavid Hollister 		case PMCIN_SET_DEVICE_STATE:
162765e70c04SDavid Hollister 		case PMCIN_GET_DEVICE_STATE:
162865e70c04SDavid Hollister 			return (B_TRUE);
162965e70c04SDavid Hollister 		}
163065e70c04SDavid Hollister 
163165e70c04SDavid Hollister 		return (B_FALSE);
163265e70c04SDavid Hollister 	}
163365e70c04SDavid Hollister 
163465e70c04SDavid Hollister 	switch (opcode) {
163565e70c04SDavid Hollister 	case PMCOUT_SSP_COMPLETION:
163665e70c04SDavid Hollister 	case PMCOUT_SMP_COMPLETION:
163765e70c04SDavid Hollister 	case PMCOUT_DEVICE_REGISTRATION:
163865e70c04SDavid Hollister 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
163965e70c04SDavid Hollister 	case PMCOUT_GET_DEVICE_HANDLE:
164065e70c04SDavid Hollister 	case PMCOUT_SATA_COMPLETION:
164165e70c04SDavid Hollister 	case PMCOUT_SATA_EVENT:
164265e70c04SDavid Hollister 	case PMCOUT_SSP_EVENT:
164365e70c04SDavid Hollister 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
164465e70c04SDavid Hollister 	case PMCOUT_SSP_REQUEST_RECEIVED:
164565e70c04SDavid Hollister 	case PMCOUT_DEVICE_INFO:
164665e70c04SDavid Hollister 	case PMCOUT_FW_FLASH_UPDATE:
164765e70c04SDavid Hollister 	case PMCOUT_GENERAL_EVENT:
164865e70c04SDavid Hollister 	case PMCOUT_SSP_ABORT:
164965e70c04SDavid Hollister 	case PMCOUT_SATA_ABORT:
165065e70c04SDavid Hollister 	case PMCOUT_SAS_HW_EVENT_ACK_ACK:
165165e70c04SDavid Hollister 	case PMCOUT_SMP_ABORT:
165265e70c04SDavid Hollister 	case PMCOUT_DEVICE_HANDLE_REMOVED:
165365e70c04SDavid Hollister 	case PMCOUT_SET_DEVICE_STATE:
165465e70c04SDavid Hollister 	case PMCOUT_GET_DEVICE_STATE:
165565e70c04SDavid Hollister 	case PMCOUT_SET_DEVICE_INFO:
165665e70c04SDavid Hollister 		return (B_TRUE);
165765e70c04SDavid Hollister 	}
165865e70c04SDavid Hollister 
165965e70c04SDavid Hollister 	return (B_FALSE);
166065e70c04SDavid Hollister }
166165e70c04SDavid Hollister 
16624c06356bSdh142964 static void
166365e70c04SDavid Hollister dump_one_qentry_outbound(struct pmcs_hw ss, uint32_t *qentryp, int idx,
166465e70c04SDavid Hollister     uint64_t devid_filter)
16654c06356bSdh142964 {
16664c06356bSdh142964 	int qeidx;
16674c06356bSdh142964 	uint32_t word0 = LE_32(*qentryp);
16689aed1621SDavid Hollister 	uint32_t word1 = LE_32(*(qentryp + 1));
16699aed1621SDavid Hollister 	uint8_t iop_event;
167065e70c04SDavid Hollister 	uint32_t devid;
167165e70c04SDavid Hollister 
167265e70c04SDavid Hollister 	/*
167365e70c04SDavid Hollister 	 * Check to see if we're filtering on a device ID
167465e70c04SDavid Hollister 	 */
167565e70c04SDavid Hollister 	if (devid_filter != PMCS_INVALID_DEVICE_ID) {
167665e70c04SDavid Hollister 		if (!iomb_is_dev_hdl_specific(word0, B_FALSE)) {
167765e70c04SDavid Hollister 			return;
167865e70c04SDavid Hollister 		}
167965e70c04SDavid Hollister 
168065e70c04SDavid Hollister 		/*
168165e70c04SDavid Hollister 		 * Go find the device id.  It might be in the outbound
168265e70c04SDavid Hollister 		 * IOMB or we may have to go find the work structure and
168365e70c04SDavid Hollister 		 * get it from there.
168465e70c04SDavid Hollister 		 */
168565e70c04SDavid Hollister 		devid = get_devid_from_ob_iomb(ss, qentryp,
168665e70c04SDavid Hollister 		    word0 & PMCS_IOMB_OPCODE_MASK);
168765e70c04SDavid Hollister 		if ((devid == PMCS_INVALID_DEVICE_ID) ||
168865e70c04SDavid Hollister 		    (devid_filter != devid)) {
168965e70c04SDavid Hollister 			return;
169065e70c04SDavid Hollister 		}
169165e70c04SDavid Hollister 	}
16924c06356bSdh142964 
16934c06356bSdh142964 	mdb_printf("Entry #%02d\n", idx);
16944c06356bSdh142964 	mdb_inc_indent(2);
16954c06356bSdh142964 
16964c06356bSdh142964 	mdb_printf("Header: 0x%08x (", word0);
16974c06356bSdh142964 	if (word0 & PMCS_IOMB_VALID) {
16984c06356bSdh142964 		mdb_printf("VALID, ");
16994c06356bSdh142964 	}
17004c06356bSdh142964 	if (word0 & PMCS_IOMB_HIPRI) {
17014c06356bSdh142964 		mdb_printf("HIPRI, ");
17024c06356bSdh142964 	}
17034c06356bSdh142964 	mdb_printf("OBID=%d, ",
17044c06356bSdh142964 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
17054c06356bSdh142964 	mdb_printf("CAT=%s, ",
17064c06356bSdh142964 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
17074c06356bSdh142964 	mdb_printf("OPCODE=%s",
17084c06356bSdh142964 	    outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
17099aed1621SDavid Hollister 	if ((word0 & PMCS_IOMB_OPCODE_MASK) == PMCOUT_SAS_HW_EVENT) {
17109aed1621SDavid Hollister 		iop_event = IOP_EVENT_EVENT(word1);
17119aed1621SDavid Hollister 		mdb_printf(" <%s>", iomb_event(iop_event));
17129aed1621SDavid Hollister 	}
17134c06356bSdh142964 	mdb_printf(")\n");
17144c06356bSdh142964 
17154c06356bSdh142964 	mdb_printf("Remaining Payload:\n");
17164c06356bSdh142964 
17174c06356bSdh142964 	mdb_inc_indent(2);
17184c06356bSdh142964 	for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
17194c06356bSdh142964 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
17204c06356bSdh142964 	}
17214c06356bSdh142964 	mdb_printf("\n");
17224c06356bSdh142964 	mdb_dec_indent(4);
17234c06356bSdh142964 }
17244c06356bSdh142964 
17254c06356bSdh142964 static void
172665e70c04SDavid Hollister display_outbound_queues(struct pmcs_hw ss, uint64_t devid_filter,
172765e70c04SDavid Hollister     uint_t verbose)
17284c06356bSdh142964 {
17294c06356bSdh142964 	int		idx, qidx;
17304c06356bSdh142964 	uintptr_t	obqp;
17314c06356bSdh142964 	uint32_t	*cip;
17324c06356bSdh142964 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
17334c06356bSdh142964 	uint32_t	last_consumed, oqpi;
17344c06356bSdh142964 
17354c06356bSdh142964 	mdb_printf("\n");
17364c06356bSdh142964 	mdb_printf("Outbound Queues\n");
17374c06356bSdh142964 	mdb_printf("---------------\n");
17384c06356bSdh142964 
17394c06356bSdh142964 	mdb_inc_indent(2);
17404c06356bSdh142964 
17414c06356bSdh142964 	for (qidx = 0; qidx < PMCS_NOQ; qidx++) {
17424c06356bSdh142964 		obqp = (uintptr_t)ss.oqp[qidx];
17434c06356bSdh142964 
17444c06356bSdh142964 		if (obqp == NULL) {
17454c06356bSdh142964 			mdb_printf("No outbound queue ptr for queue #%d\n",
17464c06356bSdh142964 			    qidx);
17474c06356bSdh142964 			continue;
17484c06356bSdh142964 		}
17494c06356bSdh142964 
17504c06356bSdh142964 		mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx,
17514c06356bSdh142964 		    obq_type(qidx));
17524c06356bSdh142964 		/*
17534c06356bSdh142964 		 * Chip is the producer, so read the actual producer index
17544c06356bSdh142964 		 * and not the driver's version
17554c06356bSdh142964 		 */
17564c06356bSdh142964 		cip = (uint32_t *)((void *)ss.cip);
17574c06356bSdh142964 		if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET +
17584c06356bSdh142964 		    (qidx * 4)) == -1) {
17594c06356bSdh142964 			mdb_warn("Couldn't read oqpi\n");
17604c06356bSdh142964 			break;
17614c06356bSdh142964 		}
17624c06356bSdh142964 
17634c06356bSdh142964 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
17644c06356bSdh142964 		    LE_32(oqpi), ss.oqci[qidx]);
17654c06356bSdh142964 		mdb_inc_indent(2);
17664c06356bSdh142964 
17674c06356bSdh142964 		if (ss.oqci[qidx] == 0) {
17684c06356bSdh142964 			last_consumed = ss.ioq_depth - 1;
17694c06356bSdh142964 		} else {
17704c06356bSdh142964 			last_consumed = ss.oqci[qidx] - 1;
17714c06356bSdh142964 		}
17724c06356bSdh142964 
17734c06356bSdh142964 
17744c06356bSdh142964 		if (!verbose) {
17754c06356bSdh142964 			mdb_printf("Last processed entry:\n");
17764c06356bSdh142964 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
17774c06356bSdh142964 			    (obqp + (PMCS_QENTRY_SIZE * last_consumed)))
17784c06356bSdh142964 			    == -1) {
17794c06356bSdh142964 				mdb_warn("Couldn't read queue entry at 0x%p\n",
17804c06356bSdh142964 				    (obqp + (PMCS_QENTRY_SIZE *
17814c06356bSdh142964 				    last_consumed)));
17824c06356bSdh142964 				break;
17834c06356bSdh142964 			}
178465e70c04SDavid Hollister 			dump_one_qentry_outbound(ss, qentryp, last_consumed,
178565e70c04SDavid Hollister 			    devid_filter);
17864c06356bSdh142964 			mdb_printf("\n");
17874c06356bSdh142964 			mdb_dec_indent(2);
17884c06356bSdh142964 			continue;
17894c06356bSdh142964 		}
17904c06356bSdh142964 
17914c06356bSdh142964 		for (idx = 0; idx < ss.ioq_depth; idx++) {
17924c06356bSdh142964 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
17934c06356bSdh142964 			    (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
17944c06356bSdh142964 				mdb_warn("Couldn't read queue entry at 0x%p\n",
17954c06356bSdh142964 				    (obqp + (PMCS_QENTRY_SIZE * idx)));
17964c06356bSdh142964 				break;
17974c06356bSdh142964 			}
179865e70c04SDavid Hollister 			dump_one_qentry_outbound(ss, qentryp, idx,
179965e70c04SDavid Hollister 			    devid_filter);
18004c06356bSdh142964 		}
18014c06356bSdh142964 
18024c06356bSdh142964 		mdb_printf("\n");
18034c06356bSdh142964 		mdb_dec_indent(2);
18044c06356bSdh142964 	}
18054c06356bSdh142964 
18064c06356bSdh142964 	mdb_dec_indent(2);
18074c06356bSdh142964 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
18084c06356bSdh142964 }
18094c06356bSdh142964 
18104c06356bSdh142964 static void
181165e70c04SDavid Hollister dump_one_qentry_inbound(uint32_t *qentryp, int idx, uint64_t devid_filter)
18124c06356bSdh142964 {
18134c06356bSdh142964 	int qeidx;
18144c06356bSdh142964 	uint32_t word0 = LE_32(*qentryp);
181565e70c04SDavid Hollister 	uint32_t devid = LE_32(*(qentryp + 2));
181665e70c04SDavid Hollister 
181765e70c04SDavid Hollister 	/*
181865e70c04SDavid Hollister 	 * Check to see if we're filtering on a device ID
181965e70c04SDavid Hollister 	 */
182065e70c04SDavid Hollister 	if (devid_filter != PMCS_INVALID_DEVICE_ID) {
182165e70c04SDavid Hollister 		if (iomb_is_dev_hdl_specific(word0, B_TRUE)) {
182265e70c04SDavid Hollister 			if (devid_filter != devid) {
182365e70c04SDavid Hollister 				return;
182465e70c04SDavid Hollister 			}
182565e70c04SDavid Hollister 		} else {
182665e70c04SDavid Hollister 			return;
182765e70c04SDavid Hollister 		}
182865e70c04SDavid Hollister 	}
18294c06356bSdh142964 
18304c06356bSdh142964 	mdb_printf("Entry #%02d\n", idx);
18314c06356bSdh142964 	mdb_inc_indent(2);
18324c06356bSdh142964 
18334c06356bSdh142964 	mdb_printf("Header: 0x%08x (", word0);
18344c06356bSdh142964 	if (word0 & PMCS_IOMB_VALID) {
18354c06356bSdh142964 		mdb_printf("VALID, ");
18364c06356bSdh142964 	}
18374c06356bSdh142964 	if (word0 & PMCS_IOMB_HIPRI) {
18384c06356bSdh142964 		mdb_printf("HIPRI, ");
18394c06356bSdh142964 	}
18404c06356bSdh142964 	mdb_printf("OBID=%d, ",
18414c06356bSdh142964 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
18424c06356bSdh142964 	mdb_printf("CAT=%s, ",
18434c06356bSdh142964 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
18444c06356bSdh142964 	mdb_printf("OPCODE=%s",
18454c06356bSdh142964 	    inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
18464c06356bSdh142964 	mdb_printf(")\n");
18474c06356bSdh142964 
18484c06356bSdh142964 	mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1)));
18494c06356bSdh142964 	mdb_printf("Remaining Payload:\n");
18504c06356bSdh142964 
18514c06356bSdh142964 	mdb_inc_indent(2);
18524c06356bSdh142964 	for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
18534c06356bSdh142964 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
18544c06356bSdh142964 	}
18554c06356bSdh142964 	mdb_printf("\n");
18564c06356bSdh142964 	mdb_dec_indent(4);
18574c06356bSdh142964 }
18584c06356bSdh142964 
18594c06356bSdh142964 static void
186065e70c04SDavid Hollister display_inbound_queues(struct pmcs_hw ss, uint64_t devid_filter, uint_t verbose)
18614c06356bSdh142964 {
18624c06356bSdh142964 	int		idx, qidx, iqci, last_consumed;
18634c06356bSdh142964 	uintptr_t	ibqp;
18644c06356bSdh142964 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
18654c06356bSdh142964 	uint32_t	*cip;
18664c06356bSdh142964 
18674c06356bSdh142964 	mdb_printf("\n");
18684c06356bSdh142964 	mdb_printf("Inbound Queues\n");
18694c06356bSdh142964 	mdb_printf("--------------\n");
18704c06356bSdh142964 
18714c06356bSdh142964 	mdb_inc_indent(2);
18724c06356bSdh142964 
18734c06356bSdh142964 	for (qidx = 0; qidx < PMCS_NIQ; qidx++) {
18744c06356bSdh142964 		ibqp = (uintptr_t)ss.iqp[qidx];
18754c06356bSdh142964 
18764c06356bSdh142964 		if (ibqp == NULL) {
18774c06356bSdh142964 			mdb_printf("No inbound queue ptr for queue #%d\n",
18784c06356bSdh142964 			    qidx);
18794c06356bSdh142964 			continue;
18804c06356bSdh142964 		}
18814c06356bSdh142964 
18824c06356bSdh142964 		mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx,
18834c06356bSdh142964 		    ibq_type(qidx));
18844c06356bSdh142964 
18854c06356bSdh142964 		cip = (uint32_t *)((void *)ss.cip);
18864c06356bSdh142964 		if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) {
18874c06356bSdh142964 			mdb_warn("Couldn't read iqci\n");
18884c06356bSdh142964 			break;
18894c06356bSdh142964 		}
18904c06356bSdh142964 		iqci = LE_32(iqci);
18914c06356bSdh142964 
18924c06356bSdh142964 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
18934c06356bSdh142964 		    ss.shadow_iqpi[qidx], iqci);
18944c06356bSdh142964 		mdb_inc_indent(2);
18954c06356bSdh142964 
18964c06356bSdh142964 		if (iqci == 0) {
18974c06356bSdh142964 			last_consumed = ss.ioq_depth - 1;
18984c06356bSdh142964 		} else {
18994c06356bSdh142964 			last_consumed = iqci - 1;
19004c06356bSdh142964 		}
19014c06356bSdh142964 
19024c06356bSdh142964 		if (!verbose) {
19034c06356bSdh142964 			mdb_printf("Last processed entry:\n");
19044c06356bSdh142964 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
19054c06356bSdh142964 			    (ibqp + (PMCS_QENTRY_SIZE * last_consumed)))
19064c06356bSdh142964 			    == -1) {
19074c06356bSdh142964 				mdb_warn("Couldn't read queue entry at 0x%p\n",
19084c06356bSdh142964 				    (ibqp + (PMCS_QENTRY_SIZE *
19094c06356bSdh142964 				    last_consumed)));
19104c06356bSdh142964 				break;
19114c06356bSdh142964 			}
191265e70c04SDavid Hollister 			dump_one_qentry_inbound(qentryp, last_consumed,
191365e70c04SDavid Hollister 			    devid_filter);
19144c06356bSdh142964 			mdb_printf("\n");
19154c06356bSdh142964 			mdb_dec_indent(2);
19164c06356bSdh142964 			continue;
19174c06356bSdh142964 		}
19184c06356bSdh142964 
19194c06356bSdh142964 		for (idx = 0; idx < ss.ioq_depth; idx++) {
19204c06356bSdh142964 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
19214c06356bSdh142964 			    (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
19224c06356bSdh142964 				mdb_warn("Couldn't read queue entry at 0x%p\n",
19234c06356bSdh142964 				    (ibqp + (PMCS_QENTRY_SIZE * idx)));
19244c06356bSdh142964 				break;
19254c06356bSdh142964 			}
192665e70c04SDavid Hollister 			dump_one_qentry_inbound(qentryp, idx, devid_filter);
19274c06356bSdh142964 		}
19284c06356bSdh142964 
19294c06356bSdh142964 		mdb_printf("\n");
19304c06356bSdh142964 		mdb_dec_indent(2);
19314c06356bSdh142964 	}
19324c06356bSdh142964 
19334c06356bSdh142964 	mdb_dec_indent(2);
19344c06356bSdh142964 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
19354c06356bSdh142964 }
19364c06356bSdh142964 
19379aed1621SDavid Hollister /*
19389aed1621SDavid Hollister  * phy is our copy of the PHY structure.  phyp is the pointer to the actual
19399aed1621SDavid Hollister  * kernel PHY data structure
19409aed1621SDavid Hollister  */
19414c06356bSdh142964 static void
19429aed1621SDavid Hollister display_phy(struct pmcs_phy phy, struct pmcs_phy *phyp, int verbose,
19439aed1621SDavid Hollister     int totals_only)
19444c06356bSdh142964 {
19454c06356bSdh142964 	char		*dtype, *speed;
19464c06356bSdh142964 	char		*yes = "Yes";
19474c06356bSdh142964 	char		*no = "No";
19484c06356bSdh142964 	char		*cfgd = no;
19494c06356bSdh142964 	char		*apend = no;
19504c06356bSdh142964 	char		*asent = no;
19514c06356bSdh142964 	char		*dead = no;
19524c06356bSdh142964 	char		*changed = no;
19539aed1621SDavid Hollister 	char		route_attr, route_method;
19544c06356bSdh142964 
19554c06356bSdh142964 	switch (phy.dtype) {
19564c06356bSdh142964 	case NOTHING:
19574c06356bSdh142964 		dtype = "None";
19584c06356bSdh142964 		break;
19594c06356bSdh142964 	case SATA:
19604c06356bSdh142964 		dtype = "SATA";
19614c06356bSdh142964 		if (phy.configured) {
19624c06356bSdh142964 			++sata_phys;
19634c06356bSdh142964 		}
19644c06356bSdh142964 		break;
19654c06356bSdh142964 	case SAS:
19664c06356bSdh142964 		dtype = "SAS";
19674c06356bSdh142964 		if (phy.configured) {
19684c06356bSdh142964 			++sas_phys;
19694c06356bSdh142964 		}
19704c06356bSdh142964 		break;
19714c06356bSdh142964 	case EXPANDER:
19724c06356bSdh142964 		dtype = "EXP";
19734c06356bSdh142964 		if (phy.configured) {
19744c06356bSdh142964 			++exp_phys;
19754c06356bSdh142964 		}
19764c06356bSdh142964 		break;
19774c06356bSdh142964 	}
19784c06356bSdh142964 
19794c06356bSdh142964 	if (phy.dtype == NOTHING) {
19804c06356bSdh142964 		empty_phys++;
19814c06356bSdh142964 	} else if ((phy.dtype == EXPANDER) && phy.configured) {
19824c06356bSdh142964 		num_expanders++;
19834c06356bSdh142964 	}
19844c06356bSdh142964 
19854c06356bSdh142964 	if (totals_only) {
19864c06356bSdh142964 		return;
19874c06356bSdh142964 	}
19884c06356bSdh142964 
19894c06356bSdh142964 	switch (phy.link_rate) {
19904c06356bSdh142964 	case SAS_LINK_RATE_1_5GBIT:
19914c06356bSdh142964 		speed = "1.5Gb/s";
19924c06356bSdh142964 		break;
19934c06356bSdh142964 	case SAS_LINK_RATE_3GBIT:
19944c06356bSdh142964 		speed = "3 Gb/s";
19954c06356bSdh142964 		break;
19964c06356bSdh142964 	case SAS_LINK_RATE_6GBIT:
19974c06356bSdh142964 		speed = "6 Gb/s";
19984c06356bSdh142964 		break;
19994c06356bSdh142964 	default:
20004c06356bSdh142964 		speed = "N/A";
20014c06356bSdh142964 		break;
20024c06356bSdh142964 	}
20034c06356bSdh142964 
20044c06356bSdh142964 	if ((phy.dtype != NOTHING) || verbose) {
20054c06356bSdh142964 		print_sas_address(&phy);
20064c06356bSdh142964 
20074c06356bSdh142964 		if (phy.device_id != PMCS_INVALID_DEVICE_ID) {
20084c06356bSdh142964 			mdb_printf(" %3d %4d %6s %4s ",
20094c06356bSdh142964 			    phy.device_id, phy.phynum, speed, dtype);
20104c06356bSdh142964 		} else {
20114c06356bSdh142964 			mdb_printf(" N/A %4d %6s %4s ",
20124c06356bSdh142964 			    phy.phynum, speed, dtype);
20134c06356bSdh142964 		}
20144c06356bSdh142964 
20154c06356bSdh142964 		if (verbose) {
20164c06356bSdh142964 			if (phy.abort_sent) {
20174c06356bSdh142964 				asent = yes;
20184c06356bSdh142964 			}
20194c06356bSdh142964 			if (phy.abort_pending) {
20204c06356bSdh142964 				apend = yes;
20214c06356bSdh142964 			}
20224c06356bSdh142964 			if (phy.configured) {
20234c06356bSdh142964 				cfgd = yes;
20244c06356bSdh142964 			}
20254c06356bSdh142964 			if (phy.dead) {
20264c06356bSdh142964 				dead = yes;
20274c06356bSdh142964 			}
20284c06356bSdh142964 			if (phy.changed) {
20294c06356bSdh142964 				changed = yes;
20304c06356bSdh142964 			}
20314c06356bSdh142964 
20329aed1621SDavid Hollister 			switch (phy.routing_attr) {
20339aed1621SDavid Hollister 			case SMP_ROUTING_DIRECT:
20349aed1621SDavid Hollister 				route_attr = 'D';
20359aed1621SDavid Hollister 				break;
20369aed1621SDavid Hollister 			case SMP_ROUTING_SUBTRACTIVE:
20379aed1621SDavid Hollister 				route_attr = 'S';
20389aed1621SDavid Hollister 				break;
20399aed1621SDavid Hollister 			case SMP_ROUTING_TABLE:
20409aed1621SDavid Hollister 				route_attr = 'T';
20419aed1621SDavid Hollister 				break;
20429aed1621SDavid Hollister 			default:
20439aed1621SDavid Hollister 				route_attr = '?';
20449aed1621SDavid Hollister 				break;
20459aed1621SDavid Hollister 			}
20469aed1621SDavid Hollister 
20479aed1621SDavid Hollister 			switch (phy.routing_method) {
20489aed1621SDavid Hollister 			case SMP_ROUTING_DIRECT:
20499aed1621SDavid Hollister 				route_method = 'D';
20509aed1621SDavid Hollister 				break;
20519aed1621SDavid Hollister 			case SMP_ROUTING_SUBTRACTIVE:
20529aed1621SDavid Hollister 				route_method = 'S';
20539aed1621SDavid Hollister 				break;
20549aed1621SDavid Hollister 			case SMP_ROUTING_TABLE:
20559aed1621SDavid Hollister 				route_method = 'T';
20569aed1621SDavid Hollister 				break;
20579aed1621SDavid Hollister 			default:
20589aed1621SDavid Hollister 				route_attr = '?';
20599aed1621SDavid Hollister 				break;
20609aed1621SDavid Hollister 			}
20619aed1621SDavid Hollister 
20629aed1621SDavid Hollister 			mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d "
20639aed1621SDavid Hollister 			    "%1d 0x%p ", cfgd, apend, asent, changed, dead,
20649aed1621SDavid Hollister 			    phy.ref_count, route_attr, route_method,
20659aed1621SDavid Hollister 			    phy.enum_attempts, phy.reenumerate, phy.phy_lock);
20664c06356bSdh142964 		}
20674c06356bSdh142964 
20684c06356bSdh142964 		mdb_printf("Path: %s\n", phy.path);
20699aed1621SDavid Hollister 
20709aed1621SDavid Hollister 		/*
20719aed1621SDavid Hollister 		 * In verbose mode, on the next line print the drill down
20729aed1621SDavid Hollister 		 * info to see either the DISCOVER response or the REPORT
20739aed1621SDavid Hollister 		 * GENERAL response depending on the PHY's dtype
20749aed1621SDavid Hollister 		 */
20759aed1621SDavid Hollister 		if (verbose) {
20769aed1621SDavid Hollister 			uintptr_t tphyp = (uintptr_t)phyp;
20779aed1621SDavid Hollister 
20789aed1621SDavid Hollister 			mdb_inc_indent(4);
20799aed1621SDavid Hollister 			switch (phy.dtype) {
20809aed1621SDavid Hollister 			case EXPANDER:
20819aed1621SDavid Hollister 				if (!phy.configured) {
20829aed1621SDavid Hollister 					break;
20839aed1621SDavid Hollister 				}
20849aed1621SDavid Hollister 				mdb_printf("REPORT GENERAL response: %p::"
20859aed1621SDavid Hollister 				    "print smp_report_general_resp_t\n",
20869aed1621SDavid Hollister 				    (tphyp + offsetof(struct pmcs_phy,
20879aed1621SDavid Hollister 				    rg_resp)));
20889aed1621SDavid Hollister 				break;
20899aed1621SDavid Hollister 			case SAS:
20909aed1621SDavid Hollister 			case SATA:
20919aed1621SDavid Hollister 				mdb_printf("DISCOVER response: %p::"
20929aed1621SDavid Hollister 				    "print smp_discover_resp_t\n",
20939aed1621SDavid Hollister 				    (tphyp + offsetof(struct pmcs_phy,
20949aed1621SDavid Hollister 				    disc_resp)));
20959aed1621SDavid Hollister 				break;
20969aed1621SDavid Hollister 			default:
20979aed1621SDavid Hollister 				break;
20989aed1621SDavid Hollister 			}
20999aed1621SDavid Hollister 			mdb_dec_indent(4);
21009aed1621SDavid Hollister 		}
21014c06356bSdh142964 	}
21024c06356bSdh142964 }
21034c06356bSdh142964 
21044c06356bSdh142964 static void
21054c06356bSdh142964 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level,
21064c06356bSdh142964     int totals_only)
21074c06356bSdh142964 {
21084c06356bSdh142964 	pmcs_phy_t	phy;
21094c06356bSdh142964 	pmcs_phy_t	*pphy = parent;
21104c06356bSdh142964 
21114c06356bSdh142964 	mdb_inc_indent(3);
21124c06356bSdh142964 
21134c06356bSdh142964 	if (parent == NULL) {
21144c06356bSdh142964 		pphy = (pmcs_phy_t *)ss.root_phys;
21154c06356bSdh142964 	} else {
21164c06356bSdh142964 		pphy = (pmcs_phy_t *)parent;
21174c06356bSdh142964 	}
21184c06356bSdh142964 
21194c06356bSdh142964 	if (level == 0) {
21204c06356bSdh142964 		sas_phys = 0;
21214c06356bSdh142964 		sata_phys = 0;
21224c06356bSdh142964 		exp_phys = 0;
21234c06356bSdh142964 		num_expanders = 0;
21244c06356bSdh142964 		empty_phys = 0;
21254c06356bSdh142964 	}
21264c06356bSdh142964 
21274c06356bSdh142964 	if (!totals_only) {
21284c06356bSdh142964 		if (level == 0) {
21294c06356bSdh142964 			mdb_printf("PHY information\n");
21304c06356bSdh142964 		}
21314c06356bSdh142964 		mdb_printf("--------\n");
21324c06356bSdh142964 		mdb_printf("Level %2d\n", level);
21334c06356bSdh142964 		mdb_printf("--------\n");
21344c06356bSdh142964 		mdb_printf("SAS Address      Hdl Phy#  Speed Type ");
21354c06356bSdh142964 
21364c06356bSdh142964 		if (verbose) {
21379aed1621SDavid Hollister 			mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R "
21389aed1621SDavid Hollister 			    "Lock\n");
21394c06356bSdh142964 		} else {
21404c06356bSdh142964 			mdb_printf("\n");
21414c06356bSdh142964 		}
21424c06356bSdh142964 	}
21434c06356bSdh142964 
21444c06356bSdh142964 	while (pphy) {
21454c06356bSdh142964 		if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) {
21464c06356bSdh142964 			NOREAD(pmcs_phy_t, phy);
21474c06356bSdh142964 			break;
21484c06356bSdh142964 		}
21494c06356bSdh142964 
21509aed1621SDavid Hollister 		display_phy(phy, pphy, verbose, totals_only);
21514c06356bSdh142964 
21524c06356bSdh142964 		if (phy.children) {
21534c06356bSdh142964 			display_phys(ss, verbose, phy.children, level + 1,
21544c06356bSdh142964 			    totals_only);
21554c06356bSdh142964 			if (!totals_only) {
21564c06356bSdh142964 				mdb_printf("\n");
21574c06356bSdh142964 			}
21584c06356bSdh142964 		}
21594c06356bSdh142964 
21604c06356bSdh142964 		pphy = phy.sibling;
21614c06356bSdh142964 	}
21624c06356bSdh142964 
21634c06356bSdh142964 	mdb_dec_indent(3);
21644c06356bSdh142964 
21654c06356bSdh142964 	if (level == 0) {
21664c06356bSdh142964 		if (verbose) {
21674c06356bSdh142964 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
21684c06356bSdh142964 			    "(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
21694c06356bSdh142964 			    (sas_phys + sata_phys + num_expanders),
21704c06356bSdh142964 			    sas_phys, sata_phys, num_expanders,
21714c06356bSdh142964 			    (exp_phys - num_expanders), empty_phys);
21724c06356bSdh142964 		} else {
21734c06356bSdh142964 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
21744c06356bSdh142964 			    "Occupied PHYs:",
21754c06356bSdh142964 			    (sas_phys + sata_phys + num_expanders),
21764c06356bSdh142964 			    sas_phys, sata_phys, num_expanders);
21774c06356bSdh142964 		}
21784c06356bSdh142964 	}
21794c06356bSdh142964 }
21804c06356bSdh142964 
21814c06356bSdh142964 /*
2182c3bc407cSdh142964  * filter is used to indicate whether we are filtering log messages based
2183c3bc407cSdh142964  * on "instance".  The other filtering (based on options) depends on the
2184c3bc407cSdh142964  * values that are passed in for "sas_addr" and "phy_path".
2185c3bc407cSdh142964  *
21864c06356bSdh142964  * MAX_INST_STRLEN is the largest string size from which we will attempt
21874c06356bSdh142964  * to convert to an instance number.  The string will be formed up as
21884c06356bSdh142964  * "0t<inst>\0" so that mdb_strtoull can parse it properly.
21894c06356bSdh142964  */
21904c06356bSdh142964 #define	MAX_INST_STRLEN	8
21914c06356bSdh142964 
21924c06356bSdh142964 static int
2193601c90f1SSrikanth, Ramana pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines,
21941f81b464SDavid Hollister     const char *phy_path, uint64_t sas_address, uint64_t verbose)
21954c06356bSdh142964 {
21964c06356bSdh142964 	pmcs_tbuf_t *tbuf_addr;
21974c06356bSdh142964 	uint_t tbuf_idx;
21984c06356bSdh142964 	pmcs_tbuf_t tbuf;
21994c06356bSdh142964 	boolean_t wrap, elem_filtered;
22004c06356bSdh142964 	uint_t start_idx, elems_to_print, idx, tbuf_num_elems;
22014c06356bSdh142964 	char *bufp;
22024c06356bSdh142964 	char elem_inst[MAX_INST_STRLEN], ei_idx;
2203c3bc407cSdh142964 	uint64_t sas_addr;
2204c3bc407cSdh142964 	uint8_t *sas_addressp;
22054c06356bSdh142964 
22064c06356bSdh142964 	/* Get the address of the first element */
22074c06356bSdh142964 	if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) {
22084c06356bSdh142964 		mdb_warn("can't read pmcs_tbuf");
22094c06356bSdh142964 		return (DCMD_ERR);
22104c06356bSdh142964 	}
22114c06356bSdh142964 
22124c06356bSdh142964 	/* Get the total number */
22134c06356bSdh142964 	if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) {
22144c06356bSdh142964 		mdb_warn("can't read pmcs_tbuf_num_elems");
22154c06356bSdh142964 		return (DCMD_ERR);
22164c06356bSdh142964 	}
22174c06356bSdh142964 
22184c06356bSdh142964 	/* Get the current index */
22194c06356bSdh142964 	if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) {
22204c06356bSdh142964 		mdb_warn("can't read pmcs_tbuf_idx");
22214c06356bSdh142964 		return (DCMD_ERR);
22224c06356bSdh142964 	}
22234c06356bSdh142964 
22244c06356bSdh142964 	/* Indicator as to whether the buffer has wrapped */
22254c06356bSdh142964 	if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) {
22264c06356bSdh142964 		mdb_warn("can't read pmcs_tbuf_wrap");
22274c06356bSdh142964 		return (DCMD_ERR);
22284c06356bSdh142964 	}
22294c06356bSdh142964 
2230c3bc407cSdh142964 	/*
2231c3bc407cSdh142964 	 * On little-endian systems, the SAS address passed in will be
2232c3bc407cSdh142964 	 * byte swapped.  Take care of that here.
2233c3bc407cSdh142964 	 */
2234c3bc407cSdh142964 #if defined(_LITTLE_ENDIAN)
2235c3bc407cSdh142964 	sas_addr = ((sas_address << 56) |
2236c3bc407cSdh142964 	    ((sas_address << 40) & 0xff000000000000ULL) |
2237c3bc407cSdh142964 	    ((sas_address << 24) & 0xff0000000000ULL) |
2238c3bc407cSdh142964 	    ((sas_address << 8)  & 0xff00000000ULL) |
2239c3bc407cSdh142964 	    ((sas_address >> 8)  & 0xff000000ULL) |
2240c3bc407cSdh142964 	    ((sas_address >> 24) & 0xff0000ULL) |
2241c3bc407cSdh142964 	    ((sas_address >> 40) & 0xff00ULL) |
2242c3bc407cSdh142964 	    (sas_address  >> 56));
2243c3bc407cSdh142964 #else
2244c3bc407cSdh142964 	sas_addr = sas_address;
2245c3bc407cSdh142964 #endif
2246c3bc407cSdh142964 	sas_addressp = (uint8_t *)&sas_addr;
2247c3bc407cSdh142964 
2248601c90f1SSrikanth, Ramana 	/* Ensure the tail number isn't greater than the size of the log */
2249601c90f1SSrikanth, Ramana 	if (tail_lines > tbuf_num_elems) {
2250601c90f1SSrikanth, Ramana 		tail_lines = tbuf_num_elems;
2251601c90f1SSrikanth, Ramana 	}
2252601c90f1SSrikanth, Ramana 
22534c06356bSdh142964 	/* Figure out where we start and stop */
22544c06356bSdh142964 	if (wrap) {
2255601c90f1SSrikanth, Ramana 		if (tail_lines) {
2256601c90f1SSrikanth, Ramana 			/* Do we need to wrap backwards? */
2257601c90f1SSrikanth, Ramana 			if (tail_lines > tbuf_idx) {
2258601c90f1SSrikanth, Ramana 				start_idx = tbuf_num_elems - (tail_lines -
2259601c90f1SSrikanth, Ramana 				    tbuf_idx);
2260601c90f1SSrikanth, Ramana 			} else {
2261601c90f1SSrikanth, Ramana 				start_idx = tbuf_idx - tail_lines;
2262601c90f1SSrikanth, Ramana 			}
2263601c90f1SSrikanth, Ramana 			elems_to_print = tail_lines;
2264601c90f1SSrikanth, Ramana 		} else {
22654c06356bSdh142964 			start_idx = tbuf_idx;
22664c06356bSdh142964 			elems_to_print = tbuf_num_elems;
2267601c90f1SSrikanth, Ramana 		}
2268601c90f1SSrikanth, Ramana 	} else {
2269601c90f1SSrikanth, Ramana 		if (tail_lines > tbuf_idx) {
2270601c90f1SSrikanth, Ramana 			tail_lines = tbuf_idx;
2271601c90f1SSrikanth, Ramana 		}
2272601c90f1SSrikanth, Ramana 		if (tail_lines) {
2273601c90f1SSrikanth, Ramana 			start_idx = tbuf_idx - tail_lines;
2274601c90f1SSrikanth, Ramana 			elems_to_print = tail_lines;
22754c06356bSdh142964 		} else {
22764c06356bSdh142964 			start_idx = 0;
22774c06356bSdh142964 			elems_to_print = tbuf_idx;
22784c06356bSdh142964 		}
2279601c90f1SSrikanth, Ramana 	}
22804c06356bSdh142964 
22814c06356bSdh142964 	idx = start_idx;
22824c06356bSdh142964 
22834c06356bSdh142964 	/* Dump the buffer contents */
22844c06356bSdh142964 	while (elems_to_print != 0) {
22854c06356bSdh142964 		if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx))
22864c06356bSdh142964 		    == -1) {
22874c06356bSdh142964 			NOREAD(tbuf, (tbuf_addr + idx));
22884c06356bSdh142964 			return (DCMD_ERR);
22894c06356bSdh142964 		}
22904c06356bSdh142964 
2291c3bc407cSdh142964 		/*
2292c3bc407cSdh142964 		 * Check for filtering on HBA instance
2293c3bc407cSdh142964 		 */
22944c06356bSdh142964 		elem_filtered = B_FALSE;
22954c06356bSdh142964 
22964c06356bSdh142964 		if (filter) {
22974c06356bSdh142964 			bufp = tbuf.buf;
22984c06356bSdh142964 			/* Skip the driver name */
22994c06356bSdh142964 			while (*bufp < '0' || *bufp > '9') {
23004c06356bSdh142964 				bufp++;
23014c06356bSdh142964 			}
23024c06356bSdh142964 
23034c06356bSdh142964 			ei_idx = 0;
23044c06356bSdh142964 			elem_inst[ei_idx++] = '0';
23054c06356bSdh142964 			elem_inst[ei_idx++] = 't';
23064c06356bSdh142964 			while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) {
23074c06356bSdh142964 				elem_inst[ei_idx++] = *bufp;
23084c06356bSdh142964 				bufp++;
23094c06356bSdh142964 			}
23104c06356bSdh142964 			elem_inst[ei_idx] = 0;
23114c06356bSdh142964 
23124c06356bSdh142964 			/* Get the instance */
23134c06356bSdh142964 			if ((int)mdb_strtoull(elem_inst) != instance) {
23144c06356bSdh142964 				elem_filtered = B_TRUE;
23154c06356bSdh142964 			}
23164c06356bSdh142964 		}
23174c06356bSdh142964 
2318c3bc407cSdh142964 		if (!elem_filtered && (phy_path || sas_address)) {
2319c3bc407cSdh142964 			/*
2320c3bc407cSdh142964 			 * This message is not being filtered by HBA instance.
2321c3bc407cSdh142964 			 * Now check to see if we're filtering based on
2322c3bc407cSdh142964 			 * PHY path or SAS address.
2323c3bc407cSdh142964 			 * Filtering is an "OR" operation.  So, if any of the
2324c3bc407cSdh142964 			 * criteria matches, this message will be printed.
2325c3bc407cSdh142964 			 */
2326c3bc407cSdh142964 			elem_filtered = B_TRUE;
2327c3bc407cSdh142964 
2328c3bc407cSdh142964 			if (phy_path != NULL) {
2329c3bc407cSdh142964 				if (strncmp(phy_path, tbuf.phy_path,
2330c3bc407cSdh142964 				    PMCS_TBUF_UA_MAX_SIZE) == 0) {
2331c3bc407cSdh142964 					elem_filtered = B_FALSE;
2332c3bc407cSdh142964 				}
2333c3bc407cSdh142964 			}
2334c3bc407cSdh142964 			if (sas_address != 0) {
2335c3bc407cSdh142964 				if (memcmp(sas_addressp, tbuf.phy_sas_address,
2336c3bc407cSdh142964 				    8) == 0) {
2337c3bc407cSdh142964 					elem_filtered = B_FALSE;
2338c3bc407cSdh142964 				}
2339c3bc407cSdh142964 			}
2340c3bc407cSdh142964 		}
2341c3bc407cSdh142964 
23424c06356bSdh142964 		if (!elem_filtered) {
23431f81b464SDavid Hollister 			/*
23441f81b464SDavid Hollister 			 * If the -v flag was given, print the firmware
23451f81b464SDavid Hollister 			 * timestamp along with the clock time
23461f81b464SDavid Hollister 			 */
23471f81b464SDavid Hollister 			mdb_printf("%Y.%09ld ", tbuf.timestamp);
23481f81b464SDavid Hollister 			if (verbose) {
23491f81b464SDavid Hollister 				mdb_printf("(0x%" PRIx64 ") ",
23501f81b464SDavid Hollister 				    tbuf.fw_timestamp);
23511f81b464SDavid Hollister 			}
23521f81b464SDavid Hollister 			mdb_printf("%s\n", tbuf.buf);
23534c06356bSdh142964 		}
23544c06356bSdh142964 
23554c06356bSdh142964 		--elems_to_print;
23564c06356bSdh142964 		if (++idx == tbuf_num_elems) {
23574c06356bSdh142964 			idx = 0;
23584c06356bSdh142964 		}
23594c06356bSdh142964 	}
23604c06356bSdh142964 
23614c06356bSdh142964 	return (DCMD_OK);
23624c06356bSdh142964 }
23634c06356bSdh142964 
23644c06356bSdh142964 /*
23654c06356bSdh142964  * Walkers
23664c06356bSdh142964  */
23674c06356bSdh142964 static int
23684c06356bSdh142964 targets_walk_i(mdb_walk_state_t *wsp)
23694c06356bSdh142964 {
23704c06356bSdh142964 	if (wsp->walk_addr == NULL) {
23714c06356bSdh142964 		mdb_warn("Can not perform global walk\n");
23724c06356bSdh142964 		return (WALK_ERR);
23734c06356bSdh142964 	}
23744c06356bSdh142964 
23754c06356bSdh142964 	/*
23764c06356bSdh142964 	 * Address provided belongs to HBA softstate.  Get the targets pointer
23774c06356bSdh142964 	 * to begin the walk.
23784c06356bSdh142964 	 */
23794c06356bSdh142964 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
23804c06356bSdh142964 	    sizeof (pmcs_hw_t)) {
23814c06356bSdh142964 		mdb_warn("Unable to read HBA softstate\n");
23824c06356bSdh142964 		return (WALK_ERR);
23834c06356bSdh142964 	}
23844c06356bSdh142964 
23854c06356bSdh142964 	if (targets == NULL) {
23864c06356bSdh142964 		targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP);
23874c06356bSdh142964 	}
23884c06356bSdh142964 
23894c06356bSdh142964 	if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) {
23904c06356bSdh142964 		NOREAD(targets, ss.targets);
23914c06356bSdh142964 		return (WALK_ERR);
23924c06356bSdh142964 	}
23934c06356bSdh142964 
23944c06356bSdh142964 	target_idx = 0;
23954c06356bSdh142964 	wsp->walk_addr = (uintptr_t)(targets[0]);
23964c06356bSdh142964 	wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP);
23974c06356bSdh142964 
23984c06356bSdh142964 	return (WALK_NEXT);
23994c06356bSdh142964 }
24004c06356bSdh142964 
24014c06356bSdh142964 static int
24024c06356bSdh142964 targets_walk_s(mdb_walk_state_t *wsp)
24034c06356bSdh142964 {
24044c06356bSdh142964 	int status;
24054c06356bSdh142964 
24064c06356bSdh142964 	if (target_idx == ss.max_dev) {
24074c06356bSdh142964 		return (WALK_DONE);
24084c06356bSdh142964 	}
24094c06356bSdh142964 
24104c06356bSdh142964 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t),
24114c06356bSdh142964 	    wsp->walk_addr) == -1) {
24124c06356bSdh142964 		mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr);
24134c06356bSdh142964 		return (WALK_DONE);
24144c06356bSdh142964 	}
24154c06356bSdh142964 
24164c06356bSdh142964 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
24174c06356bSdh142964 	    wsp->walk_cbdata);
24184c06356bSdh142964 
24194c06356bSdh142964 	do {
24204c06356bSdh142964 		wsp->walk_addr = (uintptr_t)(targets[++target_idx]);
24214c06356bSdh142964 	} while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev));
24224c06356bSdh142964 
24234c06356bSdh142964 	if (target_idx == ss.max_dev) {
24244c06356bSdh142964 		return (WALK_DONE);
24254c06356bSdh142964 	}
24264c06356bSdh142964 
24274c06356bSdh142964 	return (status);
24284c06356bSdh142964 }
24294c06356bSdh142964 
24304c06356bSdh142964 static void
24314c06356bSdh142964 targets_walk_f(mdb_walk_state_t *wsp)
24324c06356bSdh142964 {
24334c06356bSdh142964 	mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t));
24344c06356bSdh142964 }
24354c06356bSdh142964 
24364c06356bSdh142964 
24374c06356bSdh142964 static pmcs_phy_t *
24384c06356bSdh142964 pmcs_next_sibling(pmcs_phy_t *phyp)
24394c06356bSdh142964 {
24404c06356bSdh142964 	pmcs_phy_t parent;
24414c06356bSdh142964 
24424c06356bSdh142964 	/*
24434c06356bSdh142964 	 * First, if this is a root PHY, there are no more siblings
24444c06356bSdh142964 	 */
24454c06356bSdh142964 	if (phyp->level == 0) {
24464c06356bSdh142964 		return (NULL);
24474c06356bSdh142964 	}
24484c06356bSdh142964 
24494c06356bSdh142964 	/*
24504c06356bSdh142964 	 * Otherwise, next sibling is the parent's sibling
24514c06356bSdh142964 	 */
24524c06356bSdh142964 	while (phyp->level > 0) {
24534c06356bSdh142964 		if (mdb_vread(&parent, sizeof (pmcs_phy_t),
24544c06356bSdh142964 		    (uintptr_t)phyp->parent) == -1) {
24554c06356bSdh142964 			mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
24564c06356bSdh142964 			    (void *)phyp->parent);
24574c06356bSdh142964 			return (NULL);
24584c06356bSdh142964 		}
24594c06356bSdh142964 
24604c06356bSdh142964 		if (parent.sibling != NULL) {
24614c06356bSdh142964 			break;
24624c06356bSdh142964 		}
24634c06356bSdh142964 
2464e71c81d1SJesse Butler 		/*
2465e71c81d1SJesse Butler 		 * If this PHY's sibling is NULL and it's a root phy,
2466e71c81d1SJesse Butler 		 * we're done.
2467e71c81d1SJesse Butler 		 */
2468e71c81d1SJesse Butler 		if (parent.level == 0) {
2469e71c81d1SJesse Butler 			return (NULL);
2470e71c81d1SJesse Butler 		}
2471e71c81d1SJesse Butler 
24724c06356bSdh142964 		phyp = phyp->parent;
24734c06356bSdh142964 	}
24744c06356bSdh142964 
24754c06356bSdh142964 	return (parent.sibling);
24764c06356bSdh142964 }
24774c06356bSdh142964 
24784c06356bSdh142964 static int
24794c06356bSdh142964 phy_walk_i(mdb_walk_state_t *wsp)
24804c06356bSdh142964 {
24814c06356bSdh142964 	if (wsp->walk_addr == NULL) {
24824c06356bSdh142964 		mdb_warn("Can not perform global walk\n");
24834c06356bSdh142964 		return (WALK_ERR);
24844c06356bSdh142964 	}
24854c06356bSdh142964 
24864c06356bSdh142964 	/*
24874c06356bSdh142964 	 * Address provided belongs to HBA softstate.  Get the targets pointer
24884c06356bSdh142964 	 * to begin the walk.
24894c06356bSdh142964 	 */
24904c06356bSdh142964 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
24914c06356bSdh142964 	    sizeof (pmcs_hw_t)) {
24924c06356bSdh142964 		mdb_warn("Unable to read HBA softstate\n");
24934c06356bSdh142964 		return (WALK_ERR);
24944c06356bSdh142964 	}
24954c06356bSdh142964 
24964c06356bSdh142964 	wsp->walk_addr = (uintptr_t)(ss.root_phys);
24974c06356bSdh142964 	wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
24984c06356bSdh142964 
24994c06356bSdh142964 	return (WALK_NEXT);
25004c06356bSdh142964 }
25014c06356bSdh142964 
25024c06356bSdh142964 static int
25034c06356bSdh142964 phy_walk_s(mdb_walk_state_t *wsp)
25044c06356bSdh142964 {
25054c06356bSdh142964 	pmcs_phy_t *phyp, *nphyp;
25064c06356bSdh142964 	int status;
25074c06356bSdh142964 
25084c06356bSdh142964 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t),
25094c06356bSdh142964 	    wsp->walk_addr) == -1) {
25104c06356bSdh142964 		mdb_warn("phy_walk_s: Failed to read PHY at %p",
25114c06356bSdh142964 		    (void *)wsp->walk_addr);
25124c06356bSdh142964 		return (WALK_DONE);
25134c06356bSdh142964 	}
25144c06356bSdh142964 
25154c06356bSdh142964 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
25164c06356bSdh142964 	    wsp->walk_cbdata);
25174c06356bSdh142964 
25184c06356bSdh142964 	phyp = (pmcs_phy_t *)wsp->walk_data;
25194c06356bSdh142964 	if (phyp->children) {
25204c06356bSdh142964 		wsp->walk_addr = (uintptr_t)(phyp->children);
25214c06356bSdh142964 	} else {
25224c06356bSdh142964 		wsp->walk_addr = (uintptr_t)(phyp->sibling);
25234c06356bSdh142964 	}
25244c06356bSdh142964 
25254c06356bSdh142964 	if (wsp->walk_addr == NULL) {
25264c06356bSdh142964 		/*
25274c06356bSdh142964 		 * We reached the end of this sibling list.  Trudge back up
25284c06356bSdh142964 		 * to the parent and find the next sibling after the expander
25294c06356bSdh142964 		 * we just finished traversing, if there is one.
25304c06356bSdh142964 		 */
25314c06356bSdh142964 		nphyp = pmcs_next_sibling(phyp);
25324c06356bSdh142964 
25334c06356bSdh142964 		if (nphyp == NULL) {
25344c06356bSdh142964 			return (WALK_DONE);
25354c06356bSdh142964 		}
25364c06356bSdh142964 
25374c06356bSdh142964 		wsp->walk_addr = (uintptr_t)nphyp;
25384c06356bSdh142964 	}
25394c06356bSdh142964 
25404c06356bSdh142964 	return (status);
25414c06356bSdh142964 }
25424c06356bSdh142964 
25434c06356bSdh142964 static void
25444c06356bSdh142964 phy_walk_f(mdb_walk_state_t *wsp)
25454c06356bSdh142964 {
25464c06356bSdh142964 	mdb_free(wsp->walk_data, sizeof (pmcs_phy_t));
25474c06356bSdh142964 }
25484c06356bSdh142964 
254914d6cf0aSdh142964 static void
255014d6cf0aSdh142964 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum,
255114d6cf0aSdh142964     uintmax_t tag_type)
255214d6cf0aSdh142964 {
255314d6cf0aSdh142964 	int		idx;
255414d6cf0aSdh142964 	pmcwork_t	work, *wp = &work;
255514d6cf0aSdh142964 	uintptr_t	_wp;
255614d6cf0aSdh142964 	boolean_t	printed_header = B_FALSE;
255714d6cf0aSdh142964 	uint32_t	mask, mask_val, match_val;
255814d6cf0aSdh142964 	char		*match_type;
255914d6cf0aSdh142964 
256014d6cf0aSdh142964 	if (index != UINT_MAX) {
256114d6cf0aSdh142964 		match_type = "index";
256214d6cf0aSdh142964 		mask = PMCS_TAG_INDEX_MASK;
256314d6cf0aSdh142964 		mask_val = index << PMCS_TAG_INDEX_SHIFT;
256414d6cf0aSdh142964 		match_val = index;
256514d6cf0aSdh142964 	} else if (snum != UINT_MAX) {
256614d6cf0aSdh142964 		match_type = "serial number";
256714d6cf0aSdh142964 		mask = PMCS_TAG_SERNO_MASK;
256814d6cf0aSdh142964 		mask_val = snum << PMCS_TAG_SERNO_SHIFT;
256914d6cf0aSdh142964 		match_val = snum;
257014d6cf0aSdh142964 	} else {
257114d6cf0aSdh142964 		switch (tag_type) {
257214d6cf0aSdh142964 		case PMCS_TAG_TYPE_NONE:
257314d6cf0aSdh142964 			match_type = "tag type NONE";
257414d6cf0aSdh142964 			break;
257514d6cf0aSdh142964 		case PMCS_TAG_TYPE_CBACK:
257614d6cf0aSdh142964 			match_type = "tag type CBACK";
257714d6cf0aSdh142964 			break;
257814d6cf0aSdh142964 		case PMCS_TAG_TYPE_WAIT:
257914d6cf0aSdh142964 			match_type = "tag type WAIT";
258014d6cf0aSdh142964 			break;
258114d6cf0aSdh142964 		}
258214d6cf0aSdh142964 		mask = PMCS_TAG_TYPE_MASK;
258314d6cf0aSdh142964 		mask_val = tag_type << PMCS_TAG_TYPE_SHIFT;
258414d6cf0aSdh142964 		match_val = tag_type;
258514d6cf0aSdh142964 	}
258614d6cf0aSdh142964 
258714d6cf0aSdh142964 	_wp = (uintptr_t)ss.work;
258814d6cf0aSdh142964 
258914d6cf0aSdh142964 	for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
259014d6cf0aSdh142964 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
259114d6cf0aSdh142964 			NOREAD(pmcwork_t, _wp);
259214d6cf0aSdh142964 			continue;
259314d6cf0aSdh142964 		}
259414d6cf0aSdh142964 
259514d6cf0aSdh142964 		if ((work.htag & mask) != mask_val) {
259614d6cf0aSdh142964 			continue;
259714d6cf0aSdh142964 		}
259814d6cf0aSdh142964 
259914d6cf0aSdh142964 		if (printed_header == B_FALSE) {
260014d6cf0aSdh142964 			if (tag_type) {
260114d6cf0aSdh142964 				mdb_printf("\nWork structures matching %s\n\n",
260214d6cf0aSdh142964 				    match_type, match_val);
260314d6cf0aSdh142964 			} else {
260414d6cf0aSdh142964 				mdb_printf("\nWork structures matching %s of "
260514d6cf0aSdh142964 				    "0x%x\n\n", match_type, match_val);
260614d6cf0aSdh142964 			}
260714d6cf0aSdh142964 			mdb_printf("%8s %10s %20s %8s %8s O D\n",
260814d6cf0aSdh142964 			    "HTag", "State", "Phy Path", "Target", "Timer");
260914d6cf0aSdh142964 			printed_header = B_TRUE;
261014d6cf0aSdh142964 		}
261114d6cf0aSdh142964 
261214d6cf0aSdh142964 		display_one_work(wp, 0, 0);
261314d6cf0aSdh142964 	}
261414d6cf0aSdh142964 
261514d6cf0aSdh142964 	if (!printed_header) {
261614d6cf0aSdh142964 		mdb_printf("No work structure matches found\n");
261714d6cf0aSdh142964 	}
261814d6cf0aSdh142964 }
261914d6cf0aSdh142964 
262014d6cf0aSdh142964 static int
262114d6cf0aSdh142964 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
262214d6cf0aSdh142964 {
262314d6cf0aSdh142964 	struct	pmcs_hw		ss;
262414d6cf0aSdh142964 	uintmax_t		tag_type = UINT_MAX;
262514d6cf0aSdh142964 	uintmax_t		snum = UINT_MAX;
262614d6cf0aSdh142964 	uintmax_t		index = UINT_MAX;
262714d6cf0aSdh142964 	int			args = 0;
262814d6cf0aSdh142964 	void			*pmcs_state;
262914d6cf0aSdh142964 	char			*state_str;
263014d6cf0aSdh142964 	struct dev_info		dip;
263114d6cf0aSdh142964 
263214d6cf0aSdh142964 	if (!(flags & DCMD_ADDRSPEC)) {
263314d6cf0aSdh142964 		pmcs_state = NULL;
263414d6cf0aSdh142964 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
263514d6cf0aSdh142964 			mdb_warn("can't read pmcs_softc_state");
263614d6cf0aSdh142964 			return (DCMD_ERR);
263714d6cf0aSdh142964 		}
263814d6cf0aSdh142964 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc,
263914d6cf0aSdh142964 		    argv, (uintptr_t)pmcs_state) == -1) {
264014d6cf0aSdh142964 			mdb_warn("mdb_pwalk_dcmd failed");
264114d6cf0aSdh142964 			return (DCMD_ERR);
264214d6cf0aSdh142964 		}
264314d6cf0aSdh142964 		return (DCMD_OK);
264414d6cf0aSdh142964 	}
264514d6cf0aSdh142964 
264614d6cf0aSdh142964 	if (mdb_getopts(argc, argv,
264714d6cf0aSdh142964 	    'i', MDB_OPT_UINT64, &index,
264814d6cf0aSdh142964 	    's', MDB_OPT_UINT64, &snum,
264914d6cf0aSdh142964 	    't', MDB_OPT_UINT64, &tag_type) != argc)
265014d6cf0aSdh142964 		return (DCMD_USAGE);
265114d6cf0aSdh142964 
265214d6cf0aSdh142964 	/*
265314d6cf0aSdh142964 	 * Count the number of supplied options and make sure they are
265414d6cf0aSdh142964 	 * within appropriate ranges.  If they're set to UINT_MAX, that means
265514d6cf0aSdh142964 	 * they were not supplied, in which case reset them to 0.
265614d6cf0aSdh142964 	 */
265714d6cf0aSdh142964 	if (index != UINT_MAX) {
265814d6cf0aSdh142964 		args++;
265914d6cf0aSdh142964 		if (index > PMCS_TAG_INDEX_MASK) {
266014d6cf0aSdh142964 			mdb_warn("Index is out of range\n");
266114d6cf0aSdh142964 			return (DCMD_USAGE);
266214d6cf0aSdh142964 		}
266314d6cf0aSdh142964 	}
266414d6cf0aSdh142964 
266514d6cf0aSdh142964 	if (tag_type != UINT_MAX) {
266614d6cf0aSdh142964 		args++;
266714d6cf0aSdh142964 		switch (tag_type) {
266814d6cf0aSdh142964 		case PMCS_TAG_TYPE_NONE:
266914d6cf0aSdh142964 		case PMCS_TAG_TYPE_CBACK:
267014d6cf0aSdh142964 		case PMCS_TAG_TYPE_WAIT:
267114d6cf0aSdh142964 			break;
267214d6cf0aSdh142964 		default:
267314d6cf0aSdh142964 			mdb_warn("Invalid tag type\n");
267414d6cf0aSdh142964 			return (DCMD_USAGE);
267514d6cf0aSdh142964 		}
267614d6cf0aSdh142964 	}
267714d6cf0aSdh142964 
267814d6cf0aSdh142964 	if (snum != UINT_MAX) {
267914d6cf0aSdh142964 		args++;
268014d6cf0aSdh142964 		if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) {
268114d6cf0aSdh142964 			mdb_warn("Serial number is out of range\n");
268214d6cf0aSdh142964 			return (DCMD_USAGE);
268314d6cf0aSdh142964 		}
268414d6cf0aSdh142964 	}
268514d6cf0aSdh142964 
268614d6cf0aSdh142964 	/*
268714d6cf0aSdh142964 	 * Make sure 1 and only 1 option is specified
268814d6cf0aSdh142964 	 */
268914d6cf0aSdh142964 	if ((args == 0) || (args > 1)) {
269014d6cf0aSdh142964 		mdb_warn("Exactly one of -i, -s and -t must be specified\n");
269114d6cf0aSdh142964 		return (DCMD_USAGE);
269214d6cf0aSdh142964 	}
269314d6cf0aSdh142964 
269414d6cf0aSdh142964 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
269514d6cf0aSdh142964 		NOREAD(pmcs_hw_t, addr);
269614d6cf0aSdh142964 		return (DCMD_ERR);
269714d6cf0aSdh142964 	}
269814d6cf0aSdh142964 
269914d6cf0aSdh142964 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
270014d6cf0aSdh142964 		NOREAD(pmcs_hw_t, addr);
270114d6cf0aSdh142964 		return (DCMD_ERR);
270214d6cf0aSdh142964 	}
270314d6cf0aSdh142964 
270414d6cf0aSdh142964 	/* processing completed */
270514d6cf0aSdh142964 
270614d6cf0aSdh142964 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
270714d6cf0aSdh142964 	    (flags & DCMD_LOOPFIRST)) {
270814d6cf0aSdh142964 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
270914d6cf0aSdh142964 			mdb_printf("\n");
271014d6cf0aSdh142964 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
271114d6cf0aSdh142964 		    "Address", "State", "Inst", "DIP");
271214d6cf0aSdh142964 		mdb_printf("================================="
271314d6cf0aSdh142964 		    "============================================\n");
271414d6cf0aSdh142964 	}
271514d6cf0aSdh142964 
271614d6cf0aSdh142964 	switch (ss.state) {
271714d6cf0aSdh142964 	case STATE_NIL:
271814d6cf0aSdh142964 		state_str = "Invalid";
271914d6cf0aSdh142964 		break;
272014d6cf0aSdh142964 	case STATE_PROBING:
272114d6cf0aSdh142964 		state_str = "Probing";
272214d6cf0aSdh142964 		break;
272314d6cf0aSdh142964 	case STATE_RUNNING:
272414d6cf0aSdh142964 		state_str = "Running";
272514d6cf0aSdh142964 		break;
272614d6cf0aSdh142964 	case STATE_UNPROBING:
272714d6cf0aSdh142964 		state_str = "Unprobing";
272814d6cf0aSdh142964 		break;
272914d6cf0aSdh142964 	case STATE_DEAD:
273014d6cf0aSdh142964 		state_str = "Dead";
273114d6cf0aSdh142964 		break;
27325c45adf0SJesse Butler 	case STATE_IN_RESET:
27335c45adf0SJesse Butler 		state_str = "In Reset";
27345c45adf0SJesse Butler 		break;
273514d6cf0aSdh142964 	}
273614d6cf0aSdh142964 
273714d6cf0aSdh142964 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
273814d6cf0aSdh142964 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
273914d6cf0aSdh142964 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
274014d6cf0aSdh142964 	mdb_printf("\n");
274114d6cf0aSdh142964 
274214d6cf0aSdh142964 	mdb_inc_indent(4);
274314d6cf0aSdh142964 	display_matching_work(ss, index, snum, tag_type);
274414d6cf0aSdh142964 	mdb_dec_indent(4);
274514d6cf0aSdh142964 	mdb_printf("\n");
274614d6cf0aSdh142964 
274714d6cf0aSdh142964 	return (DCMD_OK);
274814d6cf0aSdh142964 }
274914d6cf0aSdh142964 
27509719310aSDavid Hollister #ifndef _KMDB
27519719310aSDavid Hollister static int
27529719310aSDavid Hollister pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile)
27539719310aSDavid Hollister {
27549719310aSDavid Hollister 	uint8_t *fwlogp;
27559719310aSDavid Hollister 	int	ofilefd = -1;
27569719310aSDavid Hollister 	char	ofilename[MAXPATHLEN];
27579719310aSDavid Hollister 	int	rval = DCMD_OK;
27589719310aSDavid Hollister 
27599719310aSDavid Hollister 	if (ss->fwlogp == NULL) {
27609719310aSDavid Hollister 		mdb_warn("Firmware event log disabled for instance %d",
27619719310aSDavid Hollister 		    instance);
27629719310aSDavid Hollister 		return (DCMD_OK);
27639719310aSDavid Hollister 	}
27649719310aSDavid Hollister 
27659719310aSDavid Hollister 	if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) >
27669719310aSDavid Hollister 	    MAXPATHLEN) {
27679719310aSDavid Hollister 		mdb_warn("Output filename is too long for instance %d",
27689719310aSDavid Hollister 		    instance);
27699719310aSDavid Hollister 		return (DCMD_ERR);
27709719310aSDavid Hollister 	}
27719719310aSDavid Hollister 
27729719310aSDavid Hollister 	fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP);
27739719310aSDavid Hollister 
27749719310aSDavid Hollister 	if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) {
27759719310aSDavid Hollister 		NOREAD(fwlogp, ss->fwlogp);
27769719310aSDavid Hollister 		rval = DCMD_ERR;
27779719310aSDavid Hollister 		goto cleanup;
27789719310aSDavid Hollister 	}
27799719310aSDavid Hollister 
27809719310aSDavid Hollister 	ofilefd = open(ofilename, O_WRONLY | O_CREAT,
27819719310aSDavid Hollister 	    S_IRUSR | S_IRGRP | S_IROTH);
27829719310aSDavid Hollister 	if (ofilefd < 0) {
27839719310aSDavid Hollister 		mdb_warn("Unable to open '%s' to dump instance %d event log",
27849719310aSDavid Hollister 		    ofilename, instance);
27859719310aSDavid Hollister 		rval = DCMD_ERR;
27869719310aSDavid Hollister 		goto cleanup;
27879719310aSDavid Hollister 	}
27889719310aSDavid Hollister 
27899719310aSDavid Hollister 	if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) {
27909719310aSDavid Hollister 		mdb_warn("Failed to write %d bytes to output file: instance %d",
27919719310aSDavid Hollister 		    PMCS_FWLOG_SIZE, instance);
27929719310aSDavid Hollister 		rval = DCMD_ERR;
27939719310aSDavid Hollister 		goto cleanup;
27949719310aSDavid Hollister 	}
27959719310aSDavid Hollister 
27969719310aSDavid Hollister 	mdb_printf("Event log for instance %d written to %s\n", instance,
27979719310aSDavid Hollister 	    ofilename);
27989719310aSDavid Hollister 
27999719310aSDavid Hollister cleanup:
28009719310aSDavid Hollister 	if (ofilefd >= 0) {
28019719310aSDavid Hollister 		close(ofilefd);
28029719310aSDavid Hollister 	}
28039719310aSDavid Hollister 	mdb_free(fwlogp, PMCS_FWLOG_SIZE);
28049719310aSDavid Hollister 	return (rval);
28059719310aSDavid Hollister }
28069719310aSDavid Hollister 
28079719310aSDavid Hollister static int
28089719310aSDavid Hollister pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
28099719310aSDavid Hollister {
28109719310aSDavid Hollister 	void		*pmcs_state;
28119719310aSDavid Hollister 	const char	*ofile = NULL;
28129719310aSDavid Hollister 	struct pmcs_hw	ss;
28139719310aSDavid Hollister 	struct dev_info	dip;
28149719310aSDavid Hollister 
28159719310aSDavid Hollister 	if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) {
28169719310aSDavid Hollister 		return (DCMD_USAGE);
28179719310aSDavid Hollister 	}
28189719310aSDavid Hollister 
28199719310aSDavid Hollister 	if (ofile == NULL) {
28209719310aSDavid Hollister 		mdb_printf("No output file specified\n");
28219719310aSDavid Hollister 		return (DCMD_USAGE);
28229719310aSDavid Hollister 	}
28239719310aSDavid Hollister 
28249719310aSDavid Hollister 	if (!(flags & DCMD_ADDRSPEC)) {
28259719310aSDavid Hollister 		pmcs_state = NULL;
28269719310aSDavid Hollister 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
28279719310aSDavid Hollister 			mdb_warn("can't read pmcs_softc_state");
28289719310aSDavid Hollister 			return (DCMD_ERR);
28299719310aSDavid Hollister 		}
28309719310aSDavid Hollister 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc,
28319719310aSDavid Hollister 		    argv, (uintptr_t)pmcs_state) == -1) {
28329719310aSDavid Hollister 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
28339719310aSDavid Hollister 			return (DCMD_ERR);
28349719310aSDavid Hollister 		}
28359719310aSDavid Hollister 		return (DCMD_OK);
28369719310aSDavid Hollister 	}
28379719310aSDavid Hollister 
28389719310aSDavid Hollister 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
28399719310aSDavid Hollister 		NOREAD(pmcs_hw_t, addr);
28409719310aSDavid Hollister 		return (DCMD_ERR);
28419719310aSDavid Hollister 	}
28429719310aSDavid Hollister 
28439719310aSDavid Hollister 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
28449719310aSDavid Hollister 		NOREAD(pmcs_hw_t, addr);
28459719310aSDavid Hollister 		return (DCMD_ERR);
28469719310aSDavid Hollister 	}
28479719310aSDavid Hollister 
28489719310aSDavid Hollister 	return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile));
28499719310aSDavid Hollister }
28509719310aSDavid Hollister #endif	/* _KMDB */
28519719310aSDavid Hollister 
28524c06356bSdh142964 static int
2853c3bc407cSdh142964 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2854c3bc407cSdh142964 {
2855c3bc407cSdh142964 	void		*pmcs_state;
2856c3bc407cSdh142964 	struct pmcs_hw	ss;
2857c3bc407cSdh142964 	struct dev_info	dip;
2858c3bc407cSdh142964 	const char	*match_phy_path = NULL;
2859601c90f1SSrikanth, Ramana 	uint64_t 	match_sas_address = 0, tail_lines = 0;
28601f81b464SDavid Hollister 	uint_t		verbose = 0;
2861c3bc407cSdh142964 
2862c3bc407cSdh142964 	if (!(flags & DCMD_ADDRSPEC)) {
2863c3bc407cSdh142964 		pmcs_state = NULL;
2864c3bc407cSdh142964 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2865c3bc407cSdh142964 			mdb_warn("can't read pmcs_softc_state");
2866c3bc407cSdh142964 			return (DCMD_ERR);
2867c3bc407cSdh142964 		}
2868c3bc407cSdh142964 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc,
2869c3bc407cSdh142964 		    argv, (uintptr_t)pmcs_state) == -1) {
2870c3bc407cSdh142964 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
2871c3bc407cSdh142964 			return (DCMD_ERR);
2872c3bc407cSdh142964 		}
2873c3bc407cSdh142964 		return (DCMD_OK);
2874c3bc407cSdh142964 	}
2875c3bc407cSdh142964 
2876c3bc407cSdh142964 	if (mdb_getopts(argc, argv,
2877601c90f1SSrikanth, Ramana 	    'l', MDB_OPT_UINT64, &tail_lines,
2878c3bc407cSdh142964 	    'p', MDB_OPT_STR, &match_phy_path,
2879c3bc407cSdh142964 	    's', MDB_OPT_UINT64, &match_sas_address,
28801f81b464SDavid Hollister 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
2881c3bc407cSdh142964 	    NULL) != argc) {
2882c3bc407cSdh142964 		return (DCMD_USAGE);
2883c3bc407cSdh142964 	}
2884c3bc407cSdh142964 
2885c3bc407cSdh142964 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2886c3bc407cSdh142964 		NOREAD(pmcs_hw_t, addr);
2887c3bc407cSdh142964 		return (DCMD_ERR);
2888c3bc407cSdh142964 	}
2889c3bc407cSdh142964 
2890c3bc407cSdh142964 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2891c3bc407cSdh142964 		NOREAD(pmcs_hw_t, addr);
2892c3bc407cSdh142964 		return (DCMD_ERR);
2893c3bc407cSdh142964 	}
2894c3bc407cSdh142964 
2895c3bc407cSdh142964 	if (!(flags & DCMD_LOOP)) {
2896c3bc407cSdh142964 		return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance,
28971f81b464SDavid Hollister 		    tail_lines, match_phy_path, match_sas_address, verbose));
2898c3bc407cSdh142964 	} else if (flags & DCMD_LOOPFIRST) {
2899601c90f1SSrikanth, Ramana 		return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines,
29001f81b464SDavid Hollister 		    match_phy_path, match_sas_address, verbose));
2901c3bc407cSdh142964 	} else {
2902c3bc407cSdh142964 		return (DCMD_OK);
2903c3bc407cSdh142964 	}
2904c3bc407cSdh142964 }
2905c3bc407cSdh142964 
2906c3bc407cSdh142964 static int
29074c06356bSdh142964 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
29084c06356bSdh142964 {
29094c06356bSdh142964 	struct pmcs_hw		ss;
29104c06356bSdh142964 	uint_t			verbose = FALSE;
29114c06356bSdh142964 	uint_t			phy_info = FALSE;
29124c06356bSdh142964 	uint_t			hw_info = FALSE;
29134c06356bSdh142964 	uint_t			target_info = FALSE;
29144c06356bSdh142964 	uint_t			work_info = FALSE;
29154c06356bSdh142964 	uint_t			ic_info = FALSE;
29164c06356bSdh142964 	uint_t			iport_info = FALSE;
29174c06356bSdh142964 	uint_t			waitqs_info = FALSE;
29184c06356bSdh142964 	uint_t			ibq = FALSE;
29194c06356bSdh142964 	uint_t			obq = FALSE;
29204c06356bSdh142964 	uint_t			tgt_phy_count = FALSE;
292114d6cf0aSdh142964 	uint_t			compq = FALSE;
2922c3bc407cSdh142964 	uint_t			unconfigured = FALSE;
2923f7aef0b0SReed 	uint_t			damap_info = FALSE;
2924f7aef0b0SReed 	uint_t			dtc_info = FALSE;
2925658280b6SDavid Hollister 	uint_t			wserno = FALSE;
29261f81b464SDavid Hollister 	uint_t			fwlog = FALSE;
292765e70c04SDavid Hollister 	boolean_t		devid_filter = FALSE;
292865e70c04SDavid Hollister 	uintptr_t		pdevid;
292965e70c04SDavid Hollister 	uint32_t		devid;
29304c06356bSdh142964 	int			rv = DCMD_OK;
29314c06356bSdh142964 	void			*pmcs_state;
29324c06356bSdh142964 	char			*state_str;
29334c06356bSdh142964 	struct dev_info		dip;
2934f7aef0b0SReed 	per_iport_setting_t	pis;
29354c06356bSdh142964 
29364c06356bSdh142964 	if (!(flags & DCMD_ADDRSPEC)) {
29374c06356bSdh142964 		pmcs_state = NULL;
29384c06356bSdh142964 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
29394c06356bSdh142964 			mdb_warn("can't read pmcs_softc_state");
29404c06356bSdh142964 			return (DCMD_ERR);
29414c06356bSdh142964 		}
29424c06356bSdh142964 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv,
29434c06356bSdh142964 		    (uintptr_t)pmcs_state) == -1) {
29444c06356bSdh142964 			mdb_warn("mdb_pwalk_dcmd failed");
29454c06356bSdh142964 			return (DCMD_ERR);
29464c06356bSdh142964 		}
29474c06356bSdh142964 		return (DCMD_OK);
29484c06356bSdh142964 	}
29494c06356bSdh142964 
29504c06356bSdh142964 	if (mdb_getopts(argc, argv,
295114d6cf0aSdh142964 	    'c', MDB_OPT_SETBITS, TRUE, &compq,
2952f7aef0b0SReed 	    'd', MDB_OPT_SETBITS, TRUE, &dtc_info,
295365e70c04SDavid Hollister 	    'D', MDB_OPT_UINTPTR_SET, &devid_filter, &pdevid,
29541f81b464SDavid Hollister 	    'e', MDB_OPT_SETBITS, TRUE, &fwlog,
29554c06356bSdh142964 	    'h', MDB_OPT_SETBITS, TRUE, &hw_info,
29564c06356bSdh142964 	    'i', MDB_OPT_SETBITS, TRUE, &ic_info,
29574c06356bSdh142964 	    'I', MDB_OPT_SETBITS, TRUE, &iport_info,
2958f7aef0b0SReed 	    'm', MDB_OPT_SETBITS, TRUE, &damap_info,
29594c06356bSdh142964 	    'p', MDB_OPT_SETBITS, TRUE, &phy_info,
29604c06356bSdh142964 	    'q', MDB_OPT_SETBITS, TRUE, &ibq,
29614c06356bSdh142964 	    'Q', MDB_OPT_SETBITS, TRUE, &obq,
2962658280b6SDavid Hollister 	    's', MDB_OPT_SETBITS, TRUE, &wserno,
29634c06356bSdh142964 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
29644c06356bSdh142964 	    'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count,
2965c3bc407cSdh142964 	    'u', MDB_OPT_SETBITS, TRUE, &unconfigured,
29664c06356bSdh142964 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
29674c06356bSdh142964 	    'w', MDB_OPT_SETBITS, TRUE, &work_info,
29684c06356bSdh142964 	    'W', MDB_OPT_SETBITS, TRUE, &waitqs_info,
29694c06356bSdh142964 	    NULL) != argc)
29704c06356bSdh142964 		return (DCMD_USAGE);
29714c06356bSdh142964 
2972f7aef0b0SReed 	/*
2973f7aef0b0SReed 	 * The 'd' and 'm' options implicitly enable the 'I' option
2974f7aef0b0SReed 	 */
2975f7aef0b0SReed 	pis.pis_damap_info = damap_info;
2976f7aef0b0SReed 	pis.pis_dtc_info = dtc_info;
2977f7aef0b0SReed 	if (damap_info || dtc_info) {
2978f7aef0b0SReed 		iport_info = TRUE;
2979f7aef0b0SReed 	}
2980f7aef0b0SReed 
298165e70c04SDavid Hollister 	/*
298265e70c04SDavid Hollister 	 * The -D option is meaningless without -q and/or -Q, and implies
298365e70c04SDavid Hollister 	 * verbosity.
298465e70c04SDavid Hollister 	 */
298565e70c04SDavid Hollister 	if (devid_filter) {
298665e70c04SDavid Hollister 		devid = (uint64_t)pdevid & 0xffffffff;
298765e70c04SDavid Hollister 		if (!ibq && !obq) {
298865e70c04SDavid Hollister 			mdb_printf("-D requires either -q or -Q\n");
298965e70c04SDavid Hollister 			return (DCMD_USAGE);
299065e70c04SDavid Hollister 		}
299165e70c04SDavid Hollister 		if (devid > PMCS_DEVICE_ID_MASK) {
299265e70c04SDavid Hollister 			mdb_printf("Device ID invalid\n");
299365e70c04SDavid Hollister 			return (DCMD_USAGE);
299465e70c04SDavid Hollister 		}
299565e70c04SDavid Hollister 		verbose = TRUE;
299665e70c04SDavid Hollister 	}
299765e70c04SDavid Hollister 
29984c06356bSdh142964 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
29994c06356bSdh142964 		NOREAD(pmcs_hw_t, addr);
30004c06356bSdh142964 		return (DCMD_ERR);
30014c06356bSdh142964 	}
30024c06356bSdh142964 
30034c06356bSdh142964 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
30044c06356bSdh142964 		NOREAD(pmcs_hw_t, addr);
30054c06356bSdh142964 		return (DCMD_ERR);
30064c06356bSdh142964 	}
30074c06356bSdh142964 
30084c06356bSdh142964 	/* processing completed */
30094c06356bSdh142964 
30104c06356bSdh142964 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
30114c06356bSdh142964 	    (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info ||
3012c3bc407cSdh142964 	    work_info || waitqs_info || ibq || obq || tgt_phy_count || compq ||
30131f81b464SDavid Hollister 	    unconfigured || fwlog) {
30144c06356bSdh142964 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
30154c06356bSdh142964 			mdb_printf("\n");
30164c06356bSdh142964 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
30174c06356bSdh142964 		    "Address", "State", "Inst", "DIP");
30184c06356bSdh142964 		mdb_printf("================================="
30194c06356bSdh142964 		    "============================================\n");
30204c06356bSdh142964 	}
30214c06356bSdh142964 
30224c06356bSdh142964 	switch (ss.state) {
30234c06356bSdh142964 	case STATE_NIL:
30244c06356bSdh142964 		state_str = "Invalid";
30254c06356bSdh142964 		break;
30264c06356bSdh142964 	case STATE_PROBING:
30274c06356bSdh142964 		state_str = "Probing";
30284c06356bSdh142964 		break;
30294c06356bSdh142964 	case STATE_RUNNING:
30304c06356bSdh142964 		state_str = "Running";
30314c06356bSdh142964 		break;
30324c06356bSdh142964 	case STATE_UNPROBING:
30334c06356bSdh142964 		state_str = "Unprobing";
30344c06356bSdh142964 		break;
30354c06356bSdh142964 	case STATE_DEAD:
30364c06356bSdh142964 		state_str = "Dead";
30374c06356bSdh142964 		break;
30385c45adf0SJesse Butler 	case STATE_IN_RESET:
30395c45adf0SJesse Butler 		state_str = "In Reset";
30405c45adf0SJesse Butler 		break;
30414c06356bSdh142964 	}
30424c06356bSdh142964 
30434c06356bSdh142964 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
30444c06356bSdh142964 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
30454c06356bSdh142964 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
30464c06356bSdh142964 	mdb_printf("\n");
30474c06356bSdh142964 
30484c06356bSdh142964 	mdb_inc_indent(4);
30494c06356bSdh142964 
30504c06356bSdh142964 	if (waitqs_info)
30514c06356bSdh142964 		display_waitqs(ss, verbose);
30524c06356bSdh142964 
30534c06356bSdh142964 	if (hw_info)
30544c06356bSdh142964 		display_hwinfo(ss, verbose);
30554c06356bSdh142964 
30564c06356bSdh142964 	if (phy_info || tgt_phy_count)
30574c06356bSdh142964 		display_phys(ss, verbose, NULL, 0, tgt_phy_count);
30584c06356bSdh142964 
30594c06356bSdh142964 	if (target_info || tgt_phy_count)
30604c06356bSdh142964 		display_targets(ss, verbose, tgt_phy_count);
30614c06356bSdh142964 
3062658280b6SDavid Hollister 	if (work_info || wserno)
3063658280b6SDavid Hollister 		display_work(ss, verbose, wserno);
30644c06356bSdh142964 
30654c06356bSdh142964 	if (ic_info)
30664c06356bSdh142964 		display_ic(ss, verbose);
30674c06356bSdh142964 
30684c06356bSdh142964 	if (ibq)
306965e70c04SDavid Hollister 		display_inbound_queues(ss, devid, verbose);
30704c06356bSdh142964 
30714c06356bSdh142964 	if (obq)
307265e70c04SDavid Hollister 		display_outbound_queues(ss, devid, verbose);
30734c06356bSdh142964 
30744c06356bSdh142964 	if (iport_info)
3075f7aef0b0SReed 		display_iport(ss, addr, verbose, &pis);
30764c06356bSdh142964 
307714d6cf0aSdh142964 	if (compq)
307814d6cf0aSdh142964 		display_completion_queue(ss);
307914d6cf0aSdh142964 
3080c3bc407cSdh142964 	if (unconfigured)
3081c3bc407cSdh142964 		display_unconfigured_targets(addr);
3082c3bc407cSdh142964 
30831f81b464SDavid Hollister 	if (fwlog)
30841f81b464SDavid Hollister 		display_event_log(ss);
30851f81b464SDavid Hollister 
30864c06356bSdh142964 	mdb_dec_indent(4);
30874c06356bSdh142964 
30884c06356bSdh142964 	return (rv);
30894c06356bSdh142964 }
30904c06356bSdh142964 
30914c06356bSdh142964 void
30924c06356bSdh142964 pmcs_help()
30934c06356bSdh142964 {
30944c06356bSdh142964 	mdb_printf("Prints summary information about each pmcs instance.\n"
309514d6cf0aSdh142964 	    "    -c: Dump the completion queue\n"
3096f7aef0b0SReed 	    "    -d: Print per-iport information about device tree children\n"
309765e70c04SDavid Hollister 	    "    -D <device ID>: With -q/-Q, filter by device handle\n"
30981f81b464SDavid Hollister 	    "    -e: Display the in-memory firmware event log\n"
30994c06356bSdh142964 	    "    -h: Print more detailed hardware information\n"
31004c06356bSdh142964 	    "    -i: Print interrupt coalescing information\n"
31014c06356bSdh142964 	    "    -I: Print information about each iport\n"
3102f7aef0b0SReed 	    "    -m: Print per-iport information about DAM/damap state\n"
31034c06356bSdh142964 	    "    -p: Print information about each attached PHY\n"
31044c06356bSdh142964 	    "    -q: Dump inbound queues\n"
31054c06356bSdh142964 	    "    -Q: Dump outbound queues\n"
3106658280b6SDavid Hollister 	    "    -s: Dump all work structures sorted by serial number\n"
3107c3bc407cSdh142964 	    "    -t: Print information about each configured target\n"
31084c06356bSdh142964 	    "    -T: Print target and PHY count summary\n"
3109c3bc407cSdh142964 	    "    -u: Show SAS address of all unconfigured targets\n"
31104c06356bSdh142964 	    "    -w: Dump work structures\n"
31114c06356bSdh142964 	    "    -W: List pmcs cmds waiting on various queues\n"
31124c06356bSdh142964 	    "    -v: Add verbosity to the above options\n");
31134c06356bSdh142964 }
31144c06356bSdh142964 
311514d6cf0aSdh142964 void
3116c3bc407cSdh142964 pmcs_log_help()
3117c3bc407cSdh142964 {
3118c3bc407cSdh142964 	mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n"
3119601c90f1SSrikanth, Ramana 	    "    -l TAIL_LINES:          Dump the last TAIL_LINES messages\n"
3120c3bc407cSdh142964 	    "    -p PHY_PATH:            Dump messages matching PHY_PATH\n"
3121c3bc407cSdh142964 	    "    -s SAS_ADDRESS:         Dump messages matching SAS_ADDRESS\n\n"
3122c3bc407cSdh142964 	    "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n"
3123c3bc407cSdh142964 	    "       SAS_ADDRESS can be found with ::pmcs -t "
3124c3bc407cSdh142964 	    "(e.g. 5000c5000358c221)\n");
3125c3bc407cSdh142964 }
3126c3bc407cSdh142964 void
312714d6cf0aSdh142964 pmcs_tag_help()
312814d6cf0aSdh142964 {
312914d6cf0aSdh142964 	mdb_printf("Print all work structures by matching the tag.\n"
313014d6cf0aSdh142964 	    "    -i index:        Match tag index (0x000 - 0xfff)\n"
313114d6cf0aSdh142964 	    "    -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
313214d6cf0aSdh142964 	    "    -t tagtype:      Match tag type [NONE(1), CBACK(2), "
313314d6cf0aSdh142964 	    "WAIT(3)]\n");
313414d6cf0aSdh142964 }
313514d6cf0aSdh142964 
31364c06356bSdh142964 static const mdb_dcmd_t dcmds[] = {
313765e70c04SDavid Hollister 	{ "pmcs", "?[-cdehiImpQqtTuwWv] [-D <device ID>]",
313865e70c04SDavid Hollister 	    "print pmcs information", pmcs_dcmd, pmcs_help
31394c06356bSdh142964 	},
3140c3bc407cSdh142964 	{ "pmcs_log",
31411f81b464SDavid Hollister 	    "?[-v] [-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]",
3142c3bc407cSdh142964 	    "dump pmcs log file", pmcs_log, pmcs_log_help
3143c3bc407cSdh142964 	},
314414d6cf0aSdh142964 	{ "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
314514d6cf0aSdh142964 	    "Find work structures by tag type, serial number or index",
314614d6cf0aSdh142964 	    pmcs_tag, pmcs_tag_help
314714d6cf0aSdh142964 	},
31489719310aSDavid Hollister #ifndef _KMDB
31499719310aSDavid Hollister 	{ "pmcs_fwlog",
31509719310aSDavid Hollister 	    "?-o output_file",
31519719310aSDavid Hollister 	    "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL
31529719310aSDavid Hollister 	},
31539719310aSDavid Hollister #endif	/* _KMDB */
31544c06356bSdh142964 	{ NULL }
31554c06356bSdh142964 };
31564c06356bSdh142964 
31574c06356bSdh142964 static const mdb_walker_t walkers[] = {
31584c06356bSdh142964 	{ "pmcs_targets", "walk target structures",
31594c06356bSdh142964 		targets_walk_i, targets_walk_s, targets_walk_f },
31604c06356bSdh142964 	{ "pmcs_phys", "walk PHY structures",
31614c06356bSdh142964 		phy_walk_i, phy_walk_s, phy_walk_f },
31624c06356bSdh142964 	{ NULL }
31634c06356bSdh142964 };
31644c06356bSdh142964 
31654c06356bSdh142964 static const mdb_modinfo_t modinfo = {
31664c06356bSdh142964 	MDB_API_VERSION, dcmds, walkers
31674c06356bSdh142964 };
31684c06356bSdh142964 
31694c06356bSdh142964 const mdb_modinfo_t *
31704c06356bSdh142964 _mdb_init(void)
31714c06356bSdh142964 {
31724c06356bSdh142964 	return (&modinfo);
31734c06356bSdh142964 }
3174