xref: /titanic_51/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c (revision e762302f03f5529f83d98085b915143b08d3ae1b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <limits.h>
27 #include <sys/mdb_modapi.h>
28 #include <sys/sysinfo.h>
29 #include <sys/scsi/scsi.h>
30 #include <sys/scsi/adapters/pmcs/pmcs.h>
31 
32 #define	MDB_RD(a, b, c)	mdb_vread(a, b, (uintptr_t)c)
33 #define	NOREAD(a, b)	mdb_warn("could not read " #a " at 0x%p", b)
34 
35 static pmcs_hw_t ss;
36 static pmcs_xscsi_t **targets = NULL;
37 static int target_idx;
38 
39 static uint32_t	sas_phys, sata_phys, exp_phys, num_expanders, empty_phys;
40 
41 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp);
42 static void display_one_work(pmcwork_t *wp, int verbose, int idx);
43 
44 static void
45 print_sas_address(pmcs_phy_t *phy)
46 {
47 	int idx;
48 
49 	for (idx = 0; idx < 8; idx++) {
50 		mdb_printf("%02x", phy->sas_address[idx]);
51 	}
52 }
53 
54 /*ARGSUSED*/
55 static void
56 display_ic(struct pmcs_hw m, int verbose)
57 {
58 	int msec_per_tick;
59 
60 	if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
61 		mdb_warn("can't read msec_per_tick");
62 		msec_per_tick = 0;
63 	}
64 
65 	mdb_printf("\n");
66 	mdb_printf("Interrupt coalescing timer info\n");
67 	mdb_printf("-------------------------------\n");
68 	if (msec_per_tick == 0) {
69 		mdb_printf("Quantum                       : ?? ms\n");
70 	} else {
71 		mdb_printf("Quantum                       : %d ms\n",
72 		    m.io_intr_coal.quantum * msec_per_tick);
73 	}
74 	mdb_printf("Timer enabled                 : ");
75 	if (m.io_intr_coal.timer_on) {
76 		mdb_printf("Yes\n");
77 		mdb_printf("Coalescing timer value        : %d us\n",
78 		    m.io_intr_coal.intr_coal_timer);
79 	} else {
80 		mdb_printf("No\n");
81 	}
82 	mdb_printf("Total nsecs between interrupts: %ld\n",
83 	    m.io_intr_coal.nsecs_between_intrs);
84 	mdb_printf("Time of last I/O interrupt    : %ld\n",
85 	    m.io_intr_coal.last_io_comp);
86 	mdb_printf("Number of I/O interrupts      : %d\n",
87 	    m.io_intr_coal.num_intrs);
88 	mdb_printf("Number of I/O completions     : %d\n",
89 	    m.io_intr_coal.num_io_completions);
90 	mdb_printf("Max I/O completion interrupts : %d\n",
91 	    m.io_intr_coal.max_io_completions);
92 	mdb_printf("Measured ECHO int latency     : %d ns\n",
93 	    m.io_intr_coal.intr_latency);
94 	mdb_printf("Interrupt threshold           : %d\n",
95 	    m.io_intr_coal.intr_threshold);
96 }
97 
98 /*ARGSUSED*/
99 static int
100 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv)
101 {
102 	struct pmcs_phy		phy;
103 
104 	if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) !=
105 	    sizeof (struct pmcs_phy)) {
106 		return (DCMD_ERR);
107 	}
108 
109 	mdb_printf("%16p %2d\n", addr, phy.phynum);
110 
111 	return (0);
112 }
113 
114 /*ARGSUSED*/
115 static int
116 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv)
117 {
118 	struct pmcs_iport	iport;
119 	uintptr_t		list_addr;
120 	char			*ua_state;
121 	char			portid[4];
122 	char			unit_address[34];
123 
124 	if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) !=
125 	    sizeof (struct pmcs_iport)) {
126 		return (DCMD_ERR);
127 	}
128 
129 	if (mdb_readstr(unit_address, sizeof (unit_address),
130 	    (uintptr_t)(iport.ua)) == -1) {
131 		strncpy(unit_address, "Unset", sizeof (unit_address));
132 	}
133 
134 	if (iport.portid == 0xffff) {
135 		mdb_snprintf(portid, sizeof (portid), "%s", "-");
136 	} else {
137 		mdb_snprintf(portid, sizeof (portid), "%d", iport.portid);
138 	}
139 
140 	switch (iport.ua_state) {
141 	case UA_INACTIVE:
142 		ua_state = "Inactive";
143 		break;
144 	case UA_PEND_ACTIVATE:
145 		ua_state = "PendActivate";
146 		break;
147 	case UA_ACTIVE:
148 		ua_state = "Active";
149 		break;
150 	case UA_PEND_DEACTIVATE:
151 		ua_state = "PendDeactivate";
152 		break;
153 	default:
154 		ua_state = "Unknown";
155 	}
156 
157 	if (strlen(unit_address) < 3) {
158 		/* Standard iport unit address */
159 		mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State",
160 		    "PortID", "NumPhys", "DIP\n");
161 		mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr,
162 		    ua_state, portid, iport.nphy, iport.dip);
163 	} else {
164 		/* Temporary iport unit address */
165 		mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport",
166 		    "UA State", "PortID", "NumPhys", "DIP\n");
167 		mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr,
168 		    ua_state, portid, iport.nphy, iport.dip);
169 	}
170 
171 	if (iport.nphy > 0) {
172 		mdb_inc_indent(4);
173 		mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
174 		mdb_inc_indent(2);
175 		list_addr =
176 		    (uintptr_t)(addr + offsetof(struct pmcs_iport, phys));
177 		if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL,
178 		    list_addr) == -1) {
179 			mdb_warn("pmcs iport walk failed");
180 		}
181 		mdb_dec_indent(6);
182 		mdb_printf("\n");
183 	}
184 
185 	return (0);
186 }
187 
188 /*ARGSUSED*/
189 static void
190 display_iport(struct pmcs_hw m, uintptr_t addr, int verbose)
191 {
192 	uintptr_t	list_addr;
193 
194 	if (m.iports_attached) {
195 		mdb_printf("Iport information:\n");
196 		mdb_printf("-----------------\n");
197 	} else {
198 		mdb_printf("No Iports found.\n\n");
199 		return;
200 	}
201 
202 	list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports));
203 
204 	if (mdb_pwalk("list", pmcs_iport_walk_cb, NULL, list_addr) == -1) {
205 		mdb_warn("pmcs iport walk failed");
206 	}
207 
208 	mdb_printf("\n");
209 }
210 
211 static void
212 display_completion_queue(struct pmcs_hw ss)
213 {
214 	pmcs_iocomp_cb_t ccb, *ccbp;
215 	pmcwork_t work;
216 
217 	if (ss.iocomp_cb_head == NULL) {
218 		mdb_printf("Completion queue is empty.\n");
219 		return;
220 	}
221 
222 	ccbp = ss.iocomp_cb_head;
223 	mdb_printf("%8s %10s %20s %8s %8s O D\n",
224 	    "HTag", "State", "Phy Path", "Target", "Timer");
225 
226 	while (ccbp) {
227 		if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t),
228 		    (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) {
229 			mdb_warn("Unable to read completion queue entry\n");
230 			return;
231 		}
232 
233 		if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk)
234 		    != sizeof (pmcwork_t)) {
235 			mdb_warn("Unable to read work structure\n");
236 			return;
237 		}
238 
239 		/*
240 		 * Only print the work structure if it's still active.  If
241 		 * it's not, it's been completed since we started looking at
242 		 * it.
243 		 */
244 		if (work.state != PMCS_WORK_STATE_NIL) {
245 			display_one_work(&work, 0, 0);
246 		}
247 		ccbp = ccb.next;
248 	}
249 }
250 
251 /*ARGSUSED*/
252 static void
253 display_hwinfo(struct pmcs_hw m, int verbose)
254 {
255 	struct pmcs_hw	*mp = &m;
256 	char		*fwsupport;
257 
258 	switch (PMCS_FW_TYPE(mp)) {
259 	case PMCS_FW_TYPE_RELEASED:
260 		fwsupport = "Released";
261 		break;
262 	case PMCS_FW_TYPE_DEVELOPMENT:
263 		fwsupport = "Development";
264 		break;
265 	case PMCS_FW_TYPE_ALPHA:
266 		fwsupport = "Alpha";
267 		break;
268 	case PMCS_FW_TYPE_BETA:
269 		fwsupport = "Beta";
270 		break;
271 	default:
272 		fwsupport = "Special";
273 		break;
274 	}
275 
276 	mdb_printf("\nHardware information:\n");
277 	mdb_printf("---------------------\n");
278 
279 	mdb_printf("Chip revision:    %c\n", 'A' + m.chiprev);
280 	mdb_printf("SAS WWID:         %"PRIx64"\n", m.sas_wwns[0]);
281 	mdb_printf("Firmware version: %x.%x.%x (%s)\n",
282 	    PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp),
283 	    fwsupport);
284 
285 	mdb_printf("Number of PHYs:   %d\n", m.nphy);
286 	mdb_printf("Maximum commands: %d\n", m.max_cmd);
287 	mdb_printf("Maximum devices:  %d\n", m.max_dev);
288 	mdb_printf("I/O queue depth:  %d\n", m.ioq_depth);
289 	if (m.fwlog == 0) {
290 		mdb_printf("Firmware logging: Disabled\n");
291 	} else {
292 		mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog);
293 	}
294 }
295 
296 static void
297 display_targets(struct pmcs_hw m, int verbose, int totals_only)
298 {
299 	char		*dtype;
300 	pmcs_xscsi_t	xs;
301 	pmcs_phy_t	phy;
302 	uint16_t	max_dev, idx;
303 	uint32_t	sas_targets = 0, smp_targets = 0, sata_targets = 0;
304 
305 	max_dev = m.max_dev;
306 
307 	if (targets == NULL) {
308 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
309 	}
310 
311 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
312 		NOREAD(targets, m.targets);
313 		return;
314 	}
315 
316 	if (!totals_only) {
317 		mdb_printf("\nTarget information:\n");
318 		mdb_printf("---------------------------------------\n");
319 		mdb_printf("VTGT %-16s %-16s %-5s %8s %s", "SAS Address",
320 		    "PHY Address", "DType", "Active", "DS");
321 		mdb_printf("\n");
322 	}
323 
324 	for (idx = 0; idx < max_dev; idx++) {
325 		if (targets[idx] == NULL) {
326 			continue;
327 		}
328 
329 		if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) {
330 			NOREAD(pmcs_xscsi_t, targets[idx]);
331 			continue;
332 		}
333 
334 		/*
335 		 * It has to be one of new, assigned or dying to be of interest.
336 		 */
337 		if (xs.new == 0 && xs.assigned == 0 && xs.dying == 0) {
338 			continue;
339 		}
340 
341 		switch (xs.dtype) {
342 		case NOTHING:
343 			dtype = "None";
344 			break;
345 		case SATA:
346 			dtype = "SATA";
347 			sata_targets++;
348 			break;
349 		case SAS:
350 			dtype = "SAS";
351 			sas_targets++;
352 			break;
353 		case EXPANDER:
354 			dtype = "SMP";
355 			smp_targets++;
356 			break;
357 		}
358 
359 		if (totals_only) {
360 			continue;
361 		}
362 
363 		if (xs.phy) {
364 			if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) {
365 				NOREAD(pmcs_phy_t, xs.phy);
366 				continue;
367 			}
368 			mdb_printf("%4d ", idx);
369 			print_sas_address(&phy);
370 			mdb_printf(" %16p", xs.phy);
371 		} else {
372 			mdb_printf("%4d %16s", idx, "<no phy avail>");
373 		}
374 		mdb_printf(" %5s", dtype);
375 		mdb_printf(" %8d", xs.actv_cnt);
376 		mdb_printf(" %2d", xs.dev_state);
377 
378 		if (verbose) {
379 			if (xs.new) {
380 				mdb_printf(" new");
381 			} else if (xs.dying) {
382 				mdb_printf(" dying");
383 			} else if (xs.assigned) {
384 				mdb_printf(" assigned");
385 			}
386 			if (xs.draining) {
387 				mdb_printf(" draining");
388 			}
389 			if (xs.reset_wait) {
390 				mdb_printf(" reset_wait");
391 			}
392 			if (xs.resetting) {
393 				mdb_printf(" resetting");
394 			}
395 			if (xs.recover_wait) {
396 				mdb_printf(" recover_wait");
397 			}
398 			if (xs.recovering) {
399 				mdb_printf(" recovering");
400 			}
401 			if (xs.event_recovery) {
402 				mdb_printf(" event recovery");
403 			}
404 			if (xs.special_running) {
405 				mdb_printf(" special_active");
406 			}
407 			if (xs.ncq) {
408 				mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
409 				    xs.tagmap, xs.qdepth);
410 			} else if (xs.pio) {
411 				mdb_printf(" pio");
412 			}
413 		}
414 
415 		mdb_printf("\n");
416 	}
417 
418 	if (!totals_only) {
419 		mdb_printf("\n");
420 	}
421 
422 	mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
423 	    "Configured targets:", (sas_targets + sata_targets + smp_targets),
424 	    sas_targets, sata_targets, smp_targets);
425 }
426 
427 static char *
428 work_state_to_string(uint32_t state)
429 {
430 	char *state_string;
431 
432 	switch (state) {
433 	case PMCS_WORK_STATE_NIL:
434 		state_string = "Free";
435 		break;
436 	case PMCS_WORK_STATE_READY:
437 		state_string = "Ready";
438 		break;
439 	case PMCS_WORK_STATE_ONCHIP:
440 		state_string = "On Chip";
441 		break;
442 	case PMCS_WORK_STATE_INTR:
443 		state_string = "In Intr";
444 		break;
445 	case PMCS_WORK_STATE_IOCOMPQ:
446 		state_string = "I/O Comp";
447 		break;
448 	case PMCS_WORK_STATE_ABORTED:
449 		state_string = "I/O Aborted";
450 		break;
451 	case PMCS_WORK_STATE_TIMED_OUT:
452 		state_string = "I/O Timed Out";
453 		break;
454 	default:
455 		state_string = "INVALID";
456 		break;
457 	}
458 
459 	return (state_string);
460 }
461 
462 static void
463 display_one_work(pmcwork_t *wp, int verbose, int idx)
464 {
465 	char		*state, *last_state;
466 	char		*path;
467 	pmcs_xscsi_t	xs;
468 	pmcs_phy_t	phy;
469 	int		tgt;
470 
471 	state = work_state_to_string(wp->state);
472 	last_state = work_state_to_string(wp->last_state);
473 
474 	if (wp->ssp_event && wp->ssp_event != 0xffffffff) {
475 		mdb_printf("SSP event 0x%x", wp->ssp_event);
476 	}
477 
478 	tgt = -1;
479 	if (wp->xp) {
480 		if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) {
481 			NOREAD(pmcs_xscsi_t, wp->xp);
482 		} else {
483 			tgt = xs.target_num;
484 		}
485 	}
486 	if (wp->phy) {
487 		if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) {
488 			NOREAD(pmcs_phy_t, wp->phy);
489 		}
490 		path = phy.path;
491 	} else {
492 		path = "N/A";
493 	}
494 
495 	if (verbose) {
496 		mdb_printf("%4d ", idx);
497 	}
498 	if (tgt == -1) {
499 		mdb_printf("%08x %10s %20s      N/A %8u %1d %1d ",
500 		    wp->htag, state, path, wp->timer,
501 		    wp->onwire, wp->dead);
502 	} else {
503 		mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
504 		    wp->htag, state, path, tgt, wp->timer,
505 		    wp->onwire, wp->dead);
506 	}
507 	if (verbose) {
508 		mdb_printf("%08x %10s 0x%016p 0x%016p\n",
509 		    wp->last_htag, last_state, wp->last_phy, wp->last_xp);
510 	} else {
511 		mdb_printf("\n");
512 	}
513 }
514 
515 static void
516 display_work(struct pmcs_hw m, int verbose)
517 {
518 	int		idx;
519 	boolean_t	header_printed = B_FALSE;
520 	pmcwork_t	work, *wp = &work;
521 	uintptr_t	_wp;
522 
523 	mdb_printf("\nActive Work structure information:\n");
524 	mdb_printf("----------------------------------\n");
525 
526 	_wp = (uintptr_t)m.work;
527 
528 	for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
529 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
530 			NOREAD(pmcwork_t, _wp);
531 			continue;
532 		}
533 
534 		if (!verbose && (wp->htag == PMCS_TAG_TYPE_FREE)) {
535 			continue;
536 		}
537 
538 		if (header_printed == B_FALSE) {
539 			if (verbose) {
540 				mdb_printf("%4s ", "Idx");
541 			}
542 			mdb_printf("%8s %10s %20s %8s %8s O D ",
543 			    "HTag", "State", "Phy Path", "Target", "Timer");
544 			if (verbose) {
545 				mdb_printf("%8s %10s %18s %18s\n", "LastHTAG",
546 				    "LastState", "LastPHY", "LastTgt");
547 			} else {
548 				mdb_printf("\n");
549 			}
550 			header_printed = B_TRUE;
551 		}
552 
553 		display_one_work(wp, verbose, idx);
554 	}
555 }
556 
557 static void
558 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose)
559 {
560 	int cdb_size, idx;
561 	struct scsi_pkt pkt;
562 	uchar_t cdb[256];
563 
564 	if (printhdr) {
565 		if (verbose) {
566 			mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
567 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
568 		} else {
569 			mdb_printf("%16s %16s %16s %8s %s\n", "Command",
570 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
571 		}
572 	}
573 
574 	mdb_printf("%16p %16p %16p %08x %08x ",
575 	    kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag);
576 
577 	/*
578 	 * If we're printing verbose, dump the CDB as well.
579 	 */
580 	if (verbose) {
581 		if (sp->cmd_pkt) {
582 			if (mdb_vread(&pkt, sizeof (struct scsi_pkt),
583 			    (uintptr_t)sp->cmd_pkt) !=
584 			    sizeof (struct scsi_pkt)) {
585 				mdb_warn("Unable to read SCSI pkt\n");
586 				return;
587 			}
588 			cdb_size = pkt.pkt_cdblen;
589 			if (mdb_vread(&cdb[0], cdb_size,
590 			    (uintptr_t)pkt.pkt_cdbp) != cdb_size) {
591 				mdb_warn("Unable to read CDB\n");
592 				return;
593 			}
594 
595 			for (idx = 0; idx < cdb_size; idx++) {
596 				mdb_printf("%02x ", cdb[idx]);
597 			}
598 		} else {
599 			mdb_printf("N/A");
600 		}
601 
602 		mdb_printf("\n");
603 	} else {
604 		mdb_printf("\n");
605 	}
606 }
607 
608 /*ARGSUSED1*/
609 static void
610 display_waitqs(struct pmcs_hw m, int verbose)
611 {
612 	pmcs_cmd_t	*sp, s;
613 	pmcs_xscsi_t	xs;
614 	int		first, i;
615 	int		max_dev = m.max_dev;
616 
617 	sp = m.dq.stqh_first;
618 	first = 1;
619 	while (sp) {
620 		if (first) {
621 			mdb_printf("\nDead Command Queue:\n");
622 			mdb_printf("---------------------------\n");
623 		}
624 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
625 			NOREAD(pmcs_cmd_t, sp);
626 			break;
627 		}
628 		print_spcmd(&s, sp, first, verbose);
629 		sp = s.cmd_next.stqe_next;
630 		first = 0;
631 	}
632 
633 	sp = m.cq.stqh_first;
634 	first = 1;
635 	while (sp) {
636 		if (first) {
637 			mdb_printf("\nCompletion Command Queue:\n");
638 			mdb_printf("---------------------------\n");
639 		}
640 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
641 			NOREAD(pmcs_cmd_t, sp);
642 			break;
643 		}
644 		print_spcmd(&s, sp, first, verbose);
645 		sp = s.cmd_next.stqe_next;
646 		first = 0;
647 	}
648 
649 
650 	if (targets == NULL) {
651 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
652 	}
653 
654 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
655 		NOREAD(targets, m.targets);
656 		return;
657 	}
658 
659 	for (i = 0; i < max_dev; i++) {
660 		if (targets[i] == NULL) {
661 			continue;
662 		}
663 		if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) {
664 			NOREAD(pmcs_xscsi_t, targets[i]);
665 			continue;
666 		}
667 		sp = xs.wq.stqh_first;
668 		first = 1;
669 		while (sp) {
670 			if (first) {
671 				mdb_printf("\nTarget %u Wait Queue:\n",
672 				    xs.target_num);
673 				mdb_printf("---------------------------\n");
674 			}
675 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
676 				NOREAD(pmcs_cmd_t, sp);
677 				break;
678 			}
679 			print_spcmd(&s, sp, first, verbose);
680 			sp = s.cmd_next.stqe_next;
681 			first = 0;
682 		}
683 		sp = xs.aq.stqh_first;
684 		first = 1;
685 		while (sp) {
686 			if (first) {
687 				mdb_printf("\nTarget %u Active Queue:\n",
688 				    xs.target_num);
689 				mdb_printf("---------------------------\n");
690 			}
691 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
692 				NOREAD(pmcs_cmd_t, sp);
693 				break;
694 			}
695 			print_spcmd(&s, sp, first, verbose);
696 			sp = s.cmd_next.stqe_next;
697 			first = 0;
698 		}
699 		sp = xs.sq.stqh_first;
700 		first = 1;
701 		while (sp) {
702 			if (first) {
703 				mdb_printf("\nTarget %u Special Queue:\n",
704 				    xs.target_num);
705 				mdb_printf("---------------------------\n");
706 			}
707 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
708 				NOREAD(pmcs_cmd_t, sp);
709 				break;
710 			}
711 			print_spcmd(&s, sp, first, verbose);
712 			sp = s.cmd_next.stqe_next;
713 			first = 0;
714 		}
715 	}
716 }
717 
718 static char *
719 ibq_type(int qnum)
720 {
721 	if (qnum < 0 || qnum >= PMCS_NIQ) {
722 		return ("UNKNOWN");
723 	}
724 
725 	if (qnum < PMCS_IQ_OTHER) {
726 		return ("I/O");
727 	}
728 
729 	return ("Other");
730 }
731 
732 static char *
733 obq_type(int qnum)
734 {
735 	switch (qnum) {
736 	case PMCS_OQ_IODONE:
737 		return ("I/O");
738 		break;
739 	case PMCS_OQ_GENERAL:
740 		return ("General");
741 		break;
742 	case PMCS_OQ_EVENTS:
743 		return ("Events");
744 		break;
745 	default:
746 		return ("UNKNOWN");
747 	}
748 }
749 
750 static char *
751 iomb_cat(uint32_t cat)
752 {
753 	switch (cat) {
754 	case PMCS_IOMB_CAT_NET:
755 		return ("NET");
756 		break;
757 	case PMCS_IOMB_CAT_FC:
758 		return ("FC");
759 		break;
760 	case PMCS_IOMB_CAT_SAS:
761 		return ("SAS");
762 		break;
763 	case PMCS_IOMB_CAT_SCSI:
764 		return ("SCSI");
765 		break;
766 	default:
767 		return ("???");
768 	}
769 }
770 
771 static char *
772 inbound_iomb_opcode(uint32_t opcode)
773 {
774 	switch (opcode) {
775 	case PMCIN_ECHO:
776 		return ("ECHO");
777 		break;
778 	case PMCIN_GET_INFO:
779 		return ("GET_INFO");
780 		break;
781 	case PMCIN_GET_VPD:
782 		return ("GET_VPD");
783 		break;
784 	case PMCIN_PHY_START:
785 		return ("PHY_START");
786 		break;
787 	case PMCIN_PHY_STOP:
788 		return ("PHY_STOP");
789 		break;
790 	case PMCIN_SSP_INI_IO_START:
791 		return ("INI_IO_START");
792 		break;
793 	case PMCIN_SSP_INI_TM_START:
794 		return ("INI_TM_START");
795 		break;
796 	case PMCIN_SSP_INI_EXT_IO_START:
797 		return ("INI_EXT_IO_START");
798 		break;
799 	case PMCIN_DEVICE_HANDLE_ACCEPT:
800 		return ("DEVICE_HANDLE_ACCEPT");
801 		break;
802 	case PMCIN_SSP_TGT_IO_START:
803 		return ("TGT_IO_START");
804 		break;
805 	case PMCIN_SSP_TGT_RESPONSE_START:
806 		return ("TGT_RESPONSE_START");
807 		break;
808 	case PMCIN_SSP_INI_EDC_EXT_IO_START:
809 		return ("INI_EDC_EXT_IO_START");
810 		break;
811 	case PMCIN_SSP_INI_EDC_EXT_IO_START1:
812 		return ("INI_EDC_EXT_IO_START1");
813 		break;
814 	case PMCIN_SSP_TGT_EDC_IO_START:
815 		return ("TGT_EDC_IO_START");
816 		break;
817 	case PMCIN_SSP_ABORT:
818 		return ("SSP_ABORT");
819 		break;
820 	case PMCIN_DEREGISTER_DEVICE_HANDLE:
821 		return ("DEREGISTER_DEVICE_HANDLE");
822 		break;
823 	case PMCIN_GET_DEVICE_HANDLE:
824 		return ("GET_DEVICE_HANDLE");
825 		break;
826 	case PMCIN_SMP_REQUEST:
827 		return ("SMP_REQUEST");
828 		break;
829 	case PMCIN_SMP_RESPONSE:
830 		return ("SMP_RESPONSE");
831 		break;
832 	case PMCIN_SMP_ABORT:
833 		return ("SMP_ABORT");
834 		break;
835 	case PMCIN_ASSISTED_DISCOVERY:
836 		return ("ASSISTED_DISCOVERY");
837 		break;
838 	case PMCIN_REGISTER_DEVICE:
839 		return ("REGISTER_DEVICE");
840 		break;
841 	case PMCIN_SATA_HOST_IO_START:
842 		return ("SATA_HOST_IO_START");
843 		break;
844 	case PMCIN_SATA_ABORT:
845 		return ("SATA_ABORT");
846 		break;
847 	case PMCIN_LOCAL_PHY_CONTROL:
848 		return ("LOCAL_PHY_CONTROL");
849 		break;
850 	case PMCIN_GET_DEVICE_INFO:
851 		return ("GET_DEVICE_INFO");
852 		break;
853 	case PMCIN_TWI:
854 		return ("TWI");
855 		break;
856 	case PMCIN_FW_FLASH_UPDATE:
857 		return ("FW_FLASH_UPDATE");
858 		break;
859 	case PMCIN_SET_VPD:
860 		return ("SET_VPD");
861 		break;
862 	case PMCIN_GPIO:
863 		return ("GPIO");
864 		break;
865 	case PMCIN_SAS_DIAG_MODE_START_END:
866 		return ("SAS_DIAG_MODE_START_END");
867 		break;
868 	case PMCIN_SAS_DIAG_EXECUTE:
869 		return ("SAS_DIAG_EXECUTE");
870 		break;
871 	case PMCIN_SAW_HW_EVENT_ACK:
872 		return ("SAS_HW_EVENT_ACK");
873 		break;
874 	case PMCIN_GET_TIME_STAMP:
875 		return ("GET_TIME_STAMP");
876 		break;
877 	case PMCIN_PORT_CONTROL:
878 		return ("PORT_CONTROL");
879 		break;
880 	case PMCIN_GET_NVMD_DATA:
881 		return ("GET_NVMD_DATA");
882 		break;
883 	case PMCIN_SET_NVMD_DATA:
884 		return ("SET_NVMD_DATA");
885 		break;
886 	case PMCIN_SET_DEVICE_STATE:
887 		return ("SET_DEVICE_STATE");
888 		break;
889 	case PMCIN_GET_DEVICE_STATE:
890 		return ("GET_DEVICE_STATE");
891 		break;
892 	default:
893 		return ("UNKNOWN");
894 		break;
895 	}
896 }
897 
898 static char *
899 outbound_iomb_opcode(uint32_t opcode)
900 {
901 	switch (opcode) {
902 	case PMCOUT_ECHO:
903 		return ("ECHO");
904 		break;
905 	case PMCOUT_GET_INFO:
906 		return ("GET_INFO");
907 		break;
908 	case PMCOUT_GET_VPD:
909 		return ("GET_VPD");
910 		break;
911 	case PMCOUT_SAS_HW_EVENT:
912 		return ("SAS_HW_EVENT");
913 		break;
914 	case PMCOUT_SSP_COMPLETION:
915 		return ("SSP_COMPLETION");
916 		break;
917 	case PMCOUT_SMP_COMPLETION:
918 		return ("SMP_COMPLETION");
919 		break;
920 	case PMCOUT_LOCAL_PHY_CONTROL:
921 		return ("LOCAL_PHY_CONTROL");
922 		break;
923 	case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT:
924 		return ("SAS_ASSISTED_DISCOVERY_SENT");
925 		break;
926 	case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT:
927 		return ("SATA_ASSISTED_DISCOVERY_SENT");
928 		break;
929 	case PMCOUT_DEVICE_REGISTRATION:
930 		return ("DEVICE_REGISTRATION");
931 		break;
932 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
933 		return ("DEREGISTER_DEVICE_HANDLE");
934 		break;
935 	case PMCOUT_GET_DEVICE_HANDLE:
936 		return ("GET_DEVICE_HANDLE");
937 		break;
938 	case PMCOUT_SATA_COMPLETION:
939 		return ("SATA_COMPLETION");
940 		break;
941 	case PMCOUT_SATA_EVENT:
942 		return ("SATA_EVENT");
943 		break;
944 	case PMCOUT_SSP_EVENT:
945 		return ("SSP_EVENT");
946 		break;
947 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
948 		return ("DEVICE_HANDLE_ARRIVED");
949 		break;
950 	case PMCOUT_SMP_REQUEST_RECEIVED:
951 		return ("SMP_REQUEST_RECEIVED");
952 		break;
953 	case PMCOUT_SSP_REQUEST_RECEIVED:
954 		return ("SSP_REQUEST_RECEIVED");
955 		break;
956 	case PMCOUT_DEVICE_INFO:
957 		return ("DEVICE_INFO");
958 		break;
959 	case PMCOUT_FW_FLASH_UPDATE:
960 		return ("FW_FLASH_UPDATE");
961 		break;
962 	case PMCOUT_SET_VPD:
963 		return ("SET_VPD");
964 		break;
965 	case PMCOUT_GPIO:
966 		return ("GPIO");
967 		break;
968 	case PMCOUT_GPIO_EVENT:
969 		return ("GPIO_EVENT");
970 		break;
971 	case PMCOUT_GENERAL_EVENT:
972 		return ("GENERAL_EVENT");
973 		break;
974 	case PMCOUT_TWI:
975 		return ("TWI");
976 		break;
977 	case PMCOUT_SSP_ABORT:
978 		return ("SSP_ABORT");
979 		break;
980 	case PMCOUT_SATA_ABORT:
981 		return ("SATA_ABORT");
982 		break;
983 	case PMCOUT_SAS_DIAG_MODE_START_END:
984 		return ("SAS_DIAG_MODE_START_END");
985 		break;
986 	case PMCOUT_SAS_DIAG_EXECUTE:
987 		return ("SAS_DIAG_EXECUTE");
988 		break;
989 	case PMCOUT_GET_TIME_STAMP:
990 		return ("GET_TIME_STAMP");
991 		break;
992 	case PMCOUT_SAS_HW_EVENT_ACK_ACK:
993 		return ("SAS_HW_EVENT_ACK_ACK");
994 		break;
995 	case PMCOUT_PORT_CONTROL:
996 		return ("PORT_CONTROL");
997 		break;
998 	case PMCOUT_SKIP_ENTRIES:
999 		return ("SKIP_ENTRIES");
1000 		break;
1001 	case PMCOUT_SMP_ABORT:
1002 		return ("SMP_ABORT");
1003 		break;
1004 	case PMCOUT_GET_NVMD_DATA:
1005 		return ("GET_NVMD_DATA");
1006 		break;
1007 	case PMCOUT_SET_NVMD_DATA:
1008 		return ("SET_NVMD_DATA");
1009 		break;
1010 	case PMCOUT_DEVICE_HANDLE_REMOVED:
1011 		return ("DEVICE_HANDLE_REMOVED");
1012 		break;
1013 	case PMCOUT_SET_DEVICE_STATE:
1014 		return ("SET_DEVICE_STATE");
1015 		break;
1016 	case PMCOUT_GET_DEVICE_STATE:
1017 		return ("GET_DEVICE_STATE");
1018 		break;
1019 	case PMCOUT_SET_DEVICE_INFO:
1020 		return ("SET_DEVICE_INFO");
1021 		break;
1022 	default:
1023 		return ("UNKNOWN");
1024 		break;
1025 	}
1026 }
1027 
1028 static void
1029 dump_one_qentry_outbound(uint32_t *qentryp, int idx)
1030 {
1031 	int qeidx;
1032 	uint32_t word0 = LE_32(*qentryp);
1033 
1034 	mdb_printf("Entry #%02d\n", idx);
1035 	mdb_inc_indent(2);
1036 
1037 	mdb_printf("Header: 0x%08x (", word0);
1038 	if (word0 & PMCS_IOMB_VALID) {
1039 		mdb_printf("VALID, ");
1040 	}
1041 	if (word0 & PMCS_IOMB_HIPRI) {
1042 		mdb_printf("HIPRI, ");
1043 	}
1044 	mdb_printf("OBID=%d, ",
1045 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
1046 	mdb_printf("CAT=%s, ",
1047 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
1048 	mdb_printf("OPCODE=%s",
1049 	    outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
1050 	mdb_printf(")\n");
1051 
1052 	mdb_printf("Remaining Payload:\n");
1053 
1054 	mdb_inc_indent(2);
1055 	for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
1056 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
1057 	}
1058 	mdb_printf("\n");
1059 	mdb_dec_indent(4);
1060 }
1061 
1062 static void
1063 display_outbound_queues(struct pmcs_hw ss, uint_t verbose)
1064 {
1065 	int		idx, qidx;
1066 	uintptr_t	obqp;
1067 	uint32_t	*cip;
1068 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
1069 	uint32_t	last_consumed, oqpi;
1070 
1071 	mdb_printf("\n");
1072 	mdb_printf("Outbound Queues\n");
1073 	mdb_printf("---------------\n");
1074 
1075 	mdb_inc_indent(2);
1076 
1077 	for (qidx = 0; qidx < PMCS_NOQ; qidx++) {
1078 		obqp = (uintptr_t)ss.oqp[qidx];
1079 
1080 		if (obqp == NULL) {
1081 			mdb_printf("No outbound queue ptr for queue #%d\n",
1082 			    qidx);
1083 			continue;
1084 		}
1085 
1086 		mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx,
1087 		    obq_type(qidx));
1088 		/*
1089 		 * Chip is the producer, so read the actual producer index
1090 		 * and not the driver's version
1091 		 */
1092 		cip = (uint32_t *)((void *)ss.cip);
1093 		if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET +
1094 		    (qidx * 4)) == -1) {
1095 			mdb_warn("Couldn't read oqpi\n");
1096 			break;
1097 		}
1098 
1099 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
1100 		    LE_32(oqpi), ss.oqci[qidx]);
1101 		mdb_inc_indent(2);
1102 
1103 		if (ss.oqci[qidx] == 0) {
1104 			last_consumed = ss.ioq_depth - 1;
1105 		} else {
1106 			last_consumed = ss.oqci[qidx] - 1;
1107 		}
1108 
1109 
1110 		if (!verbose) {
1111 			mdb_printf("Last processed entry:\n");
1112 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1113 			    (obqp + (PMCS_QENTRY_SIZE * last_consumed)))
1114 			    == -1) {
1115 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1116 				    (obqp + (PMCS_QENTRY_SIZE *
1117 				    last_consumed)));
1118 				break;
1119 			}
1120 			dump_one_qentry_outbound(qentryp, last_consumed);
1121 			mdb_printf("\n");
1122 			mdb_dec_indent(2);
1123 			continue;
1124 		}
1125 
1126 		for (idx = 0; idx < ss.ioq_depth; idx++) {
1127 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1128 			    (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
1129 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1130 				    (obqp + (PMCS_QENTRY_SIZE * idx)));
1131 				break;
1132 			}
1133 			dump_one_qentry_outbound(qentryp, idx);
1134 		}
1135 
1136 		mdb_printf("\n");
1137 		mdb_dec_indent(2);
1138 	}
1139 
1140 	mdb_dec_indent(2);
1141 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
1142 }
1143 
1144 static void
1145 dump_one_qentry_inbound(uint32_t *qentryp, int idx)
1146 {
1147 	int qeidx;
1148 	uint32_t word0 = LE_32(*qentryp);
1149 
1150 	mdb_printf("Entry #%02d\n", idx);
1151 	mdb_inc_indent(2);
1152 
1153 	mdb_printf("Header: 0x%08x (", word0);
1154 	if (word0 & PMCS_IOMB_VALID) {
1155 		mdb_printf("VALID, ");
1156 	}
1157 	if (word0 & PMCS_IOMB_HIPRI) {
1158 		mdb_printf("HIPRI, ");
1159 	}
1160 	mdb_printf("OBID=%d, ",
1161 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
1162 	mdb_printf("CAT=%s, ",
1163 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
1164 	mdb_printf("OPCODE=%s",
1165 	    inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
1166 	mdb_printf(")\n");
1167 
1168 	mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1)));
1169 	mdb_printf("Remaining Payload:\n");
1170 
1171 	mdb_inc_indent(2);
1172 	for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
1173 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
1174 	}
1175 	mdb_printf("\n");
1176 	mdb_dec_indent(4);
1177 }
1178 
1179 static void
1180 display_inbound_queues(struct pmcs_hw ss, uint_t verbose)
1181 {
1182 	int		idx, qidx, iqci, last_consumed;
1183 	uintptr_t	ibqp;
1184 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
1185 	uint32_t	*cip;
1186 
1187 	mdb_printf("\n");
1188 	mdb_printf("Inbound Queues\n");
1189 	mdb_printf("--------------\n");
1190 
1191 	mdb_inc_indent(2);
1192 
1193 	for (qidx = 0; qidx < PMCS_NIQ; qidx++) {
1194 		ibqp = (uintptr_t)ss.iqp[qidx];
1195 
1196 		if (ibqp == NULL) {
1197 			mdb_printf("No inbound queue ptr for queue #%d\n",
1198 			    qidx);
1199 			continue;
1200 		}
1201 
1202 		mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx,
1203 		    ibq_type(qidx));
1204 
1205 		cip = (uint32_t *)((void *)ss.cip);
1206 		if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) {
1207 			mdb_warn("Couldn't read iqci\n");
1208 			break;
1209 		}
1210 		iqci = LE_32(iqci);
1211 
1212 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
1213 		    ss.shadow_iqpi[qidx], iqci);
1214 		mdb_inc_indent(2);
1215 
1216 		if (iqci == 0) {
1217 			last_consumed = ss.ioq_depth - 1;
1218 		} else {
1219 			last_consumed = iqci - 1;
1220 		}
1221 
1222 		if (!verbose) {
1223 			mdb_printf("Last processed entry:\n");
1224 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1225 			    (ibqp + (PMCS_QENTRY_SIZE * last_consumed)))
1226 			    == -1) {
1227 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1228 				    (ibqp + (PMCS_QENTRY_SIZE *
1229 				    last_consumed)));
1230 				break;
1231 			}
1232 			dump_one_qentry_inbound(qentryp, last_consumed);
1233 			mdb_printf("\n");
1234 			mdb_dec_indent(2);
1235 			continue;
1236 		}
1237 
1238 		for (idx = 0; idx < ss.ioq_depth; idx++) {
1239 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1240 			    (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
1241 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1242 				    (ibqp + (PMCS_QENTRY_SIZE * idx)));
1243 				break;
1244 			}
1245 			dump_one_qentry_inbound(qentryp, idx);
1246 		}
1247 
1248 		mdb_printf("\n");
1249 		mdb_dec_indent(2);
1250 	}
1251 
1252 	mdb_dec_indent(2);
1253 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
1254 }
1255 
1256 static void
1257 display_phy(struct pmcs_phy phy, int verbose, int totals_only)
1258 {
1259 	char		*dtype, *speed;
1260 	char		*yes = "Yes";
1261 	char		*no = "No";
1262 	char		*cfgd = no;
1263 	char		*apend = no;
1264 	char		*asent = no;
1265 	char		*dead = no;
1266 	char		*changed = no;
1267 
1268 	switch (phy.dtype) {
1269 	case NOTHING:
1270 		dtype = "None";
1271 		break;
1272 	case SATA:
1273 		dtype = "SATA";
1274 		if (phy.configured) {
1275 			++sata_phys;
1276 		}
1277 		break;
1278 	case SAS:
1279 		dtype = "SAS";
1280 		if (phy.configured) {
1281 			++sas_phys;
1282 		}
1283 		break;
1284 	case EXPANDER:
1285 		dtype = "EXP";
1286 		if (phy.configured) {
1287 			++exp_phys;
1288 		}
1289 		break;
1290 	}
1291 
1292 	if (phy.dtype == NOTHING) {
1293 		empty_phys++;
1294 	} else if ((phy.dtype == EXPANDER) && phy.configured) {
1295 		num_expanders++;
1296 	}
1297 
1298 	if (totals_only) {
1299 		return;
1300 	}
1301 
1302 	switch (phy.link_rate) {
1303 	case SAS_LINK_RATE_1_5GBIT:
1304 		speed = "1.5Gb/s";
1305 		break;
1306 	case SAS_LINK_RATE_3GBIT:
1307 		speed = "3 Gb/s";
1308 		break;
1309 	case SAS_LINK_RATE_6GBIT:
1310 		speed = "6 Gb/s";
1311 		break;
1312 	default:
1313 		speed = "N/A";
1314 		break;
1315 	}
1316 
1317 	if ((phy.dtype != NOTHING) || verbose) {
1318 		print_sas_address(&phy);
1319 
1320 		if (phy.device_id != PMCS_INVALID_DEVICE_ID) {
1321 			mdb_printf(" %3d %4d %6s %4s ",
1322 			    phy.device_id, phy.phynum, speed, dtype);
1323 		} else {
1324 			mdb_printf(" N/A %4d %6s %4s ",
1325 			    phy.phynum, speed, dtype);
1326 		}
1327 
1328 		if (verbose) {
1329 			if (phy.abort_sent) {
1330 				asent = yes;
1331 			}
1332 			if (phy.abort_pending) {
1333 				apend = yes;
1334 			}
1335 			if (phy.configured) {
1336 				cfgd = yes;
1337 			}
1338 			if (phy.dead) {
1339 				dead = yes;
1340 			}
1341 			if (phy.changed) {
1342 				changed = yes;
1343 			}
1344 
1345 			mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d "
1346 			    "0x%p ", cfgd, apend, asent,
1347 			    changed, dead, phy.ref_count, phy.phy_lock);
1348 		}
1349 
1350 		mdb_printf("Path: %s\n", phy.path);
1351 	}
1352 }
1353 
1354 static void
1355 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level,
1356     int totals_only)
1357 {
1358 	pmcs_phy_t	phy;
1359 	pmcs_phy_t	*pphy = parent;
1360 
1361 	mdb_inc_indent(3);
1362 
1363 	if (parent == NULL) {
1364 		pphy = (pmcs_phy_t *)ss.root_phys;
1365 	} else {
1366 		pphy = (pmcs_phy_t *)parent;
1367 	}
1368 
1369 	if (level == 0) {
1370 		sas_phys = 0;
1371 		sata_phys = 0;
1372 		exp_phys = 0;
1373 		num_expanders = 0;
1374 		empty_phys = 0;
1375 	}
1376 
1377 	if (!totals_only) {
1378 		if (level == 0) {
1379 			mdb_printf("PHY information\n");
1380 		}
1381 		mdb_printf("--------\n");
1382 		mdb_printf("Level %2d\n", level);
1383 		mdb_printf("--------\n");
1384 		mdb_printf("SAS Address      Hdl Phy#  Speed Type ");
1385 
1386 		if (verbose) {
1387 			mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref Lock\n");
1388 		} else {
1389 			mdb_printf("\n");
1390 		}
1391 	}
1392 
1393 	while (pphy) {
1394 		if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) {
1395 			NOREAD(pmcs_phy_t, phy);
1396 			break;
1397 		}
1398 
1399 		display_phy(phy, verbose, totals_only);
1400 
1401 		if (phy.children) {
1402 			display_phys(ss, verbose, phy.children, level + 1,
1403 			    totals_only);
1404 			if (!totals_only) {
1405 				mdb_printf("\n");
1406 			}
1407 		}
1408 
1409 		pphy = phy.sibling;
1410 	}
1411 
1412 	mdb_dec_indent(3);
1413 
1414 	if (level == 0) {
1415 		if (verbose) {
1416 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
1417 			    "(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
1418 			    (sas_phys + sata_phys + num_expanders),
1419 			    sas_phys, sata_phys, num_expanders,
1420 			    (exp_phys - num_expanders), empty_phys);
1421 		} else {
1422 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
1423 			    "Occupied PHYs:",
1424 			    (sas_phys + sata_phys + num_expanders),
1425 			    sas_phys, sata_phys, num_expanders);
1426 		}
1427 	}
1428 }
1429 
1430 /*
1431  * MAX_INST_STRLEN is the largest string size from which we will attempt
1432  * to convert to an instance number.  The string will be formed up as
1433  * "0t<inst>\0" so that mdb_strtoull can parse it properly.
1434  */
1435 #define	MAX_INST_STRLEN	8
1436 
1437 static int
1438 pmcs_dump_tracelog(boolean_t filter, int instance)
1439 {
1440 	pmcs_tbuf_t *tbuf_addr;
1441 	uint_t tbuf_idx;
1442 	pmcs_tbuf_t tbuf;
1443 	boolean_t wrap, elem_filtered;
1444 	uint_t start_idx, elems_to_print, idx, tbuf_num_elems;
1445 	char *bufp;
1446 	char elem_inst[MAX_INST_STRLEN], ei_idx;
1447 
1448 	/* Get the address of the first element */
1449 	if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) {
1450 		mdb_warn("can't read pmcs_tbuf");
1451 		return (DCMD_ERR);
1452 	}
1453 
1454 	/* Get the total number */
1455 	if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) {
1456 		mdb_warn("can't read pmcs_tbuf_num_elems");
1457 		return (DCMD_ERR);
1458 	}
1459 
1460 	/* Get the current index */
1461 	if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) {
1462 		mdb_warn("can't read pmcs_tbuf_idx");
1463 		return (DCMD_ERR);
1464 	}
1465 
1466 	/* Indicator as to whether the buffer has wrapped */
1467 	if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) {
1468 		mdb_warn("can't read pmcs_tbuf_wrap");
1469 		return (DCMD_ERR);
1470 	}
1471 
1472 	/* Figure out where we start and stop */
1473 	if (wrap) {
1474 		start_idx = tbuf_idx;
1475 		elems_to_print = tbuf_num_elems;
1476 	} else {
1477 		start_idx = 0;
1478 		elems_to_print = tbuf_idx;
1479 	}
1480 
1481 	idx = start_idx;
1482 
1483 	/* Dump the buffer contents */
1484 	while (elems_to_print != 0) {
1485 		if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx))
1486 		    == -1) {
1487 			NOREAD(tbuf, (tbuf_addr + idx));
1488 			return (DCMD_ERR);
1489 		}
1490 
1491 		elem_filtered = B_FALSE;
1492 
1493 		if (filter) {
1494 			bufp = tbuf.buf;
1495 			/* Skip the driver name */
1496 			while (*bufp < '0' || *bufp > '9') {
1497 				bufp++;
1498 			}
1499 
1500 			ei_idx = 0;
1501 			elem_inst[ei_idx++] = '0';
1502 			elem_inst[ei_idx++] = 't';
1503 			while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) {
1504 				elem_inst[ei_idx++] = *bufp;
1505 				bufp++;
1506 			}
1507 			elem_inst[ei_idx] = 0;
1508 
1509 			/* Get the instance */
1510 			if ((int)mdb_strtoull(elem_inst) != instance) {
1511 				elem_filtered = B_TRUE;
1512 			}
1513 		}
1514 
1515 		if (!elem_filtered) {
1516 			mdb_printf("%Y.%09ld %s\n", tbuf.timestamp, tbuf.buf);
1517 		}
1518 
1519 		--elems_to_print;
1520 		if (++idx == tbuf_num_elems) {
1521 			idx = 0;
1522 		}
1523 	}
1524 
1525 	return (DCMD_OK);
1526 }
1527 
1528 /*
1529  * Walkers
1530  */
1531 static int
1532 targets_walk_i(mdb_walk_state_t *wsp)
1533 {
1534 	if (wsp->walk_addr == NULL) {
1535 		mdb_warn("Can not perform global walk\n");
1536 		return (WALK_ERR);
1537 	}
1538 
1539 	/*
1540 	 * Address provided belongs to HBA softstate.  Get the targets pointer
1541 	 * to begin the walk.
1542 	 */
1543 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
1544 	    sizeof (pmcs_hw_t)) {
1545 		mdb_warn("Unable to read HBA softstate\n");
1546 		return (WALK_ERR);
1547 	}
1548 
1549 	if (targets == NULL) {
1550 		targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP);
1551 	}
1552 
1553 	if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) {
1554 		NOREAD(targets, ss.targets);
1555 		return (WALK_ERR);
1556 	}
1557 
1558 	target_idx = 0;
1559 	wsp->walk_addr = (uintptr_t)(targets[0]);
1560 	wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP);
1561 
1562 	return (WALK_NEXT);
1563 }
1564 
1565 static int
1566 targets_walk_s(mdb_walk_state_t *wsp)
1567 {
1568 	int status;
1569 
1570 	if (target_idx == ss.max_dev) {
1571 		return (WALK_DONE);
1572 	}
1573 
1574 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t),
1575 	    wsp->walk_addr) == -1) {
1576 		mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr);
1577 		return (WALK_DONE);
1578 	}
1579 
1580 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1581 	    wsp->walk_cbdata);
1582 
1583 	do {
1584 		wsp->walk_addr = (uintptr_t)(targets[++target_idx]);
1585 	} while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev));
1586 
1587 	if (target_idx == ss.max_dev) {
1588 		return (WALK_DONE);
1589 	}
1590 
1591 	return (status);
1592 }
1593 
1594 static void
1595 targets_walk_f(mdb_walk_state_t *wsp)
1596 {
1597 	mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t));
1598 }
1599 
1600 
1601 static pmcs_phy_t *
1602 pmcs_next_sibling(pmcs_phy_t *phyp)
1603 {
1604 	pmcs_phy_t parent;
1605 
1606 	/*
1607 	 * First, if this is a root PHY, there are no more siblings
1608 	 */
1609 	if (phyp->level == 0) {
1610 		return (NULL);
1611 	}
1612 
1613 	/*
1614 	 * Otherwise, next sibling is the parent's sibling
1615 	 */
1616 	while (phyp->level > 0) {
1617 		if (mdb_vread(&parent, sizeof (pmcs_phy_t),
1618 		    (uintptr_t)phyp->parent) == -1) {
1619 			mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
1620 			    (void *)phyp->parent);
1621 			return (NULL);
1622 		}
1623 
1624 		if (parent.sibling != NULL) {
1625 			break;
1626 		}
1627 
1628 		phyp = phyp->parent;
1629 	}
1630 
1631 	return (parent.sibling);
1632 }
1633 
1634 static int
1635 phy_walk_i(mdb_walk_state_t *wsp)
1636 {
1637 	if (wsp->walk_addr == NULL) {
1638 		mdb_warn("Can not perform global walk\n");
1639 		return (WALK_ERR);
1640 	}
1641 
1642 	/*
1643 	 * Address provided belongs to HBA softstate.  Get the targets pointer
1644 	 * to begin the walk.
1645 	 */
1646 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
1647 	    sizeof (pmcs_hw_t)) {
1648 		mdb_warn("Unable to read HBA softstate\n");
1649 		return (WALK_ERR);
1650 	}
1651 
1652 	wsp->walk_addr = (uintptr_t)(ss.root_phys);
1653 	wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
1654 
1655 	return (WALK_NEXT);
1656 }
1657 
1658 static int
1659 phy_walk_s(mdb_walk_state_t *wsp)
1660 {
1661 	pmcs_phy_t *phyp, *nphyp;
1662 	int status;
1663 
1664 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t),
1665 	    wsp->walk_addr) == -1) {
1666 		mdb_warn("phy_walk_s: Failed to read PHY at %p",
1667 		    (void *)wsp->walk_addr);
1668 		return (WALK_DONE);
1669 	}
1670 
1671 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1672 	    wsp->walk_cbdata);
1673 
1674 	phyp = (pmcs_phy_t *)wsp->walk_data;
1675 	if (phyp->children) {
1676 		wsp->walk_addr = (uintptr_t)(phyp->children);
1677 	} else {
1678 		wsp->walk_addr = (uintptr_t)(phyp->sibling);
1679 	}
1680 
1681 	if (wsp->walk_addr == NULL) {
1682 		/*
1683 		 * We reached the end of this sibling list.  Trudge back up
1684 		 * to the parent and find the next sibling after the expander
1685 		 * we just finished traversing, if there is one.
1686 		 */
1687 		nphyp = pmcs_next_sibling(phyp);
1688 
1689 		if (nphyp == NULL) {
1690 			return (WALK_DONE);
1691 		}
1692 
1693 		wsp->walk_addr = (uintptr_t)nphyp;
1694 	}
1695 
1696 	return (status);
1697 }
1698 
1699 static void
1700 phy_walk_f(mdb_walk_state_t *wsp)
1701 {
1702 	mdb_free(wsp->walk_data, sizeof (pmcs_phy_t));
1703 }
1704 
1705 static void
1706 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum,
1707     uintmax_t tag_type)
1708 {
1709 	int		idx;
1710 	pmcwork_t	work, *wp = &work;
1711 	uintptr_t	_wp;
1712 	boolean_t	printed_header = B_FALSE;
1713 	uint32_t	mask, mask_val, match_val;
1714 	char		*match_type;
1715 
1716 	if (index != UINT_MAX) {
1717 		match_type = "index";
1718 		mask = PMCS_TAG_INDEX_MASK;
1719 		mask_val = index << PMCS_TAG_INDEX_SHIFT;
1720 		match_val = index;
1721 	} else if (snum != UINT_MAX) {
1722 		match_type = "serial number";
1723 		mask = PMCS_TAG_SERNO_MASK;
1724 		mask_val = snum << PMCS_TAG_SERNO_SHIFT;
1725 		match_val = snum;
1726 	} else {
1727 		switch (tag_type) {
1728 		case PMCS_TAG_TYPE_NONE:
1729 			match_type = "tag type NONE";
1730 			break;
1731 		case PMCS_TAG_TYPE_CBACK:
1732 			match_type = "tag type CBACK";
1733 			break;
1734 		case PMCS_TAG_TYPE_WAIT:
1735 			match_type = "tag type WAIT";
1736 			break;
1737 		}
1738 		mask = PMCS_TAG_TYPE_MASK;
1739 		mask_val = tag_type << PMCS_TAG_TYPE_SHIFT;
1740 		match_val = tag_type;
1741 	}
1742 
1743 	_wp = (uintptr_t)ss.work;
1744 
1745 	for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
1746 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
1747 			NOREAD(pmcwork_t, _wp);
1748 			continue;
1749 		}
1750 
1751 		if ((work.htag & mask) != mask_val) {
1752 			continue;
1753 		}
1754 
1755 		if (printed_header == B_FALSE) {
1756 			if (tag_type) {
1757 				mdb_printf("\nWork structures matching %s\n\n",
1758 				    match_type, match_val);
1759 			} else {
1760 				mdb_printf("\nWork structures matching %s of "
1761 				    "0x%x\n\n", match_type, match_val);
1762 			}
1763 			mdb_printf("%8s %10s %20s %8s %8s O D\n",
1764 			    "HTag", "State", "Phy Path", "Target", "Timer");
1765 			printed_header = B_TRUE;
1766 		}
1767 
1768 		display_one_work(wp, 0, 0);
1769 	}
1770 
1771 	if (!printed_header) {
1772 		mdb_printf("No work structure matches found\n");
1773 	}
1774 }
1775 
1776 static int
1777 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1778 {
1779 	struct	pmcs_hw		ss;
1780 	uintmax_t		tag_type = UINT_MAX;
1781 	uintmax_t		snum = UINT_MAX;
1782 	uintmax_t		index = UINT_MAX;
1783 	int			args = 0;
1784 	void			*pmcs_state;
1785 	char			*state_str;
1786 	struct dev_info		dip;
1787 
1788 	if (!(flags & DCMD_ADDRSPEC)) {
1789 		pmcs_state = NULL;
1790 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
1791 			mdb_warn("can't read pmcs_softc_state");
1792 			return (DCMD_ERR);
1793 		}
1794 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc,
1795 		    argv, (uintptr_t)pmcs_state) == -1) {
1796 			mdb_warn("mdb_pwalk_dcmd failed");
1797 			return (DCMD_ERR);
1798 		}
1799 		return (DCMD_OK);
1800 	}
1801 
1802 	if (mdb_getopts(argc, argv,
1803 	    'i', MDB_OPT_UINT64, &index,
1804 	    's', MDB_OPT_UINT64, &snum,
1805 	    't', MDB_OPT_UINT64, &tag_type) != argc)
1806 		return (DCMD_USAGE);
1807 
1808 	/*
1809 	 * Count the number of supplied options and make sure they are
1810 	 * within appropriate ranges.  If they're set to UINT_MAX, that means
1811 	 * they were not supplied, in which case reset them to 0.
1812 	 */
1813 	if (index != UINT_MAX) {
1814 		args++;
1815 		if (index > PMCS_TAG_INDEX_MASK) {
1816 			mdb_warn("Index is out of range\n");
1817 			return (DCMD_USAGE);
1818 		}
1819 	}
1820 
1821 	if (tag_type != UINT_MAX) {
1822 		args++;
1823 		switch (tag_type) {
1824 		case PMCS_TAG_TYPE_NONE:
1825 		case PMCS_TAG_TYPE_CBACK:
1826 		case PMCS_TAG_TYPE_WAIT:
1827 			break;
1828 		default:
1829 			mdb_warn("Invalid tag type\n");
1830 			return (DCMD_USAGE);
1831 		}
1832 	}
1833 
1834 	if (snum != UINT_MAX) {
1835 		args++;
1836 		if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) {
1837 			mdb_warn("Serial number is out of range\n");
1838 			return (DCMD_USAGE);
1839 		}
1840 	}
1841 
1842 	/*
1843 	 * Make sure 1 and only 1 option is specified
1844 	 */
1845 	if ((args == 0) || (args > 1)) {
1846 		mdb_warn("Exactly one of -i, -s and -t must be specified\n");
1847 		return (DCMD_USAGE);
1848 	}
1849 
1850 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
1851 		NOREAD(pmcs_hw_t, addr);
1852 		return (DCMD_ERR);
1853 	}
1854 
1855 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
1856 		NOREAD(pmcs_hw_t, addr);
1857 		return (DCMD_ERR);
1858 	}
1859 
1860 	/* processing completed */
1861 
1862 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
1863 	    (flags & DCMD_LOOPFIRST)) {
1864 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
1865 			mdb_printf("\n");
1866 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
1867 		    "Address", "State", "Inst", "DIP");
1868 		mdb_printf("================================="
1869 		    "============================================\n");
1870 	}
1871 
1872 	switch (ss.state) {
1873 	case STATE_NIL:
1874 		state_str = "Invalid";
1875 		break;
1876 	case STATE_PROBING:
1877 		state_str = "Probing";
1878 		break;
1879 	case STATE_RUNNING:
1880 		state_str = "Running";
1881 		break;
1882 	case STATE_UNPROBING:
1883 		state_str = "Unprobing";
1884 		break;
1885 	case STATE_DEAD:
1886 		state_str = "Dead";
1887 		break;
1888 	}
1889 
1890 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
1891 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
1892 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
1893 	mdb_printf("\n");
1894 
1895 	mdb_inc_indent(4);
1896 	display_matching_work(ss, index, snum, tag_type);
1897 	mdb_dec_indent(4);
1898 	mdb_printf("\n");
1899 
1900 	return (DCMD_OK);
1901 }
1902 
1903 static int
1904 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1905 {
1906 	struct	pmcs_hw		ss;
1907 	uint_t			verbose = FALSE;
1908 	uint_t			phy_info = FALSE;
1909 	uint_t			hw_info = FALSE;
1910 	uint_t			target_info = FALSE;
1911 	uint_t			work_info = FALSE;
1912 	uint_t			ic_info = FALSE;
1913 	uint_t			iport_info = FALSE;
1914 	uint_t			waitqs_info = FALSE;
1915 	uint_t			tracelog = FALSE;
1916 	uint_t			ibq = FALSE;
1917 	uint_t			obq = FALSE;
1918 	uint_t			tgt_phy_count = FALSE;
1919 	uint_t			compq = FALSE;
1920 	int			rv = DCMD_OK;
1921 	void			*pmcs_state;
1922 	char			*state_str;
1923 	struct dev_info		dip;
1924 
1925 	if (!(flags & DCMD_ADDRSPEC)) {
1926 		pmcs_state = NULL;
1927 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
1928 			mdb_warn("can't read pmcs_softc_state");
1929 			return (DCMD_ERR);
1930 		}
1931 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv,
1932 		    (uintptr_t)pmcs_state) == -1) {
1933 			mdb_warn("mdb_pwalk_dcmd failed");
1934 			return (DCMD_ERR);
1935 		}
1936 		return (DCMD_OK);
1937 	}
1938 
1939 	if (mdb_getopts(argc, argv,
1940 	    'c', MDB_OPT_SETBITS, TRUE, &compq,
1941 	    'h', MDB_OPT_SETBITS, TRUE, &hw_info,
1942 	    'i', MDB_OPT_SETBITS, TRUE, &ic_info,
1943 	    'I', MDB_OPT_SETBITS, TRUE, &iport_info,
1944 	    'l', MDB_OPT_SETBITS, TRUE, &tracelog,
1945 	    'p', MDB_OPT_SETBITS, TRUE, &phy_info,
1946 	    'q', MDB_OPT_SETBITS, TRUE, &ibq,
1947 	    'Q', MDB_OPT_SETBITS, TRUE, &obq,
1948 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
1949 	    'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count,
1950 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
1951 	    'w', MDB_OPT_SETBITS, TRUE, &work_info,
1952 	    'W', MDB_OPT_SETBITS, TRUE, &waitqs_info,
1953 	    NULL) != argc)
1954 		return (DCMD_USAGE);
1955 
1956 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
1957 		NOREAD(pmcs_hw_t, addr);
1958 		return (DCMD_ERR);
1959 	}
1960 
1961 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
1962 		NOREAD(pmcs_hw_t, addr);
1963 		return (DCMD_ERR);
1964 	}
1965 
1966 	/*
1967 	 * Dumping the trace log is special.  It's global, not per-HBA.
1968 	 * Thus, a provided address is ignored.  In addition, other options
1969 	 * cannot be specified at the same time.
1970 	 */
1971 	if (tracelog) {
1972 		if (hw_info || ic_info || iport_info || phy_info || work_info ||
1973 		    target_info || waitqs_info || ibq || obq || tgt_phy_count ||
1974 		    compq) {
1975 			return (DCMD_USAGE);
1976 		}
1977 
1978 		if ((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) {
1979 			return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance));
1980 		} else if (flags & DCMD_LOOPFIRST) {
1981 			return (pmcs_dump_tracelog(B_FALSE, 0));
1982 		} else {
1983 			return (DCMD_OK);
1984 		}
1985 	}
1986 
1987 	/* processing completed */
1988 
1989 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
1990 	    (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info ||
1991 	    work_info || waitqs_info || ibq || obq || tgt_phy_count || compq) {
1992 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
1993 			mdb_printf("\n");
1994 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
1995 		    "Address", "State", "Inst", "DIP");
1996 		mdb_printf("================================="
1997 		    "============================================\n");
1998 	}
1999 
2000 	switch (ss.state) {
2001 	case STATE_NIL:
2002 		state_str = "Invalid";
2003 		break;
2004 	case STATE_PROBING:
2005 		state_str = "Probing";
2006 		break;
2007 	case STATE_RUNNING:
2008 		state_str = "Running";
2009 		break;
2010 	case STATE_UNPROBING:
2011 		state_str = "Unprobing";
2012 		break;
2013 	case STATE_DEAD:
2014 		state_str = "Dead";
2015 		break;
2016 	}
2017 
2018 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
2019 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
2020 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
2021 	mdb_printf("\n");
2022 
2023 	mdb_inc_indent(4);
2024 
2025 	if (waitqs_info)
2026 		display_waitqs(ss, verbose);
2027 
2028 	if (hw_info)
2029 		display_hwinfo(ss, verbose);
2030 
2031 	if (phy_info || tgt_phy_count)
2032 		display_phys(ss, verbose, NULL, 0, tgt_phy_count);
2033 
2034 	if (target_info || tgt_phy_count)
2035 		display_targets(ss, verbose, tgt_phy_count);
2036 
2037 	if (work_info)
2038 		display_work(ss, verbose);
2039 
2040 	if (ic_info)
2041 		display_ic(ss, verbose);
2042 
2043 	if (ibq)
2044 		display_inbound_queues(ss, verbose);
2045 
2046 	if (obq)
2047 		display_outbound_queues(ss, verbose);
2048 
2049 	if (iport_info)
2050 		display_iport(ss, addr, verbose);
2051 
2052 	if (compq)
2053 		display_completion_queue(ss);
2054 
2055 	mdb_dec_indent(4);
2056 
2057 	return (rv);
2058 }
2059 
2060 void
2061 pmcs_help()
2062 {
2063 	mdb_printf("Prints summary information about each pmcs instance.\n"
2064 	    "    -c: Dump the completion queue\n"
2065 	    "    -h: Print more detailed hardware information\n"
2066 	    "    -i: Print interrupt coalescing information\n"
2067 	    "    -I: Print information about each iport\n"
2068 	    "    -l: Dump the trace log (cannot be used with other options)\n"
2069 	    "    -p: Print information about each attached PHY\n"
2070 	    "    -q: Dump inbound queues\n"
2071 	    "    -Q: Dump outbound queues\n"
2072 	    "    -t: Print information about each known target\n"
2073 	    "    -T: Print target and PHY count summary\n"
2074 	    "    -w: Dump work structures\n"
2075 	    "    -W: List pmcs cmds waiting on various queues\n"
2076 	    "    -v: Add verbosity to the above options\n");
2077 }
2078 
2079 void
2080 pmcs_tag_help()
2081 {
2082 	mdb_printf("Print all work structures by matching the tag.\n"
2083 	    "    -i index:        Match tag index (0x000 - 0xfff)\n"
2084 	    "    -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
2085 	    "    -t tagtype:      Match tag type [NONE(1), CBACK(2), "
2086 	    "WAIT(3)]\n");
2087 }
2088 
2089 static const mdb_dcmd_t dcmds[] = {
2090 	{ "pmcs", "?[-chiIpQqtTwWv] | -l", "print pmcs information",
2091 	    pmcs_dcmd, pmcs_help
2092 	},
2093 	{ "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
2094 	    "Find work structures by tag type, serial number or index",
2095 	    pmcs_tag, pmcs_tag_help
2096 	},
2097 	{ NULL }
2098 };
2099 
2100 static const mdb_walker_t walkers[] = {
2101 	{ "pmcs_targets", "walk target structures",
2102 		targets_walk_i, targets_walk_s, targets_walk_f },
2103 	{ "pmcs_phys", "walk PHY structures",
2104 		phy_walk_i, phy_walk_s, phy_walk_f },
2105 	{ NULL }
2106 };
2107 
2108 static const mdb_modinfo_t modinfo = {
2109 	MDB_API_VERSION, dcmds, walkers
2110 };
2111 
2112 const mdb_modinfo_t *
2113 _mdb_init(void)
2114 {
2115 	return (&modinfo);
2116 }
2117