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