mpt_sas.c revision 9907:98086c85a8f7
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
43struct {
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
62static int
63atoi(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
75int
76construct_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 */
102int
103mdi_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
158void
159mdi_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
182void
183print_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
213void
214display_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}
229static void *
230hash_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}
272void
273display_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
413int
414display_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
593exit:
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
602void
603display_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
689static int
690mptsas_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 */
817void
818mptsas_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
831static const mdb_dcmd_t dcmds[] = {
832	{ "mptsas", "?[-tpd]", "print mpt_sas information", mptsas_dcmd,
833	    mptsas_help}, { NULL }
834};
835
836static const mdb_modinfo_t modinfo = {
837	MDB_API_VERSION, dcmds, NULL
838};
839
840const mdb_modinfo_t *
841_mdb_init(void)
842{
843	return (&modinfo);
844}
845