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