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