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