xref: /illumos-gate/usr/src/cmd/mdb/common/modules/mpt_sas/mpt_sas.c (revision 892ad1623e11186cba8b2eb40d70318d2cb89605)
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 /*
27  * Copyright (c) 2017 Joyent, Inc.
28  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
29  */
30 
31 #include <limits.h>
32 #include <sys/mdb_modapi.h>
33 #include <sys/sysinfo.h>
34 #include <sys/sunmdi.h>
35 #include <sys/list.h>
36 #include <sys/scsi/scsi.h>
37 
38 #pragma pack(1)
39 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
40 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
41 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
42 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
43 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
44 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
45 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
46 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
47 #pragma pack()
48 
49 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
50 #include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
51 
52 struct {
53 	int	value;
54 	char	*text;
55 } devinfo_array[] = {
56 	{ MPI2_SAS_DEVICE_INFO_SEP,		"SEP" },
57 	{ MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE,	"ATAPI device" },
58 	{ MPI2_SAS_DEVICE_INFO_LSI_DEVICE,	"LSI device" },
59 	{ MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH,	"direct attach" },
60 	{ MPI2_SAS_DEVICE_INFO_SSP_TARGET,	"SSP tgt" },
61 	{ MPI2_SAS_DEVICE_INFO_STP_TARGET,	"STP tgt" },
62 	{ MPI2_SAS_DEVICE_INFO_SMP_TARGET,	"SMP tgt" },
63 	{ MPI2_SAS_DEVICE_INFO_SATA_DEVICE,	"SATA dev" },
64 	{ MPI2_SAS_DEVICE_INFO_SSP_INITIATOR,	"SSP init" },
65 	{ MPI2_SAS_DEVICE_INFO_STP_INITIATOR,	"STP init" },
66 	{ MPI2_SAS_DEVICE_INFO_SMP_INITIATOR,	"SMP init" },
67 	{ MPI2_SAS_DEVICE_INFO_SATA_HOST,	"SATA host" }
68 };
69 
70 int
71 construct_path(uintptr_t addr, char *result)
72 {
73 	struct	dev_info	d;
74 	char	devi_node[PATH_MAX];
75 	char	devi_addr[PATH_MAX];
76 
77 	if (mdb_vread(&d, sizeof (d), addr) == -1) {
78 		mdb_warn("couldn't read dev_info");
79 		return (DCMD_ERR);
80 	}
81 
82 	if (d.devi_parent) {
83 		construct_path((uintptr_t)d.devi_parent, result);
84 		mdb_readstr(devi_node, sizeof (devi_node),
85 		    (uintptr_t)d.devi_node_name);
86 		mdb_readstr(devi_addr, sizeof (devi_addr),
87 		    (uintptr_t)d.devi_addr);
88 		mdb_snprintf(result+strlen(result),
89 		    PATH_MAX-strlen(result),
90 		    "/%s%s%s", devi_node, (*devi_addr ? "@" : ""),
91 		    devi_addr);
92 	}
93 	return (DCMD_OK);
94 }
95 
96 /* ARGSUSED */
97 int
98 mdi_info_cb(uintptr_t addr, const void *data, void *cbdata)
99 {
100 	struct	mdi_pathinfo	pi;
101 	struct	mdi_client	c;
102 	char	dev_path[PATH_MAX];
103 	char	string[PATH_MAX];
104 	int	mdi_target = 0, mdi_lun = 0;
105 	int	target = *(int *)cbdata;
106 
107 	if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
108 		mdb_warn("couldn't read mdi_pathinfo");
109 		return (DCMD_ERR);
110 	}
111 	mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
112 	mdi_target = (int)mdb_strtoull(string);
113 	mdi_lun = (int)mdb_strtoull(strchr(string, ',') + 1);
114 	if (target != mdi_target)
115 		return (0);
116 
117 	if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
118 		mdb_warn("couldn't read mdi_client");
119 		return (-1);
120 	}
121 
122 	*dev_path = '\0';
123 	if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK)
124 		strcpy(dev_path, "unknown");
125 
126 	mdb_printf("LUN %d: %s\n", mdi_lun, dev_path);
127 	mdb_printf("       dip: %p %s path", c.ct_dip,
128 	    (pi.pi_preferred ? "preferred" : ""));
129 	switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) {
130 		case MDI_PATHINFO_STATE_INIT:
131 			mdb_printf(" initializing");
132 			break;
133 		case MDI_PATHINFO_STATE_ONLINE:
134 			mdb_printf(" online");
135 			break;
136 		case MDI_PATHINFO_STATE_STANDBY:
137 			mdb_printf(" standby");
138 			break;
139 		case MDI_PATHINFO_STATE_FAULT:
140 			mdb_printf(" fault");
141 			break;
142 		case MDI_PATHINFO_STATE_OFFLINE:
143 			mdb_printf(" offline");
144 			break;
145 		default:
146 			mdb_printf(" invalid state");
147 			break;
148 	}
149 	mdb_printf("\n");
150 	return (0);
151 }
152 
153 void
154 mdi_info(struct mptsas *mp, int target)
155 {
156 	struct	dev_info	d;
157 	struct	mdi_phci	p;
158 
159 	if (mdb_vread(&d, sizeof (d), (uintptr_t)mp->m_dip) == -1) {
160 		mdb_warn("couldn't read m_dip");
161 		return;
162 	}
163 
164 	if (MDI_PHCI(&d)) {
165 		if (mdb_vread(&p, sizeof (p), (uintptr_t)d.devi_mdi_xhci)
166 		    == -1) {
167 			mdb_warn("couldn't read m_dip.devi_mdi_xhci");
168 			return;
169 		}
170 		if (p.ph_path_head)
171 			mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mdi_info_cb,
172 			    &target, (uintptr_t)p.ph_path_head);
173 		return;
174 	}
175 }
176 
177 void
178 print_cdb(mptsas_cmd_t *m)
179 {
180 	struct	scsi_pkt	pkt;
181 	uchar_t	cdb[512];	/* an arbitrarily large number */
182 	int	j;
183 
184 	if (mdb_vread(&pkt, sizeof (pkt), (uintptr_t)m->cmd_pkt) == -1) {
185 		mdb_warn("couldn't read cmd_pkt");
186 		return;
187 	}
188 
189 	/*
190 	 * We use cmd_cdblen here because 5.10 doesn't
191 	 * have the cdb length in the pkt
192 	 */
193 	if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) {
194 		mdb_warn("couldn't read pkt_cdbp");
195 		return;
196 	}
197 
198 	mdb_printf("%3d,%-3d [ ",
199 	    pkt.pkt_address.a_target, pkt.pkt_address.a_lun);
200 
201 	for (j = 0; j < m->cmd_cdblen; j++)
202 		mdb_printf("%02x ", cdb[j]);
203 
204 	mdb_printf("]\n");
205 }
206 
207 
208 void
209 display_ports(struct mptsas *mp)
210 {
211 	int i;
212 	mdb_printf("\n");
213 	mdb_printf("phy number and port mapping table\n");
214 	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
215 		if (mp->m_phy_info[i].attached_devhdl) {
216 			mdb_printf("phy %x --> port %x, phymask %x,"
217 			"attached_devhdl %x\n", i, mp->m_phy_info[i].port_num,
218 			    mp->m_phy_info[i].phy_mask,
219 			    mp->m_phy_info[i].attached_devhdl);
220 		}
221 	}
222 	mdb_printf("\n");
223 }
224 
225 static uintptr_t
226 klist_head(list_t *lp, uintptr_t klp)
227 {
228 	if ((uintptr_t)lp->list_head.list_next ==
229 	    klp + offsetof(struct list, list_head))
230 		return (0);
231 
232 	return ((uintptr_t)(((char *)lp->list_head.list_next) -
233 	    lp->list_offset));
234 }
235 
236 static uintptr_t
237 klist_next(list_t *lp, uintptr_t klp, void *op)
238 {
239 	/* LINTED E_BAD_PTR_CAST_ALIG */
240 	struct list_node *np = (struct list_node *)(((char *)op) +
241 	    lp->list_offset);
242 
243 	if ((uintptr_t)np->list_next == klp + offsetof(struct list, list_head))
244 		return (0);
245 
246 	return (((uintptr_t)(np->list_next)) - lp->list_offset);
247 }
248 
249 static void *
250 krefhash_first(uintptr_t khp, uintptr_t *addr)
251 {
252 	refhash_t mh;
253 	uintptr_t klp;
254 	uintptr_t kop;
255 	void *rp;
256 
257 	mdb_vread(&mh, sizeof (mh), khp);
258 	klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
259 	if (klp == 0)
260 		return (NULL);
261 
262 	kop = klp - mh.rh_link_off;
263 	if (addr)
264 		*addr = kop;
265 	rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
266 	mdb_vread(rp, mh.rh_obj_size, kop);
267 
268 	return (rp);
269 }
270 
271 static void *
272 krefhash_next(uintptr_t khp, void *op, uintptr_t *addr)
273 {
274 	refhash_t mh;
275 	void *prev = op;
276 	refhash_link_t *lp;
277 	uintptr_t klp;
278 	uintptr_t kop;
279 	refhash_link_t ml;
280 	void *rp;
281 
282 	mdb_vread(&mh, sizeof (mh), khp);
283 	/* LINTED E_BAD_PTR_CAST_ALIG */
284 	lp = (refhash_link_t *)(((char *)(op)) + mh.rh_link_off);
285 	ml = *lp;
286 	while ((klp = klist_next(&mh.rh_objs,
287 	    khp + offsetof(refhash_t, rh_objs), &ml)) != 0) {
288 		mdb_vread(&ml, sizeof (ml), klp);
289 		if (!(ml.rhl_flags & RHL_F_DEAD))
290 			break;
291 	}
292 
293 	if (klp == 0) {
294 		mdb_free(prev, mh.rh_obj_size);
295 		return (NULL);
296 	}
297 
298 	kop = klp - mh.rh_link_off;
299 	if (addr)
300 		*addr = kop;
301 	rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
302 	mdb_vread(rp, mh.rh_obj_size, kop);
303 
304 	mdb_free(prev, mh.rh_obj_size);
305 	return (rp);
306 }
307 
308 void
309 display_targets(struct mptsas *mp, uint_t verbose)
310 {
311 	mptsas_target_t *ptgt;
312 	mptsas_smp_t *psmp;
313 	int loop, comma;
314 	uintptr_t p_addr;
315 
316 	mdb_printf("\n");
317 	mdb_printf(" mptsas_target_t slot devhdl      wwn     ncmds throttle   "
318 	    "dr_flag dups\n");
319 	mdb_printf("---------------------------------------"
320 	    "-------------------------------\n");
321 	for (ptgt = krefhash_first((uintptr_t)mp->m_targets, &p_addr);
322 	    ptgt != NULL;
323 	    ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, &p_addr)) {
324 		if (ptgt->m_addr.mta_wwn ||
325 		    ptgt->m_deviceinfo) {
326 			mdb_printf("%16p ", p_addr);
327 			mdb_printf("%4d ", ptgt->m_slot_num);
328 			mdb_printf("%4d ", ptgt->m_devhdl);
329 			if (ptgt->m_addr.mta_wwn)
330 				mdb_printf("%"PRIx64" ",
331 				    ptgt->m_addr.mta_wwn);
332 			mdb_printf("%3d", ptgt->m_t_ncmds);
333 			switch (ptgt->m_t_throttle) {
334 				case QFULL_THROTTLE:
335 					mdb_printf("   QFULL ");
336 					break;
337 				case DRAIN_THROTTLE:
338 					mdb_printf("   DRAIN ");
339 					break;
340 				case HOLD_THROTTLE:
341 					mdb_printf("    HOLD ");
342 					break;
343 				case MAX_THROTTLE:
344 					mdb_printf("     MAX ");
345 					break;
346 				default:
347 					mdb_printf("%8d ",
348 					    ptgt->m_t_throttle);
349 			}
350 			switch (ptgt->m_dr_flag) {
351 				case MPTSAS_DR_INACTIVE:
352 					mdb_printf("  INACTIVE ");
353 					break;
354 				case MPTSAS_DR_INTRANSITION:
355 					mdb_printf("TRANSITION ");
356 					break;
357 				default:
358 					mdb_printf("   UNKNOWN ");
359 					break;
360 				}
361 			mdb_printf("%d\n",
362 			    ptgt->m_dups);
363 
364 			if (verbose) {
365 				mdb_inc_indent(5);
366 				if ((ptgt->m_deviceinfo &
367 				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
368 				    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
369 					mdb_printf("Fanout expander: ");
370 				if ((ptgt->m_deviceinfo &
371 				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
372 				    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
373 					mdb_printf("Edge expander: ");
374 				if ((ptgt->m_deviceinfo &
375 				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
376 				    MPI2_SAS_DEVICE_INFO_END_DEVICE)
377 					mdb_printf("End device: ");
378 				if ((ptgt->m_deviceinfo &
379 				    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
380 				    MPI2_SAS_DEVICE_INFO_NO_DEVICE)
381 					mdb_printf("No device ");
382 
383 				for (loop = 0, comma = 0;
384 				    loop < (sizeof (devinfo_array) /
385 				    sizeof (devinfo_array[0])); loop++) {
386 					if (ptgt->m_deviceinfo &
387 					    devinfo_array[loop].value) {
388 						mdb_printf("%s%s",
389 						    (comma ? ", " : ""),
390 						    devinfo_array[loop].text);
391 						comma++;
392 					}
393 				}
394 				mdb_printf("\n");
395 				mdi_info(mp, ptgt->m_slot_num);
396 				mdb_dec_indent(5);
397 			}
398 		}
399 	}
400 
401 	mdb_printf("\n");
402 	mdb_printf("    mptsas_smp_t devhdl      wwn          phymask\n");
403 	mdb_printf("---------------------------------------"
404 	    "------------------\n");
405 	for (psmp = (mptsas_smp_t *)krefhash_first(
406 	    (uintptr_t)mp->m_smp_targets, &p_addr);
407 	    psmp != NULL;
408 	    psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp,
409 	    &p_addr)) {
410 		mdb_printf("%16p   ", p_addr);
411 		mdb_printf("%4d  %"PRIx64"    %04x\n",
412 		    psmp->m_devhdl, psmp->m_addr.mta_wwn,
413 		    psmp->m_addr.mta_phymask);
414 
415 		if (!verbose)
416 			continue;
417 
418 		mdb_inc_indent(5);
419 		if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
420 		    == MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
421 			mdb_printf("Fanout expander: ");
422 		if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
423 		    == MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
424 			mdb_printf("Edge expander: ");
425 		if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
426 		    == MPI2_SAS_DEVICE_INFO_END_DEVICE)
427 			mdb_printf("End device: ");
428 		if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
429 		    == MPI2_SAS_DEVICE_INFO_NO_DEVICE)
430 			mdb_printf("No device ");
431 
432 		for (loop = 0, comma = 0;
433 		    loop < (sizeof (devinfo_array)
434 		    / sizeof (devinfo_array[0]));
435 		    loop++) {
436 			if (psmp->m_deviceinfo &
437 			    devinfo_array[loop].value) {
438 				mdb_printf("%s%s",
439 				    (comma ? ", " : ""),
440 				    devinfo_array[loop].text);
441 				comma++;
442 			}
443 		}
444 		mdb_printf("\n");
445 		mdb_dec_indent(5);
446 	}
447 }
448 
449 int
450 display_slotinfo(struct mptsas *mp, struct mptsas_slots *s)
451 {
452 	int			i, nslots;
453 	struct mptsas_cmd	c, *q, *slots;
454 	mptsas_target_t		*ptgt;
455 	int			header_output = 0;
456 	int			rv = DCMD_OK;
457 	int			slots_in_use = 0;
458 	int			tcmds = 0;
459 	int			mismatch = 0;
460 	int			wq, dq;
461 	int			ncmds = 0;
462 	ulong_t			saved_indent;
463 	uintptr_t		panicstr;
464 	int			state;
465 
466 	if ((state = mdb_get_state()) == MDB_STATE_RUNNING) {
467 		mdb_warn("mptsas: slot info can only be displayed on a system "
468 		    "dump or under kmdb\n");
469 		return (DCMD_ERR);
470 	}
471 
472 	if (mdb_readvar(&panicstr, "panicstr") == -1) {
473 		mdb_warn("can't read variable 'panicstr'");
474 		return (DCMD_ERR);
475 	}
476 
477 	if (state != MDB_STATE_STOPPED && panicstr == 0) {
478 		mdb_warn("mptsas: slot info not available for live dump\n");
479 		return (DCMD_ERR);
480 	}
481 
482 	nslots = s->m_n_normal;
483 	slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
484 
485 	for (i = 0; i < nslots; i++)
486 		if (s->m_slot[i]) {
487 			slots_in_use++;
488 			if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
489 			    (uintptr_t)s->m_slot[i]) == -1) {
490 				mdb_warn("couldn't read slot");
491 				s->m_slot[i] = NULL;
492 			}
493 			if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
494 				tcmds++;
495 			if (i != slots[i].cmd_slot)
496 				mismatch++;
497 		}
498 
499 	for (q = mp->m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
500 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
501 			mdb_warn("couldn't follow m_waitq");
502 			rv = DCMD_ERR;
503 			goto exit;
504 		}
505 
506 	for (q = mp->m_doneq, dq = 0; q; q = c.cmd_linkp, dq++)
507 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
508 			mdb_warn("couldn't follow m_doneq");
509 			rv = DCMD_ERR;
510 			goto exit;
511 		}
512 
513 	for (ptgt = krefhash_first((uintptr_t)mp->m_targets, NULL);
514 	    ptgt != NULL;
515 	    ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, NULL)) {
516 		if (ptgt->m_addr.mta_wwn ||
517 		    ptgt->m_deviceinfo) {
518 			ncmds += ptgt->m_t_ncmds;
519 		}
520 	}
521 
522 	mdb_printf("\n");
523 	mdb_printf("   mpt.  slot               mptsas_slots     slot");
524 	mdb_printf("\n");
525 	mdb_printf("m_ncmds total"
526 	    " targ throttle m_t_ncmds targ_tot wq dq");
527 	mdb_printf("\n");
528 	mdb_printf("----------------------------------------------------");
529 	mdb_printf("\n");
530 
531 	mdb_printf("%7d ", mp->m_ncmds);
532 	mdb_printf("%s", (mp->m_ncmds == slots_in_use ? "  " : "!="));
533 	mdb_printf("%3d               total %3d ", slots_in_use, ncmds);
534 	mdb_printf("%s", (tcmds == ncmds ? "     " : "   !="));
535 	mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
536 
537 	saved_indent = mdb_dec_indent(0);
538 	mdb_dec_indent(saved_indent);
539 
540 	for (i = 0; i < s->m_n_normal; i++)
541 		if (s->m_slot[i]) {
542 			if (!header_output) {
543 				mdb_printf("\n");
544 				mdb_printf("mptsas_cmd          slot cmd_slot "
545 				    "cmd_flags cmd_pkt_flags scsi_pkt      "
546 				    "  targ,lun [ pkt_cdbp ...\n");
547 				mdb_printf("-------------------------------"
548 				    "--------------------------------------"
549 				    "--------------------------------------"
550 				    "------\n");
551 				header_output = 1;
552 			}
553 			mdb_printf("%16p %4d %s %4d  %8x      %8x %16p ",
554 			    s->m_slot[i], i,
555 			    (i == slots[i].cmd_slot?"   ":"BAD"),
556 			    slots[i].cmd_slot,
557 			    slots[i].cmd_flags,
558 			    slots[i].cmd_pkt_flags,
559 			    slots[i].cmd_pkt);
560 			(void) print_cdb(&slots[i]);
561 		}
562 
563 	/* print the wait queue */
564 
565 	for (q = mp->m_waitq; q; q = c.cmd_linkp) {
566 		if (q == mp->m_waitq)
567 			mdb_printf("\n");
568 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
569 		    == -1) {
570 			mdb_warn("couldn't follow m_waitq");
571 			rv = DCMD_ERR;
572 			goto exit;
573 		}
574 		mdb_printf("%16p wait n/a %4d  %8x      %8x %16p ",
575 		    q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
576 		    c.cmd_pkt);
577 		print_cdb(&c);
578 	}
579 
580 	/* print the done queue */
581 
582 	for (q = mp->m_doneq; q; q = c.cmd_linkp) {
583 		if (q == mp->m_doneq)
584 			mdb_printf("\n");
585 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
586 		    == -1) {
587 			mdb_warn("couldn't follow m_doneq");
588 			rv = DCMD_ERR;
589 			goto exit;
590 		}
591 		mdb_printf("%16p done  n/a %4d  %8x      %8x %16p ",
592 		    q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
593 		    c.cmd_pkt);
594 		print_cdb(&c);
595 	}
596 
597 	mdb_inc_indent(saved_indent);
598 
599 	if (mp->m_ncmds != slots_in_use)
600 		mdb_printf("WARNING: mpt.m_ncmds does not match the number of "
601 		    "slots in use\n");
602 
603 	if (tcmds != ncmds)
604 		mdb_printf("WARNING: the total of m_target[].m_t_ncmds does "
605 		    "not match the slots in use\n");
606 
607 	if (mismatch)
608 		mdb_printf("WARNING: corruption in slot table, "
609 		    "m_slot[].cmd_slot incorrect\n");
610 
611 	/* now check for corruptions */
612 
613 	for (q = mp->m_waitq; q; q = c.cmd_linkp) {
614 		for (i = 0; i < nslots; i++)
615 			if (s->m_slot[i] == q)
616 				mdb_printf("WARNING: m_waitq entry"
617 				    "(mptsas_cmd_t) %p is in m_slot[%i]\n",
618 				    q, i);
619 
620 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
621 			mdb_warn("couldn't follow m_waitq");
622 			rv = DCMD_ERR;
623 			goto exit;
624 		}
625 	}
626 
627 	for (q = mp->m_doneq; q; q = c.cmd_linkp) {
628 		for (i = 0; i < nslots; i++)
629 			if (s->m_slot[i] == q)
630 				mdb_printf("WARNING: m_doneq entry "
631 				"(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i);
632 
633 		if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
634 			mdb_warn("couldn't follow m_doneq");
635 			rv = DCMD_ERR;
636 			goto exit;
637 		}
638 		if ((c.cmd_flags & CFLAG_FINISHED) == 0)
639 			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
640 			    "should have CFLAG_FINISHED set\n", q);
641 		if (c.cmd_flags & CFLAG_IN_TRANSPORT)
642 			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
643 			    "should not have CFLAG_IN_TRANSPORT set\n", q);
644 		if (c.cmd_flags & CFLAG_CMDARQ)
645 			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
646 			    "should not have CFLAG_CMDARQ set\n", q);
647 		if (c.cmd_flags & CFLAG_COMPLETED)
648 			mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
649 			    "should not have CFLAG_COMPLETED set\n", q);
650 	}
651 
652 exit:
653 	mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
654 	return (rv);
655 }
656 
657 void
658 display_deviceinfo(struct mptsas *mp)
659 {
660 	char	device_path[PATH_MAX];
661 
662 	*device_path = 0;
663 	if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
664 		strcpy(device_path, "couldn't determine device path");
665 	}
666 
667 	mdb_printf("\n");
668 	mdb_printf("base_wwid          phys "
669 	    " prodid  devid          revid   ssid\n");
670 	mdb_printf("-----------------------------"
671 	    "----------------------------------\n");
672 	mdb_printf("%"PRIx64"     %2d  "
673 	    "0x%04x 0x%04x ", mp->un.m_base_wwid, mp->m_num_phys,
674 	    mp->m_productid, mp->m_devid);
675 	switch (mp->m_devid) {
676 		case MPI2_MFGPAGE_DEVID_SAS2004:
677 			mdb_printf("(SAS2004) ");
678 			break;
679 		case MPI2_MFGPAGE_DEVID_SAS2008:
680 			mdb_printf("(SAS2008) ");
681 			break;
682 		case MPI2_MFGPAGE_DEVID_SAS2108_1:
683 		case MPI2_MFGPAGE_DEVID_SAS2108_2:
684 		case MPI2_MFGPAGE_DEVID_SAS2108_3:
685 			mdb_printf("(SAS2108) ");
686 			break;
687 		case MPI2_MFGPAGE_DEVID_SAS2116_1:
688 		case MPI2_MFGPAGE_DEVID_SAS2116_2:
689 			mdb_printf("(SAS2116) ");
690 			break;
691 		case MPI2_MFGPAGE_DEVID_SSS6200:
692 			mdb_printf("(SSS6200) ");
693 			break;
694 		case MPI2_MFGPAGE_DEVID_SAS2208_1:
695 		case MPI2_MFGPAGE_DEVID_SAS2208_2:
696 		case MPI2_MFGPAGE_DEVID_SAS2208_3:
697 		case MPI2_MFGPAGE_DEVID_SAS2208_4:
698 		case MPI2_MFGPAGE_DEVID_SAS2208_5:
699 		case MPI2_MFGPAGE_DEVID_SAS2208_6:
700 			mdb_printf("(SAS2208) ");
701 			break;
702 		case MPI2_MFGPAGE_DEVID_SAS2308_1:
703 		case MPI2_MFGPAGE_DEVID_SAS2308_2:
704 		case MPI2_MFGPAGE_DEVID_SAS2308_3:
705 			mdb_printf("(SAS2308) ");
706 			break;
707 		case MPI25_MFGPAGE_DEVID_SAS3004:
708 			mdb_printf("(SAS3004) ");
709 			break;
710 		case MPI25_MFGPAGE_DEVID_SAS3008:
711 			mdb_printf("(SAS3008) ");
712 			break;
713 		case MPI25_MFGPAGE_DEVID_SAS3108_1:
714 		case MPI25_MFGPAGE_DEVID_SAS3108_2:
715 		case MPI25_MFGPAGE_DEVID_SAS3108_5:
716 		case MPI25_MFGPAGE_DEVID_SAS3108_6:
717 			mdb_printf("(SAS3108) ");
718 			break;
719 		case MPI26_MFGPAGE_DEVID_SAS3216:
720 		case MPI26_MFGPAGE_DEVID_SAS3316_1:
721 		case MPI26_MFGPAGE_DEVID_SAS3316_2:
722 		case MPI26_MFGPAGE_DEVID_SAS3316_3:
723 		case MPI26_MFGPAGE_DEVID_SAS3316_4:
724 			mdb_printf("(SAS3216) ");
725 			break;
726 		case MPI26_MFGPAGE_DEVID_SAS3224:
727 		case MPI26_MFGPAGE_DEVID_SAS3324_1:
728 		case MPI26_MFGPAGE_DEVID_SAS3324_2:
729 		case MPI26_MFGPAGE_DEVID_SAS3324_3:
730 		case MPI26_MFGPAGE_DEVID_SAS3324_4:
731 			mdb_printf("(SAS3224) ");
732 			break;
733 		case MPI26_MFGPAGE_DEVID_SAS3408:
734 			mdb_printf("(SAS3408) ");
735 			break;
736 		case MPI26_MFGPAGE_DEVID_SAS3416:
737 			mdb_printf("(SAS3416) ");
738 			break;
739 		case MPI26_MFGPAGE_DEVID_SAS3508:
740 		case MPI26_MFGPAGE_DEVID_SAS3508_1:
741 			mdb_printf("(SAS3508) ");
742 			break;
743 		case MPI26_MFGPAGE_DEVID_SAS3516:
744 		case MPI26_MFGPAGE_DEVID_SAS3516_1:
745 			mdb_printf("(SAS3516) ");
746 			break;
747 		case MPI26_MFGPAGE_DEVID_SAS3616:
748 			mdb_printf("(SAS3616) ");
749 			break;
750 		case MPI26_MFGPAGE_DEVID_SAS3708:
751 			mdb_printf("(SAS3708) ");
752 			break;
753 		case MPI26_MFGPAGE_DEVID_SAS3716:
754 			mdb_printf("(SAS3716) ");
755 			break;
756 		case MPI26_MFGPAGE_DEVID_SAS4008:
757 			mdb_printf("(SAS4008) ");
758 			break;
759 		default:
760 			mdb_printf("(SAS????) ");
761 			break;
762 	}
763 	mdb_printf("0x%02x 0x%04x\n", mp->m_revid, mp->m_ssid);
764 	mdb_printf("%s\n", device_path);
765 
766 }
767 
768 void
769 dump_debug_log(void)
770 {
771 	uint32_t idx;
772 	size_t	linecnt, linelen;
773 	char	*logbuf;
774 	int	i;
775 
776 	if (mdb_readsym(&idx, sizeof (uint32_t), "mptsas_dbglog_idx") == -1) {
777 		mdb_warn("No debug log buffer present");
778 		return;
779 	}
780 	if (mdb_readsym(&linecnt, sizeof (size_t), "mptsas_dbglog_linecnt")
781 	    == -1) {
782 		mdb_warn("No debug linecnt present");
783 		return;
784 	}
785 	if (mdb_readsym(&linelen, sizeof (size_t), "mptsas_dbglog_linelen")
786 	    == -1) {
787 		mdb_warn("No debug linelen present");
788 		return;
789 	}
790 	logbuf = mdb_alloc(linelen * linecnt, UM_SLEEP);
791 
792 	if (mdb_readsym(logbuf, linelen * linecnt, "mptsas_dbglog_bufs")
793 	    == -1) {
794 		mdb_warn("No debug log buffer present");
795 		return;
796 	}
797 	mdb_printf("\n");
798 	idx &= linecnt - 1;
799 	for (i = 0; i < linecnt; i++) {
800 		mdb_printf("%s\n", &logbuf[idx * linelen]);
801 		idx++;
802 		idx &= linecnt - 1;
803 	}
804 	mdb_free(logbuf, linelen * linecnt);
805 }
806 
807 static int
808 mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
809 {
810 	struct mptsas		m;
811 	struct mptsas_slots	*s;
812 
813 	int			nslots;
814 	int			slot_size = 0;
815 	uint_t			verbose = FALSE;
816 	uint_t			target_info = FALSE;
817 	uint_t			slot_info = FALSE;
818 	uint_t			device_info = FALSE;
819 	uint_t			port_info = FALSE;
820 	uint_t			debug_log = FALSE;
821 	int			rv = DCMD_OK;
822 
823 	if (!(flags & DCMD_ADDRSPEC)) {
824 		void		*mptsas_state = NULL;
825 
826 		if (mdb_readvar(&mptsas_state, "mptsas_state") == -1) {
827 			mdb_warn("can't read mptsas_state");
828 			return (DCMD_ERR);
829 		}
830 		if (mdb_pwalk_dcmd("genunix`softstate", "mpt_sas`mptsas", argc,
831 		    argv, (uintptr_t)mptsas_state) == -1) {
832 			mdb_warn("mdb_pwalk_dcmd failed");
833 			return (DCMD_ERR);
834 		}
835 		return (DCMD_OK);
836 	}
837 
838 	if (mdb_getopts(argc, argv,
839 	    's', MDB_OPT_SETBITS, TRUE, &slot_info,
840 	    'd', MDB_OPT_SETBITS, TRUE, &device_info,
841 	    't', MDB_OPT_SETBITS, TRUE, &target_info,
842 	    'p', MDB_OPT_SETBITS, TRUE, &port_info,
843 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
844 	    'D', MDB_OPT_SETBITS, TRUE, &debug_log,
845 	    NULL) != argc)
846 		return (DCMD_USAGE);
847 
848 
849 	if (mdb_vread(&m, sizeof (m), addr) == -1) {
850 		mdb_warn("couldn't read mpt struct at 0x%p", addr);
851 		return (DCMD_ERR);
852 	}
853 
854 	s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
855 
856 	if (mdb_vread(s, sizeof (mptsas_slots_t),
857 	    (uintptr_t)m.m_active) == -1) {
858 		mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
859 		    m.m_active);
860 		mdb_free(s, sizeof (mptsas_slots_t));
861 		return (DCMD_ERR);
862 	}
863 
864 	nslots = s->m_n_normal;
865 
866 	mdb_free(s, sizeof (mptsas_slots_t));
867 
868 	slot_size = sizeof (mptsas_slots_t) +
869 	    (sizeof (mptsas_cmd_t *) * (nslots-1));
870 
871 	s = mdb_alloc(slot_size, UM_SLEEP);
872 
873 	if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
874 		mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
875 		    m.m_active);
876 		mdb_free(s, slot_size);
877 		return (DCMD_ERR);
878 	}
879 
880 	/* processing completed */
881 
882 	if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
883 	    (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
884 	    target_info) {
885 		if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
886 			mdb_printf("\n");
887 		mdb_printf("        mptsas_t inst ncmds suspend  power");
888 		mdb_printf("\n");
889 		mdb_printf("========================================="
890 		    "=======================================");
891 		mdb_printf("\n");
892 	}
893 
894 	mdb_printf("%16p %4d %5d ", addr, m.m_instance, m.m_ncmds);
895 	mdb_printf("%7d", m.m_suspended);
896 	switch (m.m_power_level) {
897 		case PM_LEVEL_D0:
898 			mdb_printf(" ON=D0 ");
899 			break;
900 		case PM_LEVEL_D1:
901 			mdb_printf("    D1 ");
902 			break;
903 		case PM_LEVEL_D2:
904 			mdb_printf("    D2 ");
905 			break;
906 		case PM_LEVEL_D3:
907 			mdb_printf("OFF=D3 ");
908 			break;
909 		default:
910 			mdb_printf("INVALD ");
911 	}
912 	mdb_printf("\n");
913 
914 	mdb_inc_indent(17);
915 
916 	if (target_info)
917 		display_targets(&m, verbose);
918 
919 	if (port_info)
920 		display_ports(&m);
921 
922 	if (device_info)
923 		display_deviceinfo(&m);
924 
925 	if (slot_info)
926 		display_slotinfo(&m, s);
927 
928 	if (debug_log)
929 		dump_debug_log();
930 
931 	mdb_dec_indent(17);
932 
933 	mdb_free(s, slot_size);
934 
935 	return (rv);
936 }
937 
938 void
939 mptsas_help()
940 {
941 	mdb_printf("Prints summary information about each mpt_sas instance, "
942 	    "including warning\nmessages when slot usage doesn't match "
943 	    "summary information.\n"
944 	    "Without the address of a \"struct mptsas\", prints every "
945 	    "instance.\n\n"
946 	    "Switches:\n"
947 	    "  -t[v]  includes information about targets, v = be more verbose\n"
948 	    "  -p     includes information about port\n"
949 	    "  -s     includes information about mpt slots\n"
950 	    "  -d     includes information about the hardware\n"
951 	    "  -D     print the mptsas specific debug log\n");
952 }
953 
954 static const mdb_dcmd_t dcmds[] = {
955 	{ "mptsas", "?[-tpsdD]", "print mpt_sas information", mptsas_dcmd,
956 	    mptsas_help}, { NULL }
957 };
958 
959 static const mdb_modinfo_t modinfo = {
960 	MDB_API_VERSION, dcmds, NULL
961 };
962 
963 const mdb_modinfo_t *
964 _mdb_init(void)
965 {
966 	return (&modinfo);
967 }
968