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