xref: /illumos-gate/usr/src/cmd/mdb/common/modules/pmcs/pmcs.c (revision 2ac4abe882db38ef90020f7c5ca28586e3d57258)
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 2010 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 <mdb/mdb_ctf.h>
29 #include <sys/sysinfo.h>
30 #include <sys/byteorder.h>
31 #include <sys/nvpair.h>
32 #include <sys/damap.h>
33 #include <sys/scsi/scsi.h>
34 #include <sys/scsi/adapters/pmcs/pmcs.h>
35 #ifndef _KMDB
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #endif	/* _KMDB */
41 
42 /*
43  * We need use this to pass the settings when display_iport
44  */
45 typedef struct per_iport_setting {
46 	uint_t  pis_damap_info; /* -m: DAM/damap */
47 	uint_t  pis_dtc_info; /* -d: device tree children: dev_info/path_info */
48 } per_iport_setting_t;
49 
50 #define	MDB_RD(a, b, c)		mdb_vread(a, b, (uintptr_t)c)
51 #define	NOREAD(a, b)		mdb_warn("could not read " #a " at 0x%p", b)
52 
53 static pmcs_hw_t ss;
54 static pmcs_xscsi_t **targets = NULL;
55 static int target_idx;
56 
57 static uint32_t	sas_phys, sata_phys, exp_phys, num_expanders, empty_phys;
58 
59 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp);
60 static void display_one_work(pmcwork_t *wp, int verbose, int idx);
61 
62 static void
63 print_sas_address(pmcs_phy_t *phy)
64 {
65 	int idx;
66 
67 	for (idx = 0; idx < 8; idx++) {
68 		mdb_printf("%02x", phy->sas_address[idx]);
69 	}
70 }
71 
72 /*ARGSUSED*/
73 static void
74 display_ic(struct pmcs_hw m, int verbose)
75 {
76 	int msec_per_tick;
77 
78 	if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
79 		mdb_warn("can't read msec_per_tick");
80 		msec_per_tick = 0;
81 	}
82 
83 	mdb_printf("\n");
84 	mdb_printf("Interrupt coalescing timer info\n");
85 	mdb_printf("-------------------------------\n");
86 	if (msec_per_tick == 0) {
87 		mdb_printf("Quantum                       : ?? ms\n");
88 	} else {
89 		mdb_printf("Quantum                       : %d ms\n",
90 		    m.io_intr_coal.quantum * msec_per_tick);
91 	}
92 	mdb_printf("Timer enabled                 : ");
93 	if (m.io_intr_coal.timer_on) {
94 		mdb_printf("Yes\n");
95 		mdb_printf("Coalescing timer value        : %d us\n",
96 		    m.io_intr_coal.intr_coal_timer);
97 	} else {
98 		mdb_printf("No\n");
99 	}
100 	mdb_printf("Total nsecs between interrupts: %ld\n",
101 	    m.io_intr_coal.nsecs_between_intrs);
102 	mdb_printf("Time of last I/O interrupt    : %ld\n",
103 	    m.io_intr_coal.last_io_comp);
104 	mdb_printf("Number of I/O interrupts      : %d\n",
105 	    m.io_intr_coal.num_intrs);
106 	mdb_printf("Number of I/O completions     : %d\n",
107 	    m.io_intr_coal.num_io_completions);
108 	mdb_printf("Max I/O completion interrupts : %d\n",
109 	    m.io_intr_coal.max_io_completions);
110 	mdb_printf("Measured ECHO int latency     : %d ns\n",
111 	    m.io_intr_coal.intr_latency);
112 	mdb_printf("Interrupt threshold           : %d\n",
113 	    m.io_intr_coal.intr_threshold);
114 }
115 
116 /*ARGSUSED*/
117 static int
118 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv)
119 {
120 	struct pmcs_phy		phy;
121 
122 	if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) !=
123 	    sizeof (struct pmcs_phy)) {
124 		return (DCMD_ERR);
125 	}
126 
127 	mdb_printf("%16p %2d\n", addr, phy.phynum);
128 
129 	return (0);
130 }
131 
132 static int
133 display_iport_damap(dev_info_t *pdip)
134 {
135 	int rval = DCMD_ERR;
136 	struct dev_info dip;
137 	scsi_hba_tran_t sht;
138 	mdb_ctf_id_t istm_ctfid; /* impl_scsi_tgtmap_t ctf_id */
139 	ulong_t tmd_offset = 0; /* tgtmap_dam offset to impl_scsi_tgtmap_t */
140 	uintptr_t dam0;
141 	uintptr_t dam1;
142 
143 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
144 	    sizeof (struct dev_info)) {
145 		return (rval);
146 	}
147 
148 	if (dip.devi_driver_data == NULL) {
149 		return (rval);
150 	}
151 
152 	if (mdb_vread(&sht, sizeof (scsi_hba_tran_t),
153 	    (uintptr_t)dip.devi_driver_data) != sizeof (scsi_hba_tran_t)) {
154 		return (rval);
155 	}
156 
157 	if (sht.tran_tgtmap == NULL) {
158 		return (rval);
159 	}
160 
161 	if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid) != 0) {
162 		return (rval);
163 	}
164 
165 	if (mdb_ctf_offsetof(istm_ctfid, "tgtmap_dam", &tmd_offset) != 0) {
166 		return (rval);
167 	}
168 
169 	tmd_offset /= NBBY;
170 	mdb_vread(&dam0, sizeof (dam0),
171 	    (uintptr_t)(tmd_offset + (char *)sht.tran_tgtmap));
172 	mdb_vread(&dam1, sizeof (dam1),
173 	    (uintptr_t)(sizeof (dam0) + tmd_offset + (char *)sht.tran_tgtmap));
174 
175 	if (dam0 != NULL) {
176 		rval = mdb_call_dcmd("damap", dam0, DCMD_ADDRSPEC, 0, NULL);
177 		mdb_printf("\n");
178 		if (rval != DCMD_OK) {
179 			return (rval);
180 		}
181 	}
182 
183 	if (dam1 != NULL) {
184 		rval = mdb_call_dcmd("damap", dam1, DCMD_ADDRSPEC, 0, NULL);
185 		mdb_printf("\n");
186 	}
187 
188 	return (rval);
189 }
190 
191 /* ARGSUSED */
192 static int
193 display_iport_di_cb(uintptr_t addr, const void *wdata, void *priv)
194 {
195 	uint_t *idx = (uint_t *)priv;
196 	struct dev_info dip;
197 	char devi_name[MAXNAMELEN];
198 	char devi_addr[MAXNAMELEN];
199 
200 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)addr) !=
201 	    sizeof (struct dev_info)) {
202 		return (DCMD_ERR);
203 	}
204 
205 	if (mdb_readstr(devi_name, sizeof (devi_name),
206 	    (uintptr_t)dip.devi_node_name) == -1) {
207 		devi_name[0] = '?';
208 		devi_name[1] = '\0';
209 	}
210 
211 	if (mdb_readstr(devi_addr, sizeof (devi_addr),
212 	    (uintptr_t)dip.devi_addr) == -1) {
213 		devi_addr[0] = '?';
214 		devi_addr[1] = '\0';
215 	}
216 
217 	mdb_printf("  %3d: @%-21s%10s@\t%p::devinfo -s\n",
218 	    (*idx)++, devi_addr, devi_name, addr);
219 	return (DCMD_OK);
220 }
221 
222 /* ARGSUSED */
223 static int
224 display_iport_pi_cb(uintptr_t addr, const void *wdata, void *priv)
225 {
226 	uint_t *idx = (uint_t *)priv;
227 	struct mdi_pathinfo mpi;
228 	char pi_addr[MAXNAMELEN];
229 
230 	if (mdb_vread(&mpi, sizeof (struct mdi_pathinfo), (uintptr_t)addr) !=
231 	    sizeof (struct mdi_pathinfo)) {
232 		return (DCMD_ERR);
233 	}
234 
235 	if (mdb_readstr(pi_addr, sizeof (pi_addr),
236 	    (uintptr_t)mpi.pi_addr) == -1) {
237 		pi_addr[0] = '?';
238 		pi_addr[1] = '\0';
239 	}
240 
241 	mdb_printf("  %3d: @%-21s %p::print struct mdi_pathinfo\n",
242 	    (*idx)++, pi_addr, addr);
243 	return (DCMD_OK);
244 }
245 
246 static int
247 display_iport_dtc(dev_info_t *pdip)
248 {
249 	int rval = DCMD_ERR;
250 	struct dev_info dip;
251 	struct mdi_phci phci;
252 	uint_t didx = 1;
253 	uint_t pidx = 1;
254 
255 	if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
256 	    sizeof (struct dev_info)) {
257 		return (rval);
258 	}
259 
260 	mdb_printf("Device tree children - dev_info:\n");
261 	if (dip.devi_child == NULL) {
262 		mdb_printf("\tdevi_child is NULL, no dev_info\n\n");
263 		goto skip_di;
264 	}
265 
266 	/*
267 	 * First, we dump the iport's children dev_info node information.
268 	 * use existing walker: devinfo_siblings
269 	 */
270 	mdb_printf("\t#: @unit-address               name@\tdrill-down\n");
271 	rval = mdb_pwalk("devinfo_siblings", display_iport_di_cb,
272 	    (void *)&didx, (uintptr_t)dip.devi_child);
273 	mdb_printf("\n");
274 
275 skip_di:
276 	/*
277 	 * Then we try to dump the iport's path_info node information.
278 	 * use existing walker: mdipi_phci_list
279 	 */
280 	mdb_printf("Device tree children - path_info:\n");
281 	if (mdb_vread(&phci, sizeof (struct mdi_phci),
282 	    (uintptr_t)dip.devi_mdi_xhci) != sizeof (struct mdi_phci)) {
283 		mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n");
284 		return (rval);
285 	}
286 
287 	if (phci.ph_path_head == NULL) {
288 		mdb_printf("\tph_path_head is NULL, no path_info\n\n");
289 		return (rval);
290 	}
291 
292 	mdb_printf("\t#: @unit-address          drill-down\n");
293 	rval = mdb_pwalk("mdipi_phci_list", display_iport_pi_cb,
294 	    (void *)&pidx, (uintptr_t)phci.ph_path_head);
295 	mdb_printf("\n");
296 	return (rval);
297 }
298 
299 static void
300 display_iport_more(dev_info_t *dip, per_iport_setting_t *pis)
301 {
302 	if (pis->pis_damap_info) {
303 		(void) display_iport_damap(dip);
304 	}
305 
306 	if (pis->pis_dtc_info) {
307 		(void) display_iport_dtc(dip);
308 	}
309 }
310 
311 /*ARGSUSED*/
312 static int
313 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv)
314 {
315 	struct pmcs_iport	iport;
316 	uintptr_t		list_addr;
317 	char			*ua_state;
318 	char			portid[4];
319 	char			unit_address[34];
320 	per_iport_setting_t	*pis = (per_iport_setting_t *)priv;
321 
322 	if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) !=
323 	    sizeof (struct pmcs_iport)) {
324 		return (DCMD_ERR);
325 	}
326 
327 	if (mdb_readstr(unit_address, sizeof (unit_address),
328 	    (uintptr_t)(iport.ua)) == -1) {
329 		strncpy(unit_address, "Unset", sizeof (unit_address));
330 	}
331 
332 	if (iport.portid == 0xffff) {
333 		mdb_snprintf(portid, sizeof (portid), "%s", "-");
334 	} else if (iport.portid == PMCS_IPORT_INVALID_PORT_ID) {
335 		mdb_snprintf(portid, sizeof (portid), "%s", "N/A");
336 	} else {
337 		mdb_snprintf(portid, sizeof (portid), "%d", iport.portid);
338 	}
339 
340 	switch (iport.ua_state) {
341 	case UA_INACTIVE:
342 		ua_state = "Inactive";
343 		break;
344 	case UA_PEND_ACTIVATE:
345 		ua_state = "PendActivate";
346 		break;
347 	case UA_ACTIVE:
348 		ua_state = "Active";
349 		break;
350 	case UA_PEND_DEACTIVATE:
351 		ua_state = "PendDeactivate";
352 		break;
353 	default:
354 		ua_state = "Unknown";
355 	}
356 
357 	if (strlen(unit_address) < 3) {
358 		/* Standard iport unit address */
359 		mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State",
360 		    "PortID", "NumPhys", "DIP\n");
361 		mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr,
362 		    ua_state, portid, iport.nphy, iport.dip);
363 	} else {
364 		/* Temporary iport unit address */
365 		mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport",
366 		    "UA State", "PortID", "NumPhys", "DIP\n");
367 		mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr,
368 		    ua_state, portid, iport.nphy, iport.dip);
369 	}
370 
371 	if (iport.nphy > 0) {
372 		mdb_inc_indent(4);
373 		mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
374 		mdb_inc_indent(2);
375 		list_addr =
376 		    (uintptr_t)(addr + offsetof(struct pmcs_iport, phys));
377 		if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL,
378 		    list_addr) == -1) {
379 			mdb_warn("pmcs iport walk failed");
380 		}
381 		mdb_dec_indent(6);
382 		mdb_printf("\n");
383 	}
384 
385 	/*
386 	 * See if we need to show more information based on 'd' or 'm' options
387 	 */
388 	display_iport_more(iport.dip, pis);
389 
390 	return (0);
391 }
392 
393 /*ARGSUSED*/
394 static void
395 display_iport(struct pmcs_hw m, uintptr_t addr, int verbose,
396     per_iport_setting_t *pis)
397 {
398 	uintptr_t	list_addr;
399 
400 	if (m.iports_attached) {
401 		mdb_printf("Iport information:\n");
402 		mdb_printf("-----------------\n");
403 	} else {
404 		mdb_printf("No Iports found.\n\n");
405 		return;
406 	}
407 
408 	list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports));
409 
410 	if (mdb_pwalk("list", pmcs_iport_walk_cb, pis, list_addr) == -1) {
411 		mdb_warn("pmcs iport walk failed");
412 	}
413 
414 	mdb_printf("\n");
415 }
416 
417 /* ARGSUSED */
418 static int
419 pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv)
420 {
421 	pmcs_phy_t phy;
422 
423 	if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) {
424 		mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p",
425 		    (void *)addr);
426 		return (DCMD_ERR);
427 	}
428 
429 	if (phy.configured && (phy.target == NULL)) {
430 		mdb_printf("SAS address: ");
431 		print_sas_address(&phy);
432 		mdb_printf("  DType: ");
433 		switch (phy.dtype) {
434 		case SAS:
435 			mdb_printf("%4s", "SAS");
436 			break;
437 		case SATA:
438 			mdb_printf("%4s", "SATA");
439 			break;
440 		case EXPANDER:
441 			mdb_printf("%4s", "SMP");
442 			break;
443 		default:
444 			mdb_printf("%4s", "N/A");
445 			break;
446 		}
447 		mdb_printf("  Path: %s\n", phy.path);
448 	}
449 
450 	return (0);
451 }
452 
453 static void
454 display_unconfigured_targets(uintptr_t addr)
455 {
456 	mdb_printf("Unconfigured target SAS address:\n\n");
457 
458 	if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) {
459 		mdb_warn("pmcs phys walk failed");
460 	}
461 }
462 
463 static void
464 display_completion_queue(struct pmcs_hw ss)
465 {
466 	pmcs_iocomp_cb_t ccb, *ccbp;
467 	pmcwork_t work;
468 
469 	if (ss.iocomp_cb_head == NULL) {
470 		mdb_printf("Completion queue is empty.\n");
471 		return;
472 	}
473 
474 	ccbp = ss.iocomp_cb_head;
475 	mdb_printf("%8s %10s %20s %8s %8s O D\n",
476 	    "HTag", "State", "Phy Path", "Target", "Timer");
477 
478 	while (ccbp) {
479 		if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t),
480 		    (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) {
481 			mdb_warn("Unable to read completion queue entry\n");
482 			return;
483 		}
484 
485 		if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk)
486 		    != sizeof (pmcwork_t)) {
487 			mdb_warn("Unable to read work structure\n");
488 			return;
489 		}
490 
491 		/*
492 		 * Only print the work structure if it's still active.  If
493 		 * it's not, it's been completed since we started looking at
494 		 * it.
495 		 */
496 		if (work.state != PMCS_WORK_STATE_NIL) {
497 			display_one_work(&work, 0, 0);
498 		}
499 		ccbp = ccb.next;
500 	}
501 }
502 
503 /*ARGSUSED*/
504 static void
505 display_hwinfo(struct pmcs_hw m, int verbose)
506 {
507 	struct pmcs_hw	*mp = &m;
508 	char		*fwsupport;
509 
510 	switch (PMCS_FW_TYPE(mp)) {
511 	case PMCS_FW_TYPE_RELEASED:
512 		fwsupport = "Released";
513 		break;
514 	case PMCS_FW_TYPE_DEVELOPMENT:
515 		fwsupport = "Development";
516 		break;
517 	case PMCS_FW_TYPE_ALPHA:
518 		fwsupport = "Alpha";
519 		break;
520 	case PMCS_FW_TYPE_BETA:
521 		fwsupport = "Beta";
522 		break;
523 	default:
524 		fwsupport = "Special";
525 		break;
526 	}
527 
528 	mdb_printf("\nHardware information:\n");
529 	mdb_printf("---------------------\n");
530 
531 	mdb_printf("Chip revision:    %c\n", 'A' + m.chiprev);
532 	mdb_printf("SAS WWID:         %"PRIx64"\n", m.sas_wwns[0]);
533 	mdb_printf("Firmware version: %x.%x.%x (%s)\n",
534 	    PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp),
535 	    fwsupport);
536 	mdb_printf("ILA version:      %08x\n", m.ila_ver);
537 	mdb_printf("Active f/w img:   %c\n", (m.fw_active_img) ? 'A' : 'B');
538 
539 	mdb_printf("Number of PHYs:   %d\n", m.nphy);
540 	mdb_printf("Maximum commands: %d\n", m.max_cmd);
541 	mdb_printf("Maximum devices:  %d\n", m.max_dev);
542 	mdb_printf("I/O queue depth:  %d\n", m.ioq_depth);
543 	if (m.fwlog == 0) {
544 		mdb_printf("Firmware logging: Disabled\n");
545 	} else {
546 		mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog);
547 	}
548 	if (m.fwlog_file == 0) {
549 		mdb_printf("Firmware logfile: Not configured\n");
550 	} else {
551 		mdb_printf("Firmware logfile: Configured\n");
552 		mdb_inc_indent(2);
553 		mdb_printf("AAP1 log file:  %s\n", m.fwlogfile_aap1);
554 		mdb_printf("IOP logfile:    %s\n", m.fwlogfile_iop);
555 		mdb_dec_indent(2);
556 	}
557 }
558 
559 static void
560 display_targets(struct pmcs_hw m, int verbose, int totals_only)
561 {
562 	char		*dtype;
563 	pmcs_xscsi_t	xs;
564 	pmcs_phy_t	phy;
565 	uint16_t	max_dev, idx;
566 	uint32_t	sas_targets = 0, smp_targets = 0, sata_targets = 0;
567 
568 	max_dev = m.max_dev;
569 
570 	if (targets == NULL) {
571 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
572 	}
573 
574 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
575 		NOREAD(targets, m.targets);
576 		return;
577 	}
578 
579 	if (!totals_only) {
580 		mdb_printf("\nTarget information:\n");
581 		mdb_printf("---------------------------------------\n");
582 		mdb_printf("VTGT %-16s %-16s %-5s %4s %6s %s", "SAS Address",
583 		    "PHY Address", "DType", "Actv", "OnChip", "DS");
584 		mdb_printf("\n");
585 	}
586 
587 	for (idx = 0; idx < max_dev; idx++) {
588 		if (targets[idx] == NULL) {
589 			continue;
590 		}
591 
592 		if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) {
593 			NOREAD(pmcs_xscsi_t, targets[idx]);
594 			continue;
595 		}
596 
597 		/*
598 		 * It has to be new or assigned to be of interest.
599 		 */
600 		if (xs.new == 0 && xs.assigned == 0) {
601 			continue;
602 		}
603 
604 		switch (xs.dtype) {
605 		case NOTHING:
606 			dtype = "None";
607 			break;
608 		case SATA:
609 			dtype = "SATA";
610 			sata_targets++;
611 			break;
612 		case SAS:
613 			dtype = "SAS";
614 			sas_targets++;
615 			break;
616 		case EXPANDER:
617 			dtype = "SMP";
618 			smp_targets++;
619 			break;
620 		}
621 
622 		if (totals_only) {
623 			continue;
624 		}
625 
626 		if (xs.phy) {
627 			if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) {
628 				NOREAD(pmcs_phy_t, xs.phy);
629 				continue;
630 			}
631 			mdb_printf("%4d ", idx);
632 			print_sas_address(&phy);
633 			mdb_printf(" %16p", xs.phy);
634 		} else {
635 			mdb_printf("%4d %16s", idx, "<no phy avail>");
636 		}
637 		mdb_printf(" %5s", dtype);
638 		mdb_printf(" %4d", xs.actv_pkts);
639 		mdb_printf(" %6d", xs.actv_cnt);
640 		mdb_printf(" %2d", xs.dev_state);
641 
642 		if (verbose) {
643 			if (xs.new) {
644 				mdb_printf(" new");
645 			}
646 			if (xs.assigned) {
647 				mdb_printf(" assigned");
648 			}
649 			if (xs.draining) {
650 				mdb_printf(" draining");
651 			}
652 			if (xs.reset_wait) {
653 				mdb_printf(" reset_wait");
654 			}
655 			if (xs.resetting) {
656 				mdb_printf(" resetting");
657 			}
658 			if (xs.recover_wait) {
659 				mdb_printf(" recover_wait");
660 			}
661 			if (xs.recovering) {
662 				mdb_printf(" recovering");
663 			}
664 			if (xs.event_recovery) {
665 				mdb_printf(" event recovery");
666 			}
667 			if (xs.special_running) {
668 				mdb_printf(" special_active");
669 			}
670 			if (xs.ncq) {
671 				mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
672 				    xs.tagmap, xs.qdepth);
673 			} else if (xs.pio) {
674 				mdb_printf(" pio");
675 			}
676 		}
677 
678 		mdb_printf("\n");
679 	}
680 
681 	if (!totals_only) {
682 		mdb_printf("\n");
683 	}
684 
685 	mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
686 	    "Configured targets:", (sas_targets + sata_targets + smp_targets),
687 	    sas_targets, sata_targets, smp_targets);
688 }
689 
690 static char *
691 work_state_to_string(uint32_t state)
692 {
693 	char *state_string;
694 
695 	switch (state) {
696 	case PMCS_WORK_STATE_NIL:
697 		state_string = "Free";
698 		break;
699 	case PMCS_WORK_STATE_READY:
700 		state_string = "Ready";
701 		break;
702 	case PMCS_WORK_STATE_ONCHIP:
703 		state_string = "On Chip";
704 		break;
705 	case PMCS_WORK_STATE_INTR:
706 		state_string = "In Intr";
707 		break;
708 	case PMCS_WORK_STATE_IOCOMPQ:
709 		state_string = "I/O Comp";
710 		break;
711 	case PMCS_WORK_STATE_ABORTED:
712 		state_string = "I/O Aborted";
713 		break;
714 	case PMCS_WORK_STATE_TIMED_OUT:
715 		state_string = "I/O Timed Out";
716 		break;
717 	default:
718 		state_string = "INVALID";
719 		break;
720 	}
721 
722 	return (state_string);
723 }
724 
725 static void
726 display_one_work(pmcwork_t *wp, int verbose, int idx)
727 {
728 	char		*state, *last_state;
729 	char		*path;
730 	pmcs_xscsi_t	xs;
731 	pmcs_phy_t	phy;
732 	int		tgt;
733 
734 	state = work_state_to_string(wp->state);
735 	last_state = work_state_to_string(wp->last_state);
736 
737 	if (wp->ssp_event && wp->ssp_event != 0xffffffff) {
738 		mdb_printf("SSP event 0x%x", wp->ssp_event);
739 	}
740 
741 	tgt = -1;
742 	if (wp->xp) {
743 		if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) {
744 			NOREAD(pmcs_xscsi_t, wp->xp);
745 		} else {
746 			tgt = xs.target_num;
747 		}
748 	}
749 	if (wp->phy) {
750 		if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) {
751 			NOREAD(pmcs_phy_t, wp->phy);
752 		}
753 		path = phy.path;
754 	} else {
755 		path = "N/A";
756 	}
757 
758 	if (verbose) {
759 		mdb_printf("%4d ", idx);
760 	}
761 	if (tgt == -1) {
762 		mdb_printf("%08x %10s %20s      N/A %8u %1d %1d ",
763 		    wp->htag, state, path, wp->timer,
764 		    wp->onwire, wp->dead);
765 	} else {
766 		mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
767 		    wp->htag, state, path, tgt, wp->timer,
768 		    wp->onwire, wp->dead);
769 	}
770 	if (verbose) {
771 		mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n",
772 		    wp->last_htag, last_state, wp->last_phy, wp->last_xp,
773 		    wp->last_arg);
774 	} else {
775 		mdb_printf("\n");
776 	}
777 }
778 
779 static void
780 display_work(struct pmcs_hw m, int verbose)
781 {
782 	int		idx;
783 	boolean_t	header_printed = B_FALSE;
784 	pmcwork_t	work, *wp = &work;
785 	uintptr_t	_wp;
786 
787 	mdb_printf("\nActive Work structure information:\n");
788 	mdb_printf("----------------------------------\n");
789 
790 	_wp = (uintptr_t)m.work;
791 
792 	for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
793 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
794 			NOREAD(pmcwork_t, _wp);
795 			continue;
796 		}
797 
798 		if (!verbose && (wp->htag == PMCS_TAG_TYPE_FREE)) {
799 			continue;
800 		}
801 
802 		if (header_printed == B_FALSE) {
803 			if (verbose) {
804 				mdb_printf("%4s ", "Idx");
805 			}
806 			mdb_printf("%8s %10s %20s %8s %8s O D ",
807 			    "HTag", "State", "Phy Path", "Target", "Timer");
808 			if (verbose) {
809 				mdb_printf("%8s %10s %18s %18s %18s\n",
810 				    "LastHTAG", "LastState", "LastPHY",
811 				    "LastTgt", "LastArg");
812 			} else {
813 				mdb_printf("\n");
814 			}
815 			header_printed = B_TRUE;
816 		}
817 
818 		display_one_work(wp, verbose, idx);
819 	}
820 }
821 
822 static void
823 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose)
824 {
825 	int cdb_size, idx;
826 	struct scsi_pkt pkt;
827 	uchar_t cdb[256];
828 
829 	if (printhdr) {
830 		if (verbose) {
831 			mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
832 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
833 		} else {
834 			mdb_printf("%16s %16s %16s %8s %s\n", "Command",
835 			    "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
836 		}
837 	}
838 
839 	mdb_printf("%16p %16p %16p %08x %08x ",
840 	    kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag);
841 
842 	/*
843 	 * If we're printing verbose, dump the CDB as well.
844 	 */
845 	if (verbose) {
846 		if (sp->cmd_pkt) {
847 			if (mdb_vread(&pkt, sizeof (struct scsi_pkt),
848 			    (uintptr_t)sp->cmd_pkt) !=
849 			    sizeof (struct scsi_pkt)) {
850 				mdb_warn("Unable to read SCSI pkt\n");
851 				return;
852 			}
853 			cdb_size = pkt.pkt_cdblen;
854 			if (mdb_vread(&cdb[0], cdb_size,
855 			    (uintptr_t)pkt.pkt_cdbp) != cdb_size) {
856 				mdb_warn("Unable to read CDB\n");
857 				return;
858 			}
859 
860 			for (idx = 0; idx < cdb_size; idx++) {
861 				mdb_printf("%02x ", cdb[idx]);
862 			}
863 		} else {
864 			mdb_printf("N/A");
865 		}
866 
867 		mdb_printf("\n");
868 	} else {
869 		mdb_printf("\n");
870 	}
871 }
872 
873 /*ARGSUSED1*/
874 static void
875 display_waitqs(struct pmcs_hw m, int verbose)
876 {
877 	pmcs_cmd_t	*sp, s;
878 	pmcs_xscsi_t	xs;
879 	int		first, i;
880 	int		max_dev = m.max_dev;
881 
882 	sp = m.dq.stqh_first;
883 	first = 1;
884 	while (sp) {
885 		if (first) {
886 			mdb_printf("\nDead Command Queue:\n");
887 			mdb_printf("---------------------------\n");
888 		}
889 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
890 			NOREAD(pmcs_cmd_t, sp);
891 			break;
892 		}
893 		print_spcmd(&s, sp, first, verbose);
894 		sp = s.cmd_next.stqe_next;
895 		first = 0;
896 	}
897 
898 	sp = m.cq.stqh_first;
899 	first = 1;
900 	while (sp) {
901 		if (first) {
902 			mdb_printf("\nCompletion Command Queue:\n");
903 			mdb_printf("---------------------------\n");
904 		}
905 		if (MDB_RD(&s, sizeof (s), sp) == -1) {
906 			NOREAD(pmcs_cmd_t, sp);
907 			break;
908 		}
909 		print_spcmd(&s, sp, first, verbose);
910 		sp = s.cmd_next.stqe_next;
911 		first = 0;
912 	}
913 
914 
915 	if (targets == NULL) {
916 		targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
917 	}
918 
919 	if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
920 		NOREAD(targets, m.targets);
921 		return;
922 	}
923 
924 	for (i = 0; i < max_dev; i++) {
925 		if (targets[i] == NULL) {
926 			continue;
927 		}
928 		if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) {
929 			NOREAD(pmcs_xscsi_t, targets[i]);
930 			continue;
931 		}
932 		sp = xs.wq.stqh_first;
933 		first = 1;
934 		while (sp) {
935 			if (first) {
936 				mdb_printf("\nTarget %u Wait Queue:\n",
937 				    xs.target_num);
938 				mdb_printf("---------------------------\n");
939 			}
940 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
941 				NOREAD(pmcs_cmd_t, sp);
942 				break;
943 			}
944 			print_spcmd(&s, sp, first, verbose);
945 			sp = s.cmd_next.stqe_next;
946 			first = 0;
947 		}
948 		sp = xs.aq.stqh_first;
949 		first = 1;
950 		while (sp) {
951 			if (first) {
952 				mdb_printf("\nTarget %u Active Queue:\n",
953 				    xs.target_num);
954 				mdb_printf("---------------------------\n");
955 			}
956 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
957 				NOREAD(pmcs_cmd_t, sp);
958 				break;
959 			}
960 			print_spcmd(&s, sp, first, verbose);
961 			sp = s.cmd_next.stqe_next;
962 			first = 0;
963 		}
964 		sp = xs.sq.stqh_first;
965 		first = 1;
966 		while (sp) {
967 			if (first) {
968 				mdb_printf("\nTarget %u Special Queue:\n",
969 				    xs.target_num);
970 				mdb_printf("---------------------------\n");
971 			}
972 			if (MDB_RD(&s, sizeof (s), sp) == -1) {
973 				NOREAD(pmcs_cmd_t, sp);
974 				break;
975 			}
976 			print_spcmd(&s, sp, first, verbose);
977 			sp = s.cmd_next.stqe_next;
978 			first = 0;
979 		}
980 	}
981 }
982 
983 static char *
984 ibq_type(int qnum)
985 {
986 	if (qnum < 0 || qnum >= PMCS_NIQ) {
987 		return ("UNKNOWN");
988 	}
989 
990 	if (qnum < PMCS_IQ_OTHER) {
991 		return ("I/O");
992 	}
993 
994 	return ("Other");
995 }
996 
997 static char *
998 obq_type(int qnum)
999 {
1000 	switch (qnum) {
1001 	case PMCS_OQ_IODONE:
1002 		return ("I/O");
1003 		break;
1004 	case PMCS_OQ_GENERAL:
1005 		return ("General");
1006 		break;
1007 	case PMCS_OQ_EVENTS:
1008 		return ("Events");
1009 		break;
1010 	default:
1011 		return ("UNKNOWN");
1012 	}
1013 }
1014 
1015 static char *
1016 iomb_cat(uint32_t cat)
1017 {
1018 	switch (cat) {
1019 	case PMCS_IOMB_CAT_NET:
1020 		return ("NET");
1021 		break;
1022 	case PMCS_IOMB_CAT_FC:
1023 		return ("FC");
1024 		break;
1025 	case PMCS_IOMB_CAT_SAS:
1026 		return ("SAS");
1027 		break;
1028 	case PMCS_IOMB_CAT_SCSI:
1029 		return ("SCSI");
1030 		break;
1031 	default:
1032 		return ("???");
1033 	}
1034 }
1035 
1036 static char *
1037 iomb_event(uint8_t event)
1038 {
1039 	switch (event) {
1040 	case IOP_EVENT_PHY_STOP_STATUS:
1041 		return ("PHY STOP");
1042 		break;
1043 	case IOP_EVENT_SAS_PHY_UP:
1044 		return ("PHY UP");
1045 		break;
1046 	case IOP_EVENT_SATA_PHY_UP:
1047 		return ("SATA PHY UP");
1048 		break;
1049 	case IOP_EVENT_SATA_SPINUP_HOLD:
1050 		return ("SATA SPINUP HOLD");
1051 		break;
1052 	case IOP_EVENT_PHY_DOWN:
1053 		return ("PHY DOWN");
1054 		break;
1055 	case IOP_EVENT_BROADCAST_CHANGE:
1056 		return ("BROADCAST CHANGE");
1057 		break;
1058 	case IOP_EVENT_BROADCAST_SES:
1059 		return ("BROADCAST SES");
1060 		break;
1061 	case IOP_EVENT_PHY_ERR_INBOUND_CRC:
1062 		return ("INBOUND CRC ERROR");
1063 		break;
1064 	case IOP_EVENT_HARD_RESET_RECEIVED:
1065 		return ("HARD RESET");
1066 		break;
1067 	case IOP_EVENT_EVENT_ID_FRAME_TIMO:
1068 		return ("IDENTIFY FRAME TIMEOUT");
1069 		break;
1070 	case IOP_EVENT_BROADCAST_EXP:
1071 		return ("BROADCAST EXPANDER");
1072 		break;
1073 	case IOP_EVENT_PHY_START_STATUS:
1074 		return ("PHY START");
1075 		break;
1076 	case IOP_EVENT_PHY_ERR_INVALID_DWORD:
1077 		return ("INVALID DWORD");
1078 		break;
1079 	case IOP_EVENT_PHY_ERR_DISPARITY_ERROR:
1080 		return ("DISPARITY ERROR");
1081 		break;
1082 	case IOP_EVENT_PHY_ERR_CODE_VIOLATION:
1083 		return ("CODE VIOLATION");
1084 		break;
1085 	case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN:
1086 		return ("LOSS OF DWORD SYNC");
1087 		break;
1088 	case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD:
1089 		return ("PHY RESET FAILED");
1090 		break;
1091 	case IOP_EVENT_PORT_RECOVERY_TIMER_TMO:
1092 		return ("PORT RECOVERY TIMEOUT");
1093 		break;
1094 	case IOP_EVENT_PORT_RECOVER:
1095 		return ("PORT RECOVERY");
1096 		break;
1097 	case IOP_EVENT_PORT_RESET_TIMER_TMO:
1098 		return ("PORT RESET TIMEOUT");
1099 		break;
1100 	case IOP_EVENT_PORT_RESET_COMPLETE:
1101 		return ("PORT RESET COMPLETE");
1102 		break;
1103 	case IOP_EVENT_BROADCAST_ASYNC_EVENT:
1104 		return ("BROADCAST ASYNC");
1105 		break;
1106 	case IOP_EVENT_IT_NEXUS_LOSS:
1107 		return ("I/T NEXUS LOSS");
1108 		break;
1109 	default:
1110 		return ("Unknown Event");
1111 	}
1112 }
1113 
1114 static char *
1115 inbound_iomb_opcode(uint32_t opcode)
1116 {
1117 	switch (opcode) {
1118 	case PMCIN_ECHO:
1119 		return ("ECHO");
1120 		break;
1121 	case PMCIN_GET_INFO:
1122 		return ("GET_INFO");
1123 		break;
1124 	case PMCIN_GET_VPD:
1125 		return ("GET_VPD");
1126 		break;
1127 	case PMCIN_PHY_START:
1128 		return ("PHY_START");
1129 		break;
1130 	case PMCIN_PHY_STOP:
1131 		return ("PHY_STOP");
1132 		break;
1133 	case PMCIN_SSP_INI_IO_START:
1134 		return ("INI_IO_START");
1135 		break;
1136 	case PMCIN_SSP_INI_TM_START:
1137 		return ("INI_TM_START");
1138 		break;
1139 	case PMCIN_SSP_INI_EXT_IO_START:
1140 		return ("INI_EXT_IO_START");
1141 		break;
1142 	case PMCIN_DEVICE_HANDLE_ACCEPT:
1143 		return ("DEVICE_HANDLE_ACCEPT");
1144 		break;
1145 	case PMCIN_SSP_TGT_IO_START:
1146 		return ("TGT_IO_START");
1147 		break;
1148 	case PMCIN_SSP_TGT_RESPONSE_START:
1149 		return ("TGT_RESPONSE_START");
1150 		break;
1151 	case PMCIN_SSP_INI_EDC_EXT_IO_START:
1152 		return ("INI_EDC_EXT_IO_START");
1153 		break;
1154 	case PMCIN_SSP_INI_EDC_EXT_IO_START1:
1155 		return ("INI_EDC_EXT_IO_START1");
1156 		break;
1157 	case PMCIN_SSP_TGT_EDC_IO_START:
1158 		return ("TGT_EDC_IO_START");
1159 		break;
1160 	case PMCIN_SSP_ABORT:
1161 		return ("SSP_ABORT");
1162 		break;
1163 	case PMCIN_DEREGISTER_DEVICE_HANDLE:
1164 		return ("DEREGISTER_DEVICE_HANDLE");
1165 		break;
1166 	case PMCIN_GET_DEVICE_HANDLE:
1167 		return ("GET_DEVICE_HANDLE");
1168 		break;
1169 	case PMCIN_SMP_REQUEST:
1170 		return ("SMP_REQUEST");
1171 		break;
1172 	case PMCIN_SMP_RESPONSE:
1173 		return ("SMP_RESPONSE");
1174 		break;
1175 	case PMCIN_SMP_ABORT:
1176 		return ("SMP_ABORT");
1177 		break;
1178 	case PMCIN_ASSISTED_DISCOVERY:
1179 		return ("ASSISTED_DISCOVERY");
1180 		break;
1181 	case PMCIN_REGISTER_DEVICE:
1182 		return ("REGISTER_DEVICE");
1183 		break;
1184 	case PMCIN_SATA_HOST_IO_START:
1185 		return ("SATA_HOST_IO_START");
1186 		break;
1187 	case PMCIN_SATA_ABORT:
1188 		return ("SATA_ABORT");
1189 		break;
1190 	case PMCIN_LOCAL_PHY_CONTROL:
1191 		return ("LOCAL_PHY_CONTROL");
1192 		break;
1193 	case PMCIN_GET_DEVICE_INFO:
1194 		return ("GET_DEVICE_INFO");
1195 		break;
1196 	case PMCIN_TWI:
1197 		return ("TWI");
1198 		break;
1199 	case PMCIN_FW_FLASH_UPDATE:
1200 		return ("FW_FLASH_UPDATE");
1201 		break;
1202 	case PMCIN_SET_VPD:
1203 		return ("SET_VPD");
1204 		break;
1205 	case PMCIN_GPIO:
1206 		return ("GPIO");
1207 		break;
1208 	case PMCIN_SAS_DIAG_MODE_START_END:
1209 		return ("SAS_DIAG_MODE_START_END");
1210 		break;
1211 	case PMCIN_SAS_DIAG_EXECUTE:
1212 		return ("SAS_DIAG_EXECUTE");
1213 		break;
1214 	case PMCIN_SAW_HW_EVENT_ACK:
1215 		return ("SAS_HW_EVENT_ACK");
1216 		break;
1217 	case PMCIN_GET_TIME_STAMP:
1218 		return ("GET_TIME_STAMP");
1219 		break;
1220 	case PMCIN_PORT_CONTROL:
1221 		return ("PORT_CONTROL");
1222 		break;
1223 	case PMCIN_GET_NVMD_DATA:
1224 		return ("GET_NVMD_DATA");
1225 		break;
1226 	case PMCIN_SET_NVMD_DATA:
1227 		return ("SET_NVMD_DATA");
1228 		break;
1229 	case PMCIN_SET_DEVICE_STATE:
1230 		return ("SET_DEVICE_STATE");
1231 		break;
1232 	case PMCIN_GET_DEVICE_STATE:
1233 		return ("GET_DEVICE_STATE");
1234 		break;
1235 	default:
1236 		return ("UNKNOWN");
1237 		break;
1238 	}
1239 }
1240 
1241 static char *
1242 outbound_iomb_opcode(uint32_t opcode)
1243 {
1244 	switch (opcode) {
1245 	case PMCOUT_ECHO:
1246 		return ("ECHO");
1247 		break;
1248 	case PMCOUT_GET_INFO:
1249 		return ("GET_INFO");
1250 		break;
1251 	case PMCOUT_GET_VPD:
1252 		return ("GET_VPD");
1253 		break;
1254 	case PMCOUT_SAS_HW_EVENT:
1255 		return ("SAS_HW_EVENT");
1256 		break;
1257 	case PMCOUT_SSP_COMPLETION:
1258 		return ("SSP_COMPLETION");
1259 		break;
1260 	case PMCOUT_SMP_COMPLETION:
1261 		return ("SMP_COMPLETION");
1262 		break;
1263 	case PMCOUT_LOCAL_PHY_CONTROL:
1264 		return ("LOCAL_PHY_CONTROL");
1265 		break;
1266 	case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT:
1267 		return ("SAS_ASSISTED_DISCOVERY_SENT");
1268 		break;
1269 	case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT:
1270 		return ("SATA_ASSISTED_DISCOVERY_SENT");
1271 		break;
1272 	case PMCOUT_DEVICE_REGISTRATION:
1273 		return ("DEVICE_REGISTRATION");
1274 		break;
1275 	case PMCOUT_DEREGISTER_DEVICE_HANDLE:
1276 		return ("DEREGISTER_DEVICE_HANDLE");
1277 		break;
1278 	case PMCOUT_GET_DEVICE_HANDLE:
1279 		return ("GET_DEVICE_HANDLE");
1280 		break;
1281 	case PMCOUT_SATA_COMPLETION:
1282 		return ("SATA_COMPLETION");
1283 		break;
1284 	case PMCOUT_SATA_EVENT:
1285 		return ("SATA_EVENT");
1286 		break;
1287 	case PMCOUT_SSP_EVENT:
1288 		return ("SSP_EVENT");
1289 		break;
1290 	case PMCOUT_DEVICE_HANDLE_ARRIVED:
1291 		return ("DEVICE_HANDLE_ARRIVED");
1292 		break;
1293 	case PMCOUT_SMP_REQUEST_RECEIVED:
1294 		return ("SMP_REQUEST_RECEIVED");
1295 		break;
1296 	case PMCOUT_SSP_REQUEST_RECEIVED:
1297 		return ("SSP_REQUEST_RECEIVED");
1298 		break;
1299 	case PMCOUT_DEVICE_INFO:
1300 		return ("DEVICE_INFO");
1301 		break;
1302 	case PMCOUT_FW_FLASH_UPDATE:
1303 		return ("FW_FLASH_UPDATE");
1304 		break;
1305 	case PMCOUT_SET_VPD:
1306 		return ("SET_VPD");
1307 		break;
1308 	case PMCOUT_GPIO:
1309 		return ("GPIO");
1310 		break;
1311 	case PMCOUT_GPIO_EVENT:
1312 		return ("GPIO_EVENT");
1313 		break;
1314 	case PMCOUT_GENERAL_EVENT:
1315 		return ("GENERAL_EVENT");
1316 		break;
1317 	case PMCOUT_TWI:
1318 		return ("TWI");
1319 		break;
1320 	case PMCOUT_SSP_ABORT:
1321 		return ("SSP_ABORT");
1322 		break;
1323 	case PMCOUT_SATA_ABORT:
1324 		return ("SATA_ABORT");
1325 		break;
1326 	case PMCOUT_SAS_DIAG_MODE_START_END:
1327 		return ("SAS_DIAG_MODE_START_END");
1328 		break;
1329 	case PMCOUT_SAS_DIAG_EXECUTE:
1330 		return ("SAS_DIAG_EXECUTE");
1331 		break;
1332 	case PMCOUT_GET_TIME_STAMP:
1333 		return ("GET_TIME_STAMP");
1334 		break;
1335 	case PMCOUT_SAS_HW_EVENT_ACK_ACK:
1336 		return ("SAS_HW_EVENT_ACK_ACK");
1337 		break;
1338 	case PMCOUT_PORT_CONTROL:
1339 		return ("PORT_CONTROL");
1340 		break;
1341 	case PMCOUT_SKIP_ENTRIES:
1342 		return ("SKIP_ENTRIES");
1343 		break;
1344 	case PMCOUT_SMP_ABORT:
1345 		return ("SMP_ABORT");
1346 		break;
1347 	case PMCOUT_GET_NVMD_DATA:
1348 		return ("GET_NVMD_DATA");
1349 		break;
1350 	case PMCOUT_SET_NVMD_DATA:
1351 		return ("SET_NVMD_DATA");
1352 		break;
1353 	case PMCOUT_DEVICE_HANDLE_REMOVED:
1354 		return ("DEVICE_HANDLE_REMOVED");
1355 		break;
1356 	case PMCOUT_SET_DEVICE_STATE:
1357 		return ("SET_DEVICE_STATE");
1358 		break;
1359 	case PMCOUT_GET_DEVICE_STATE:
1360 		return ("GET_DEVICE_STATE");
1361 		break;
1362 	case PMCOUT_SET_DEVICE_INFO:
1363 		return ("SET_DEVICE_INFO");
1364 		break;
1365 	default:
1366 		return ("UNKNOWN");
1367 		break;
1368 	}
1369 }
1370 
1371 static void
1372 dump_one_qentry_outbound(uint32_t *qentryp, int idx)
1373 {
1374 	int qeidx;
1375 	uint32_t word0 = LE_32(*qentryp);
1376 	uint32_t word1 = LE_32(*(qentryp + 1));
1377 	uint8_t iop_event;
1378 
1379 	mdb_printf("Entry #%02d\n", idx);
1380 	mdb_inc_indent(2);
1381 
1382 	mdb_printf("Header: 0x%08x (", word0);
1383 	if (word0 & PMCS_IOMB_VALID) {
1384 		mdb_printf("VALID, ");
1385 	}
1386 	if (word0 & PMCS_IOMB_HIPRI) {
1387 		mdb_printf("HIPRI, ");
1388 	}
1389 	mdb_printf("OBID=%d, ",
1390 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
1391 	mdb_printf("CAT=%s, ",
1392 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
1393 	mdb_printf("OPCODE=%s",
1394 	    outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
1395 	if ((word0 & PMCS_IOMB_OPCODE_MASK) == PMCOUT_SAS_HW_EVENT) {
1396 		iop_event = IOP_EVENT_EVENT(word1);
1397 		mdb_printf(" <%s>", iomb_event(iop_event));
1398 	}
1399 	mdb_printf(")\n");
1400 
1401 	mdb_printf("Remaining Payload:\n");
1402 
1403 	mdb_inc_indent(2);
1404 	for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
1405 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
1406 	}
1407 	mdb_printf("\n");
1408 	mdb_dec_indent(4);
1409 }
1410 
1411 static void
1412 display_outbound_queues(struct pmcs_hw ss, uint_t verbose)
1413 {
1414 	int		idx, qidx;
1415 	uintptr_t	obqp;
1416 	uint32_t	*cip;
1417 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
1418 	uint32_t	last_consumed, oqpi;
1419 
1420 	mdb_printf("\n");
1421 	mdb_printf("Outbound Queues\n");
1422 	mdb_printf("---------------\n");
1423 
1424 	mdb_inc_indent(2);
1425 
1426 	for (qidx = 0; qidx < PMCS_NOQ; qidx++) {
1427 		obqp = (uintptr_t)ss.oqp[qidx];
1428 
1429 		if (obqp == NULL) {
1430 			mdb_printf("No outbound queue ptr for queue #%d\n",
1431 			    qidx);
1432 			continue;
1433 		}
1434 
1435 		mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx,
1436 		    obq_type(qidx));
1437 		/*
1438 		 * Chip is the producer, so read the actual producer index
1439 		 * and not the driver's version
1440 		 */
1441 		cip = (uint32_t *)((void *)ss.cip);
1442 		if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET +
1443 		    (qidx * 4)) == -1) {
1444 			mdb_warn("Couldn't read oqpi\n");
1445 			break;
1446 		}
1447 
1448 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
1449 		    LE_32(oqpi), ss.oqci[qidx]);
1450 		mdb_inc_indent(2);
1451 
1452 		if (ss.oqci[qidx] == 0) {
1453 			last_consumed = ss.ioq_depth - 1;
1454 		} else {
1455 			last_consumed = ss.oqci[qidx] - 1;
1456 		}
1457 
1458 
1459 		if (!verbose) {
1460 			mdb_printf("Last processed entry:\n");
1461 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1462 			    (obqp + (PMCS_QENTRY_SIZE * last_consumed)))
1463 			    == -1) {
1464 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1465 				    (obqp + (PMCS_QENTRY_SIZE *
1466 				    last_consumed)));
1467 				break;
1468 			}
1469 			dump_one_qentry_outbound(qentryp, last_consumed);
1470 			mdb_printf("\n");
1471 			mdb_dec_indent(2);
1472 			continue;
1473 		}
1474 
1475 		for (idx = 0; idx < ss.ioq_depth; idx++) {
1476 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1477 			    (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
1478 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1479 				    (obqp + (PMCS_QENTRY_SIZE * idx)));
1480 				break;
1481 			}
1482 			dump_one_qentry_outbound(qentryp, idx);
1483 		}
1484 
1485 		mdb_printf("\n");
1486 		mdb_dec_indent(2);
1487 	}
1488 
1489 	mdb_dec_indent(2);
1490 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
1491 }
1492 
1493 static void
1494 dump_one_qentry_inbound(uint32_t *qentryp, int idx)
1495 {
1496 	int qeidx;
1497 	uint32_t word0 = LE_32(*qentryp);
1498 
1499 	mdb_printf("Entry #%02d\n", idx);
1500 	mdb_inc_indent(2);
1501 
1502 	mdb_printf("Header: 0x%08x (", word0);
1503 	if (word0 & PMCS_IOMB_VALID) {
1504 		mdb_printf("VALID, ");
1505 	}
1506 	if (word0 & PMCS_IOMB_HIPRI) {
1507 		mdb_printf("HIPRI, ");
1508 	}
1509 	mdb_printf("OBID=%d, ",
1510 	    (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
1511 	mdb_printf("CAT=%s, ",
1512 	    iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
1513 	mdb_printf("OPCODE=%s",
1514 	    inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
1515 	mdb_printf(")\n");
1516 
1517 	mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1)));
1518 	mdb_printf("Remaining Payload:\n");
1519 
1520 	mdb_inc_indent(2);
1521 	for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
1522 		mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
1523 	}
1524 	mdb_printf("\n");
1525 	mdb_dec_indent(4);
1526 }
1527 
1528 static void
1529 display_inbound_queues(struct pmcs_hw ss, uint_t verbose)
1530 {
1531 	int		idx, qidx, iqci, last_consumed;
1532 	uintptr_t	ibqp;
1533 	uint32_t	*qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
1534 	uint32_t	*cip;
1535 
1536 	mdb_printf("\n");
1537 	mdb_printf("Inbound Queues\n");
1538 	mdb_printf("--------------\n");
1539 
1540 	mdb_inc_indent(2);
1541 
1542 	for (qidx = 0; qidx < PMCS_NIQ; qidx++) {
1543 		ibqp = (uintptr_t)ss.iqp[qidx];
1544 
1545 		if (ibqp == NULL) {
1546 			mdb_printf("No inbound queue ptr for queue #%d\n",
1547 			    qidx);
1548 			continue;
1549 		}
1550 
1551 		mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx,
1552 		    ibq_type(qidx));
1553 
1554 		cip = (uint32_t *)((void *)ss.cip);
1555 		if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) {
1556 			mdb_warn("Couldn't read iqci\n");
1557 			break;
1558 		}
1559 		iqci = LE_32(iqci);
1560 
1561 		mdb_printf("Producer index: %d  Consumer index: %d\n\n",
1562 		    ss.shadow_iqpi[qidx], iqci);
1563 		mdb_inc_indent(2);
1564 
1565 		if (iqci == 0) {
1566 			last_consumed = ss.ioq_depth - 1;
1567 		} else {
1568 			last_consumed = iqci - 1;
1569 		}
1570 
1571 		if (!verbose) {
1572 			mdb_printf("Last processed entry:\n");
1573 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1574 			    (ibqp + (PMCS_QENTRY_SIZE * last_consumed)))
1575 			    == -1) {
1576 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1577 				    (ibqp + (PMCS_QENTRY_SIZE *
1578 				    last_consumed)));
1579 				break;
1580 			}
1581 			dump_one_qentry_inbound(qentryp, last_consumed);
1582 			mdb_printf("\n");
1583 			mdb_dec_indent(2);
1584 			continue;
1585 		}
1586 
1587 		for (idx = 0; idx < ss.ioq_depth; idx++) {
1588 			if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1589 			    (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
1590 				mdb_warn("Couldn't read queue entry at 0x%p\n",
1591 				    (ibqp + (PMCS_QENTRY_SIZE * idx)));
1592 				break;
1593 			}
1594 			dump_one_qentry_inbound(qentryp, idx);
1595 		}
1596 
1597 		mdb_printf("\n");
1598 		mdb_dec_indent(2);
1599 	}
1600 
1601 	mdb_dec_indent(2);
1602 	mdb_free(qentryp, PMCS_QENTRY_SIZE);
1603 }
1604 
1605 /*
1606  * phy is our copy of the PHY structure.  phyp is the pointer to the actual
1607  * kernel PHY data structure
1608  */
1609 static void
1610 display_phy(struct pmcs_phy phy, struct pmcs_phy *phyp, int verbose,
1611     int totals_only)
1612 {
1613 	char		*dtype, *speed;
1614 	char		*yes = "Yes";
1615 	char		*no = "No";
1616 	char		*cfgd = no;
1617 	char		*apend = no;
1618 	char		*asent = no;
1619 	char		*dead = no;
1620 	char		*changed = no;
1621 	char		route_attr, route_method;
1622 
1623 	switch (phy.dtype) {
1624 	case NOTHING:
1625 		dtype = "None";
1626 		break;
1627 	case SATA:
1628 		dtype = "SATA";
1629 		if (phy.configured) {
1630 			++sata_phys;
1631 		}
1632 		break;
1633 	case SAS:
1634 		dtype = "SAS";
1635 		if (phy.configured) {
1636 			++sas_phys;
1637 		}
1638 		break;
1639 	case EXPANDER:
1640 		dtype = "EXP";
1641 		if (phy.configured) {
1642 			++exp_phys;
1643 		}
1644 		break;
1645 	}
1646 
1647 	if (phy.dtype == NOTHING) {
1648 		empty_phys++;
1649 	} else if ((phy.dtype == EXPANDER) && phy.configured) {
1650 		num_expanders++;
1651 	}
1652 
1653 	if (totals_only) {
1654 		return;
1655 	}
1656 
1657 	switch (phy.link_rate) {
1658 	case SAS_LINK_RATE_1_5GBIT:
1659 		speed = "1.5Gb/s";
1660 		break;
1661 	case SAS_LINK_RATE_3GBIT:
1662 		speed = "3 Gb/s";
1663 		break;
1664 	case SAS_LINK_RATE_6GBIT:
1665 		speed = "6 Gb/s";
1666 		break;
1667 	default:
1668 		speed = "N/A";
1669 		break;
1670 	}
1671 
1672 	if ((phy.dtype != NOTHING) || verbose) {
1673 		print_sas_address(&phy);
1674 
1675 		if (phy.device_id != PMCS_INVALID_DEVICE_ID) {
1676 			mdb_printf(" %3d %4d %6s %4s ",
1677 			    phy.device_id, phy.phynum, speed, dtype);
1678 		} else {
1679 			mdb_printf(" N/A %4d %6s %4s ",
1680 			    phy.phynum, speed, dtype);
1681 		}
1682 
1683 		if (verbose) {
1684 			if (phy.abort_sent) {
1685 				asent = yes;
1686 			}
1687 			if (phy.abort_pending) {
1688 				apend = yes;
1689 			}
1690 			if (phy.configured) {
1691 				cfgd = yes;
1692 			}
1693 			if (phy.dead) {
1694 				dead = yes;
1695 			}
1696 			if (phy.changed) {
1697 				changed = yes;
1698 			}
1699 
1700 			switch (phy.routing_attr) {
1701 			case SMP_ROUTING_DIRECT:
1702 				route_attr = 'D';
1703 				break;
1704 			case SMP_ROUTING_SUBTRACTIVE:
1705 				route_attr = 'S';
1706 				break;
1707 			case SMP_ROUTING_TABLE:
1708 				route_attr = 'T';
1709 				break;
1710 			default:
1711 				route_attr = '?';
1712 				break;
1713 			}
1714 
1715 			switch (phy.routing_method) {
1716 			case SMP_ROUTING_DIRECT:
1717 				route_method = 'D';
1718 				break;
1719 			case SMP_ROUTING_SUBTRACTIVE:
1720 				route_method = 'S';
1721 				break;
1722 			case SMP_ROUTING_TABLE:
1723 				route_method = 'T';
1724 				break;
1725 			default:
1726 				route_attr = '?';
1727 				break;
1728 			}
1729 
1730 			mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d "
1731 			    "%1d 0x%p ", cfgd, apend, asent, changed, dead,
1732 			    phy.ref_count, route_attr, route_method,
1733 			    phy.enum_attempts, phy.reenumerate, phy.phy_lock);
1734 		}
1735 
1736 		mdb_printf("Path: %s\n", phy.path);
1737 
1738 		/*
1739 		 * In verbose mode, on the next line print the drill down
1740 		 * info to see either the DISCOVER response or the REPORT
1741 		 * GENERAL response depending on the PHY's dtype
1742 		 */
1743 		if (verbose) {
1744 			uintptr_t tphyp = (uintptr_t)phyp;
1745 
1746 			mdb_inc_indent(4);
1747 			switch (phy.dtype) {
1748 			case EXPANDER:
1749 				if (!phy.configured) {
1750 					break;
1751 				}
1752 				mdb_printf("REPORT GENERAL response: %p::"
1753 				    "print smp_report_general_resp_t\n",
1754 				    (tphyp + offsetof(struct pmcs_phy,
1755 				    rg_resp)));
1756 				break;
1757 			case SAS:
1758 			case SATA:
1759 				mdb_printf("DISCOVER response: %p::"
1760 				    "print smp_discover_resp_t\n",
1761 				    (tphyp + offsetof(struct pmcs_phy,
1762 				    disc_resp)));
1763 				break;
1764 			default:
1765 				break;
1766 			}
1767 			mdb_dec_indent(4);
1768 		}
1769 	}
1770 }
1771 
1772 static void
1773 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level,
1774     int totals_only)
1775 {
1776 	pmcs_phy_t	phy;
1777 	pmcs_phy_t	*pphy = parent;
1778 
1779 	mdb_inc_indent(3);
1780 
1781 	if (parent == NULL) {
1782 		pphy = (pmcs_phy_t *)ss.root_phys;
1783 	} else {
1784 		pphy = (pmcs_phy_t *)parent;
1785 	}
1786 
1787 	if (level == 0) {
1788 		sas_phys = 0;
1789 		sata_phys = 0;
1790 		exp_phys = 0;
1791 		num_expanders = 0;
1792 		empty_phys = 0;
1793 	}
1794 
1795 	if (!totals_only) {
1796 		if (level == 0) {
1797 			mdb_printf("PHY information\n");
1798 		}
1799 		mdb_printf("--------\n");
1800 		mdb_printf("Level %2d\n", level);
1801 		mdb_printf("--------\n");
1802 		mdb_printf("SAS Address      Hdl Phy#  Speed Type ");
1803 
1804 		if (verbose) {
1805 			mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R "
1806 			    "Lock\n");
1807 		} else {
1808 			mdb_printf("\n");
1809 		}
1810 	}
1811 
1812 	while (pphy) {
1813 		if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) {
1814 			NOREAD(pmcs_phy_t, phy);
1815 			break;
1816 		}
1817 
1818 		display_phy(phy, pphy, verbose, totals_only);
1819 
1820 		if (phy.children) {
1821 			display_phys(ss, verbose, phy.children, level + 1,
1822 			    totals_only);
1823 			if (!totals_only) {
1824 				mdb_printf("\n");
1825 			}
1826 		}
1827 
1828 		pphy = phy.sibling;
1829 	}
1830 
1831 	mdb_dec_indent(3);
1832 
1833 	if (level == 0) {
1834 		if (verbose) {
1835 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
1836 			    "(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
1837 			    (sas_phys + sata_phys + num_expanders),
1838 			    sas_phys, sata_phys, num_expanders,
1839 			    (exp_phys - num_expanders), empty_phys);
1840 		} else {
1841 			mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
1842 			    "Occupied PHYs:",
1843 			    (sas_phys + sata_phys + num_expanders),
1844 			    sas_phys, sata_phys, num_expanders);
1845 		}
1846 	}
1847 }
1848 
1849 /*
1850  * filter is used to indicate whether we are filtering log messages based
1851  * on "instance".  The other filtering (based on options) depends on the
1852  * values that are passed in for "sas_addr" and "phy_path".
1853  *
1854  * MAX_INST_STRLEN is the largest string size from which we will attempt
1855  * to convert to an instance number.  The string will be formed up as
1856  * "0t<inst>\0" so that mdb_strtoull can parse it properly.
1857  */
1858 #define	MAX_INST_STRLEN	8
1859 
1860 static int
1861 pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines,
1862     const char *phy_path, uint64_t sas_address)
1863 {
1864 	pmcs_tbuf_t *tbuf_addr;
1865 	uint_t tbuf_idx;
1866 	pmcs_tbuf_t tbuf;
1867 	boolean_t wrap, elem_filtered;
1868 	uint_t start_idx, elems_to_print, idx, tbuf_num_elems;
1869 	char *bufp;
1870 	char elem_inst[MAX_INST_STRLEN], ei_idx;
1871 	uint64_t sas_addr;
1872 	uint8_t *sas_addressp;
1873 
1874 	/* Get the address of the first element */
1875 	if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) {
1876 		mdb_warn("can't read pmcs_tbuf");
1877 		return (DCMD_ERR);
1878 	}
1879 
1880 	/* Get the total number */
1881 	if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) {
1882 		mdb_warn("can't read pmcs_tbuf_num_elems");
1883 		return (DCMD_ERR);
1884 	}
1885 
1886 	/* Get the current index */
1887 	if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) {
1888 		mdb_warn("can't read pmcs_tbuf_idx");
1889 		return (DCMD_ERR);
1890 	}
1891 
1892 	/* Indicator as to whether the buffer has wrapped */
1893 	if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) {
1894 		mdb_warn("can't read pmcs_tbuf_wrap");
1895 		return (DCMD_ERR);
1896 	}
1897 
1898 	/*
1899 	 * On little-endian systems, the SAS address passed in will be
1900 	 * byte swapped.  Take care of that here.
1901 	 */
1902 #if defined(_LITTLE_ENDIAN)
1903 	sas_addr = ((sas_address << 56) |
1904 	    ((sas_address << 40) & 0xff000000000000ULL) |
1905 	    ((sas_address << 24) & 0xff0000000000ULL) |
1906 	    ((sas_address << 8)  & 0xff00000000ULL) |
1907 	    ((sas_address >> 8)  & 0xff000000ULL) |
1908 	    ((sas_address >> 24) & 0xff0000ULL) |
1909 	    ((sas_address >> 40) & 0xff00ULL) |
1910 	    (sas_address  >> 56));
1911 #else
1912 	sas_addr = sas_address;
1913 #endif
1914 	sas_addressp = (uint8_t *)&sas_addr;
1915 
1916 	/* Ensure the tail number isn't greater than the size of the log */
1917 	if (tail_lines > tbuf_num_elems) {
1918 		tail_lines = tbuf_num_elems;
1919 	}
1920 
1921 	/* Figure out where we start and stop */
1922 	if (wrap) {
1923 		if (tail_lines) {
1924 			/* Do we need to wrap backwards? */
1925 			if (tail_lines > tbuf_idx) {
1926 				start_idx = tbuf_num_elems - (tail_lines -
1927 				    tbuf_idx);
1928 			} else {
1929 				start_idx = tbuf_idx - tail_lines;
1930 			}
1931 			elems_to_print = tail_lines;
1932 		} else {
1933 			start_idx = tbuf_idx;
1934 			elems_to_print = tbuf_num_elems;
1935 		}
1936 	} else {
1937 		if (tail_lines > tbuf_idx) {
1938 			tail_lines = tbuf_idx;
1939 		}
1940 		if (tail_lines) {
1941 			start_idx = tbuf_idx - tail_lines;
1942 			elems_to_print = tail_lines;
1943 		} else {
1944 			start_idx = 0;
1945 			elems_to_print = tbuf_idx;
1946 		}
1947 	}
1948 
1949 	idx = start_idx;
1950 
1951 	/* Dump the buffer contents */
1952 	while (elems_to_print != 0) {
1953 		if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx))
1954 		    == -1) {
1955 			NOREAD(tbuf, (tbuf_addr + idx));
1956 			return (DCMD_ERR);
1957 		}
1958 
1959 		/*
1960 		 * Check for filtering on HBA instance
1961 		 */
1962 		elem_filtered = B_FALSE;
1963 
1964 		if (filter) {
1965 			bufp = tbuf.buf;
1966 			/* Skip the driver name */
1967 			while (*bufp < '0' || *bufp > '9') {
1968 				bufp++;
1969 			}
1970 
1971 			ei_idx = 0;
1972 			elem_inst[ei_idx++] = '0';
1973 			elem_inst[ei_idx++] = 't';
1974 			while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) {
1975 				elem_inst[ei_idx++] = *bufp;
1976 				bufp++;
1977 			}
1978 			elem_inst[ei_idx] = 0;
1979 
1980 			/* Get the instance */
1981 			if ((int)mdb_strtoull(elem_inst) != instance) {
1982 				elem_filtered = B_TRUE;
1983 			}
1984 		}
1985 
1986 		if (!elem_filtered && (phy_path || sas_address)) {
1987 			/*
1988 			 * This message is not being filtered by HBA instance.
1989 			 * Now check to see if we're filtering based on
1990 			 * PHY path or SAS address.
1991 			 * Filtering is an "OR" operation.  So, if any of the
1992 			 * criteria matches, this message will be printed.
1993 			 */
1994 			elem_filtered = B_TRUE;
1995 
1996 			if (phy_path != NULL) {
1997 				if (strncmp(phy_path, tbuf.phy_path,
1998 				    PMCS_TBUF_UA_MAX_SIZE) == 0) {
1999 					elem_filtered = B_FALSE;
2000 				}
2001 			}
2002 			if (sas_address != 0) {
2003 				if (memcmp(sas_addressp, tbuf.phy_sas_address,
2004 				    8) == 0) {
2005 					elem_filtered = B_FALSE;
2006 				}
2007 			}
2008 		}
2009 
2010 		if (!elem_filtered) {
2011 			mdb_printf("%Y.%09ld %s\n", tbuf.timestamp, tbuf.buf);
2012 		}
2013 
2014 		--elems_to_print;
2015 		if (++idx == tbuf_num_elems) {
2016 			idx = 0;
2017 		}
2018 	}
2019 
2020 	return (DCMD_OK);
2021 }
2022 
2023 /*
2024  * Walkers
2025  */
2026 static int
2027 targets_walk_i(mdb_walk_state_t *wsp)
2028 {
2029 	if (wsp->walk_addr == NULL) {
2030 		mdb_warn("Can not perform global walk\n");
2031 		return (WALK_ERR);
2032 	}
2033 
2034 	/*
2035 	 * Address provided belongs to HBA softstate.  Get the targets pointer
2036 	 * to begin the walk.
2037 	 */
2038 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
2039 	    sizeof (pmcs_hw_t)) {
2040 		mdb_warn("Unable to read HBA softstate\n");
2041 		return (WALK_ERR);
2042 	}
2043 
2044 	if (targets == NULL) {
2045 		targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP);
2046 	}
2047 
2048 	if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) {
2049 		NOREAD(targets, ss.targets);
2050 		return (WALK_ERR);
2051 	}
2052 
2053 	target_idx = 0;
2054 	wsp->walk_addr = (uintptr_t)(targets[0]);
2055 	wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP);
2056 
2057 	return (WALK_NEXT);
2058 }
2059 
2060 static int
2061 targets_walk_s(mdb_walk_state_t *wsp)
2062 {
2063 	int status;
2064 
2065 	if (target_idx == ss.max_dev) {
2066 		return (WALK_DONE);
2067 	}
2068 
2069 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t),
2070 	    wsp->walk_addr) == -1) {
2071 		mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr);
2072 		return (WALK_DONE);
2073 	}
2074 
2075 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2076 	    wsp->walk_cbdata);
2077 
2078 	do {
2079 		wsp->walk_addr = (uintptr_t)(targets[++target_idx]);
2080 	} while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev));
2081 
2082 	if (target_idx == ss.max_dev) {
2083 		return (WALK_DONE);
2084 	}
2085 
2086 	return (status);
2087 }
2088 
2089 static void
2090 targets_walk_f(mdb_walk_state_t *wsp)
2091 {
2092 	mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t));
2093 }
2094 
2095 
2096 static pmcs_phy_t *
2097 pmcs_next_sibling(pmcs_phy_t *phyp)
2098 {
2099 	pmcs_phy_t parent;
2100 
2101 	/*
2102 	 * First, if this is a root PHY, there are no more siblings
2103 	 */
2104 	if (phyp->level == 0) {
2105 		return (NULL);
2106 	}
2107 
2108 	/*
2109 	 * Otherwise, next sibling is the parent's sibling
2110 	 */
2111 	while (phyp->level > 0) {
2112 		if (mdb_vread(&parent, sizeof (pmcs_phy_t),
2113 		    (uintptr_t)phyp->parent) == -1) {
2114 			mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
2115 			    (void *)phyp->parent);
2116 			return (NULL);
2117 		}
2118 
2119 		if (parent.sibling != NULL) {
2120 			break;
2121 		}
2122 
2123 		/*
2124 		 * If this PHY's sibling is NULL and it's a root phy,
2125 		 * we're done.
2126 		 */
2127 		if (parent.level == 0) {
2128 			return (NULL);
2129 		}
2130 
2131 		phyp = phyp->parent;
2132 	}
2133 
2134 	return (parent.sibling);
2135 }
2136 
2137 static int
2138 phy_walk_i(mdb_walk_state_t *wsp)
2139 {
2140 	if (wsp->walk_addr == NULL) {
2141 		mdb_warn("Can not perform global walk\n");
2142 		return (WALK_ERR);
2143 	}
2144 
2145 	/*
2146 	 * Address provided belongs to HBA softstate.  Get the targets pointer
2147 	 * to begin the walk.
2148 	 */
2149 	if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
2150 	    sizeof (pmcs_hw_t)) {
2151 		mdb_warn("Unable to read HBA softstate\n");
2152 		return (WALK_ERR);
2153 	}
2154 
2155 	wsp->walk_addr = (uintptr_t)(ss.root_phys);
2156 	wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
2157 
2158 	return (WALK_NEXT);
2159 }
2160 
2161 static int
2162 phy_walk_s(mdb_walk_state_t *wsp)
2163 {
2164 	pmcs_phy_t *phyp, *nphyp;
2165 	int status;
2166 
2167 	if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t),
2168 	    wsp->walk_addr) == -1) {
2169 		mdb_warn("phy_walk_s: Failed to read PHY at %p",
2170 		    (void *)wsp->walk_addr);
2171 		return (WALK_DONE);
2172 	}
2173 
2174 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2175 	    wsp->walk_cbdata);
2176 
2177 	phyp = (pmcs_phy_t *)wsp->walk_data;
2178 	if (phyp->children) {
2179 		wsp->walk_addr = (uintptr_t)(phyp->children);
2180 	} else {
2181 		wsp->walk_addr = (uintptr_t)(phyp->sibling);
2182 	}
2183 
2184 	if (wsp->walk_addr == NULL) {
2185 		/*
2186 		 * We reached the end of this sibling list.  Trudge back up
2187 		 * to the parent and find the next sibling after the expander
2188 		 * we just finished traversing, if there is one.
2189 		 */
2190 		nphyp = pmcs_next_sibling(phyp);
2191 
2192 		if (nphyp == NULL) {
2193 			return (WALK_DONE);
2194 		}
2195 
2196 		wsp->walk_addr = (uintptr_t)nphyp;
2197 	}
2198 
2199 	return (status);
2200 }
2201 
2202 static void
2203 phy_walk_f(mdb_walk_state_t *wsp)
2204 {
2205 	mdb_free(wsp->walk_data, sizeof (pmcs_phy_t));
2206 }
2207 
2208 static void
2209 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum,
2210     uintmax_t tag_type)
2211 {
2212 	int		idx;
2213 	pmcwork_t	work, *wp = &work;
2214 	uintptr_t	_wp;
2215 	boolean_t	printed_header = B_FALSE;
2216 	uint32_t	mask, mask_val, match_val;
2217 	char		*match_type;
2218 
2219 	if (index != UINT_MAX) {
2220 		match_type = "index";
2221 		mask = PMCS_TAG_INDEX_MASK;
2222 		mask_val = index << PMCS_TAG_INDEX_SHIFT;
2223 		match_val = index;
2224 	} else if (snum != UINT_MAX) {
2225 		match_type = "serial number";
2226 		mask = PMCS_TAG_SERNO_MASK;
2227 		mask_val = snum << PMCS_TAG_SERNO_SHIFT;
2228 		match_val = snum;
2229 	} else {
2230 		switch (tag_type) {
2231 		case PMCS_TAG_TYPE_NONE:
2232 			match_type = "tag type NONE";
2233 			break;
2234 		case PMCS_TAG_TYPE_CBACK:
2235 			match_type = "tag type CBACK";
2236 			break;
2237 		case PMCS_TAG_TYPE_WAIT:
2238 			match_type = "tag type WAIT";
2239 			break;
2240 		}
2241 		mask = PMCS_TAG_TYPE_MASK;
2242 		mask_val = tag_type << PMCS_TAG_TYPE_SHIFT;
2243 		match_val = tag_type;
2244 	}
2245 
2246 	_wp = (uintptr_t)ss.work;
2247 
2248 	for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
2249 		if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
2250 			NOREAD(pmcwork_t, _wp);
2251 			continue;
2252 		}
2253 
2254 		if ((work.htag & mask) != mask_val) {
2255 			continue;
2256 		}
2257 
2258 		if (printed_header == B_FALSE) {
2259 			if (tag_type) {
2260 				mdb_printf("\nWork structures matching %s\n\n",
2261 				    match_type, match_val);
2262 			} else {
2263 				mdb_printf("\nWork structures matching %s of "
2264 				    "0x%x\n\n", match_type, match_val);
2265 			}
2266 			mdb_printf("%8s %10s %20s %8s %8s O D\n",
2267 			    "HTag", "State", "Phy Path", "Target", "Timer");
2268 			printed_header = B_TRUE;
2269 		}
2270 
2271 		display_one_work(wp, 0, 0);
2272 	}
2273 
2274 	if (!printed_header) {
2275 		mdb_printf("No work structure matches found\n");
2276 	}
2277 }
2278 
2279 static int
2280 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2281 {
2282 	struct	pmcs_hw		ss;
2283 	uintmax_t		tag_type = UINT_MAX;
2284 	uintmax_t		snum = UINT_MAX;
2285 	uintmax_t		index = UINT_MAX;
2286 	int			args = 0;
2287 	void			*pmcs_state;
2288 	char			*state_str;
2289 	struct dev_info		dip;
2290 
2291 	if (!(flags & DCMD_ADDRSPEC)) {
2292 		pmcs_state = NULL;
2293 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2294 			mdb_warn("can't read pmcs_softc_state");
2295 			return (DCMD_ERR);
2296 		}
2297 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc,
2298 		    argv, (uintptr_t)pmcs_state) == -1) {
2299 			mdb_warn("mdb_pwalk_dcmd failed");
2300 			return (DCMD_ERR);
2301 		}
2302 		return (DCMD_OK);
2303 	}
2304 
2305 	if (mdb_getopts(argc, argv,
2306 	    'i', MDB_OPT_UINT64, &index,
2307 	    's', MDB_OPT_UINT64, &snum,
2308 	    't', MDB_OPT_UINT64, &tag_type) != argc)
2309 		return (DCMD_USAGE);
2310 
2311 	/*
2312 	 * Count the number of supplied options and make sure they are
2313 	 * within appropriate ranges.  If they're set to UINT_MAX, that means
2314 	 * they were not supplied, in which case reset them to 0.
2315 	 */
2316 	if (index != UINT_MAX) {
2317 		args++;
2318 		if (index > PMCS_TAG_INDEX_MASK) {
2319 			mdb_warn("Index is out of range\n");
2320 			return (DCMD_USAGE);
2321 		}
2322 	}
2323 
2324 	if (tag_type != UINT_MAX) {
2325 		args++;
2326 		switch (tag_type) {
2327 		case PMCS_TAG_TYPE_NONE:
2328 		case PMCS_TAG_TYPE_CBACK:
2329 		case PMCS_TAG_TYPE_WAIT:
2330 			break;
2331 		default:
2332 			mdb_warn("Invalid tag type\n");
2333 			return (DCMD_USAGE);
2334 		}
2335 	}
2336 
2337 	if (snum != UINT_MAX) {
2338 		args++;
2339 		if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) {
2340 			mdb_warn("Serial number is out of range\n");
2341 			return (DCMD_USAGE);
2342 		}
2343 	}
2344 
2345 	/*
2346 	 * Make sure 1 and only 1 option is specified
2347 	 */
2348 	if ((args == 0) || (args > 1)) {
2349 		mdb_warn("Exactly one of -i, -s and -t must be specified\n");
2350 		return (DCMD_USAGE);
2351 	}
2352 
2353 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2354 		NOREAD(pmcs_hw_t, addr);
2355 		return (DCMD_ERR);
2356 	}
2357 
2358 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2359 		NOREAD(pmcs_hw_t, addr);
2360 		return (DCMD_ERR);
2361 	}
2362 
2363 	/* processing completed */
2364 
2365 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
2366 	    (flags & DCMD_LOOPFIRST)) {
2367 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
2368 			mdb_printf("\n");
2369 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
2370 		    "Address", "State", "Inst", "DIP");
2371 		mdb_printf("================================="
2372 		    "============================================\n");
2373 	}
2374 
2375 	switch (ss.state) {
2376 	case STATE_NIL:
2377 		state_str = "Invalid";
2378 		break;
2379 	case STATE_PROBING:
2380 		state_str = "Probing";
2381 		break;
2382 	case STATE_RUNNING:
2383 		state_str = "Running";
2384 		break;
2385 	case STATE_UNPROBING:
2386 		state_str = "Unprobing";
2387 		break;
2388 	case STATE_DEAD:
2389 		state_str = "Dead";
2390 		break;
2391 	case STATE_IN_RESET:
2392 		state_str = "In Reset";
2393 		break;
2394 	}
2395 
2396 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
2397 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
2398 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
2399 	mdb_printf("\n");
2400 
2401 	mdb_inc_indent(4);
2402 	display_matching_work(ss, index, snum, tag_type);
2403 	mdb_dec_indent(4);
2404 	mdb_printf("\n");
2405 
2406 	return (DCMD_OK);
2407 }
2408 
2409 #ifndef _KMDB
2410 static int
2411 pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile)
2412 {
2413 	uint8_t *fwlogp;
2414 	int	ofilefd = -1;
2415 	char	ofilename[MAXPATHLEN];
2416 	int	rval = DCMD_OK;
2417 
2418 	if (ss->fwlogp == NULL) {
2419 		mdb_warn("Firmware event log disabled for instance %d",
2420 		    instance);
2421 		return (DCMD_OK);
2422 	}
2423 
2424 	if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) >
2425 	    MAXPATHLEN) {
2426 		mdb_warn("Output filename is too long for instance %d",
2427 		    instance);
2428 		return (DCMD_ERR);
2429 	}
2430 
2431 	fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP);
2432 
2433 	if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) {
2434 		NOREAD(fwlogp, ss->fwlogp);
2435 		rval = DCMD_ERR;
2436 		goto cleanup;
2437 	}
2438 
2439 	ofilefd = open(ofilename, O_WRONLY | O_CREAT,
2440 	    S_IRUSR | S_IRGRP | S_IROTH);
2441 	if (ofilefd < 0) {
2442 		mdb_warn("Unable to open '%s' to dump instance %d event log",
2443 		    ofilename, instance);
2444 		rval = DCMD_ERR;
2445 		goto cleanup;
2446 	}
2447 
2448 	if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) {
2449 		mdb_warn("Failed to write %d bytes to output file: instance %d",
2450 		    PMCS_FWLOG_SIZE, instance);
2451 		rval = DCMD_ERR;
2452 		goto cleanup;
2453 	}
2454 
2455 	mdb_printf("Event log for instance %d written to %s\n", instance,
2456 	    ofilename);
2457 
2458 cleanup:
2459 	if (ofilefd >= 0) {
2460 		close(ofilefd);
2461 	}
2462 	mdb_free(fwlogp, PMCS_FWLOG_SIZE);
2463 	return (rval);
2464 }
2465 
2466 static int
2467 pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2468 {
2469 	void		*pmcs_state;
2470 	const char	*ofile = NULL;
2471 	struct pmcs_hw	ss;
2472 	struct dev_info	dip;
2473 
2474 	if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) {
2475 		return (DCMD_USAGE);
2476 	}
2477 
2478 	if (ofile == NULL) {
2479 		mdb_printf("No output file specified\n");
2480 		return (DCMD_USAGE);
2481 	}
2482 
2483 	if (!(flags & DCMD_ADDRSPEC)) {
2484 		pmcs_state = NULL;
2485 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2486 			mdb_warn("can't read pmcs_softc_state");
2487 			return (DCMD_ERR);
2488 		}
2489 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc,
2490 		    argv, (uintptr_t)pmcs_state) == -1) {
2491 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
2492 			return (DCMD_ERR);
2493 		}
2494 		return (DCMD_OK);
2495 	}
2496 
2497 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2498 		NOREAD(pmcs_hw_t, addr);
2499 		return (DCMD_ERR);
2500 	}
2501 
2502 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2503 		NOREAD(pmcs_hw_t, addr);
2504 		return (DCMD_ERR);
2505 	}
2506 
2507 	return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile));
2508 }
2509 #endif	/* _KMDB */
2510 
2511 static int
2512 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2513 {
2514 	void		*pmcs_state;
2515 	struct pmcs_hw	ss;
2516 	struct dev_info	dip;
2517 	const char	*match_phy_path = NULL;
2518 	uint64_t 	match_sas_address = 0, tail_lines = 0;
2519 
2520 	if (!(flags & DCMD_ADDRSPEC)) {
2521 		pmcs_state = NULL;
2522 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2523 			mdb_warn("can't read pmcs_softc_state");
2524 			return (DCMD_ERR);
2525 		}
2526 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc,
2527 		    argv, (uintptr_t)pmcs_state) == -1) {
2528 			mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
2529 			return (DCMD_ERR);
2530 		}
2531 		return (DCMD_OK);
2532 	}
2533 
2534 	if (mdb_getopts(argc, argv,
2535 	    'l', MDB_OPT_UINT64, &tail_lines,
2536 	    'p', MDB_OPT_STR, &match_phy_path,
2537 	    's', MDB_OPT_UINT64, &match_sas_address,
2538 	    NULL) != argc) {
2539 		return (DCMD_USAGE);
2540 	}
2541 
2542 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2543 		NOREAD(pmcs_hw_t, addr);
2544 		return (DCMD_ERR);
2545 	}
2546 
2547 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2548 		NOREAD(pmcs_hw_t, addr);
2549 		return (DCMD_ERR);
2550 	}
2551 
2552 	if (!(flags & DCMD_LOOP)) {
2553 		return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance,
2554 		    tail_lines, match_phy_path, match_sas_address));
2555 	} else if (flags & DCMD_LOOPFIRST) {
2556 		return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines,
2557 		    match_phy_path, match_sas_address));
2558 	} else {
2559 		return (DCMD_OK);
2560 	}
2561 }
2562 
2563 static int
2564 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2565 {
2566 	struct pmcs_hw		ss;
2567 	uint_t			verbose = FALSE;
2568 	uint_t			phy_info = FALSE;
2569 	uint_t			hw_info = FALSE;
2570 	uint_t			target_info = FALSE;
2571 	uint_t			work_info = FALSE;
2572 	uint_t			ic_info = FALSE;
2573 	uint_t			iport_info = FALSE;
2574 	uint_t			waitqs_info = FALSE;
2575 	uint_t			ibq = FALSE;
2576 	uint_t			obq = FALSE;
2577 	uint_t			tgt_phy_count = FALSE;
2578 	uint_t			compq = FALSE;
2579 	uint_t			unconfigured = FALSE;
2580 	uint_t			damap_info = FALSE;
2581 	uint_t			dtc_info = FALSE;
2582 	int			rv = DCMD_OK;
2583 	void			*pmcs_state;
2584 	char			*state_str;
2585 	struct dev_info		dip;
2586 	per_iport_setting_t	pis;
2587 
2588 	if (!(flags & DCMD_ADDRSPEC)) {
2589 		pmcs_state = NULL;
2590 		if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2591 			mdb_warn("can't read pmcs_softc_state");
2592 			return (DCMD_ERR);
2593 		}
2594 		if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv,
2595 		    (uintptr_t)pmcs_state) == -1) {
2596 			mdb_warn("mdb_pwalk_dcmd failed");
2597 			return (DCMD_ERR);
2598 		}
2599 		return (DCMD_OK);
2600 	}
2601 
2602 	if (mdb_getopts(argc, argv,
2603 	    'c', MDB_OPT_SETBITS, TRUE, &compq,
2604 	    'd', MDB_OPT_SETBITS, TRUE, &dtc_info,
2605 	    'h', MDB_OPT_SETBITS, TRUE, &hw_info,
2606 	    'i', MDB_OPT_SETBITS, TRUE, &ic_info,
2607 	    'I', MDB_OPT_SETBITS, TRUE, &iport_info,
2608 	    'm', MDB_OPT_SETBITS, TRUE, &damap_info,
2609 	    'p', MDB_OPT_SETBITS, TRUE, &phy_info,
2610 	    'q', MDB_OPT_SETBITS, TRUE, &ibq,
2611 	    'Q', MDB_OPT_SETBITS, TRUE, &obq,
2612 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
2613 	    'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count,
2614 	    'u', MDB_OPT_SETBITS, TRUE, &unconfigured,
2615 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
2616 	    'w', MDB_OPT_SETBITS, TRUE, &work_info,
2617 	    'W', MDB_OPT_SETBITS, TRUE, &waitqs_info,
2618 	    NULL) != argc)
2619 		return (DCMD_USAGE);
2620 
2621 	/*
2622 	 * The 'd' and 'm' options implicitly enable the 'I' option
2623 	 */
2624 	pis.pis_damap_info = damap_info;
2625 	pis.pis_dtc_info = dtc_info;
2626 	if (damap_info || dtc_info) {
2627 		iport_info = TRUE;
2628 	}
2629 
2630 	if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2631 		NOREAD(pmcs_hw_t, addr);
2632 		return (DCMD_ERR);
2633 	}
2634 
2635 	if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2636 		NOREAD(pmcs_hw_t, addr);
2637 		return (DCMD_ERR);
2638 	}
2639 
2640 	/* processing completed */
2641 
2642 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
2643 	    (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info ||
2644 	    work_info || waitqs_info || ibq || obq || tgt_phy_count || compq ||
2645 	    unconfigured) {
2646 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
2647 			mdb_printf("\n");
2648 		mdb_printf("%16s %9s %4s B C  WorkFlags wserno DbgMsk %16s\n",
2649 		    "Address", "State", "Inst", "DIP");
2650 		mdb_printf("================================="
2651 		    "============================================\n");
2652 	}
2653 
2654 	switch (ss.state) {
2655 	case STATE_NIL:
2656 		state_str = "Invalid";
2657 		break;
2658 	case STATE_PROBING:
2659 		state_str = "Probing";
2660 		break;
2661 	case STATE_RUNNING:
2662 		state_str = "Running";
2663 		break;
2664 	case STATE_UNPROBING:
2665 		state_str = "Unprobing";
2666 		break;
2667 	case STATE_DEAD:
2668 		state_str = "Dead";
2669 		break;
2670 	case STATE_IN_RESET:
2671 		state_str = "In Reset";
2672 		break;
2673 	}
2674 
2675 	mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
2676 	    state_str, dip.devi_instance, ss.blocked, ss.configuring,
2677 	    ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
2678 	mdb_printf("\n");
2679 
2680 	mdb_inc_indent(4);
2681 
2682 	if (waitqs_info)
2683 		display_waitqs(ss, verbose);
2684 
2685 	if (hw_info)
2686 		display_hwinfo(ss, verbose);
2687 
2688 	if (phy_info || tgt_phy_count)
2689 		display_phys(ss, verbose, NULL, 0, tgt_phy_count);
2690 
2691 	if (target_info || tgt_phy_count)
2692 		display_targets(ss, verbose, tgt_phy_count);
2693 
2694 	if (work_info)
2695 		display_work(ss, verbose);
2696 
2697 	if (ic_info)
2698 		display_ic(ss, verbose);
2699 
2700 	if (ibq)
2701 		display_inbound_queues(ss, verbose);
2702 
2703 	if (obq)
2704 		display_outbound_queues(ss, verbose);
2705 
2706 	if (iport_info)
2707 		display_iport(ss, addr, verbose, &pis);
2708 
2709 	if (compq)
2710 		display_completion_queue(ss);
2711 
2712 	if (unconfigured)
2713 		display_unconfigured_targets(addr);
2714 
2715 	mdb_dec_indent(4);
2716 
2717 	return (rv);
2718 }
2719 
2720 void
2721 pmcs_help()
2722 {
2723 	mdb_printf("Prints summary information about each pmcs instance.\n"
2724 	    "    -c: Dump the completion queue\n"
2725 	    "    -d: Print per-iport information about device tree children\n"
2726 	    "    -h: Print more detailed hardware information\n"
2727 	    "    -i: Print interrupt coalescing information\n"
2728 	    "    -I: Print information about each iport\n"
2729 	    "    -m: Print per-iport information about DAM/damap state\n"
2730 	    "    -p: Print information about each attached PHY\n"
2731 	    "    -q: Dump inbound queues\n"
2732 	    "    -Q: Dump outbound queues\n"
2733 	    "    -t: Print information about each configured target\n"
2734 	    "    -T: Print target and PHY count summary\n"
2735 	    "    -u: Show SAS address of all unconfigured targets\n"
2736 	    "    -w: Dump work structures\n"
2737 	    "    -W: List pmcs cmds waiting on various queues\n"
2738 	    "    -v: Add verbosity to the above options\n");
2739 }
2740 
2741 void
2742 pmcs_log_help()
2743 {
2744 	mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n"
2745 	    "    -l TAIL_LINES:          Dump the last TAIL_LINES messages\n"
2746 	    "    -p PHY_PATH:            Dump messages matching PHY_PATH\n"
2747 	    "    -s SAS_ADDRESS:         Dump messages matching SAS_ADDRESS\n\n"
2748 	    "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n"
2749 	    "       SAS_ADDRESS can be found with ::pmcs -t "
2750 	    "(e.g. 5000c5000358c221)\n");
2751 }
2752 void
2753 pmcs_tag_help()
2754 {
2755 	mdb_printf("Print all work structures by matching the tag.\n"
2756 	    "    -i index:        Match tag index (0x000 - 0xfff)\n"
2757 	    "    -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
2758 	    "    -t tagtype:      Match tag type [NONE(1), CBACK(2), "
2759 	    "WAIT(3)]\n");
2760 }
2761 
2762 static const mdb_dcmd_t dcmds[] = {
2763 	{ "pmcs", "?[-cdhiImpQqtTuwWv]", "print pmcs information",
2764 	    pmcs_dcmd, pmcs_help
2765 	},
2766 	{ "pmcs_log",
2767 	    "?[-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]",
2768 	    "dump pmcs log file", pmcs_log, pmcs_log_help
2769 	},
2770 	{ "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
2771 	    "Find work structures by tag type, serial number or index",
2772 	    pmcs_tag, pmcs_tag_help
2773 	},
2774 #ifndef _KMDB
2775 	{ "pmcs_fwlog",
2776 	    "?-o output_file",
2777 	    "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL
2778 	},
2779 #endif	/* _KMDB */
2780 	{ NULL }
2781 };
2782 
2783 static const mdb_walker_t walkers[] = {
2784 	{ "pmcs_targets", "walk target structures",
2785 		targets_walk_i, targets_walk_s, targets_walk_f },
2786 	{ "pmcs_phys", "walk PHY structures",
2787 		phy_walk_i, phy_walk_s, phy_walk_f },
2788 	{ NULL }
2789 };
2790 
2791 static const mdb_modinfo_t modinfo = {
2792 	MDB_API_VERSION, dcmds, walkers
2793 };
2794 
2795 const mdb_modinfo_t *
2796 _mdb_init(void)
2797 {
2798 	return (&modinfo);
2799 }
2800