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