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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2019 Joyent, Inc.
26  */
27 
28 #include <sys/kmem.h>
29 #include <sys/proc.h>
30 #include <sys/time.h>
31 #include <sys/conf.h>
32 #include <sys/file.h>
33 #include <sys/ddi.h>
34 #include <sys/ddi_impldefs.h>
35 #include <sys/modctl.h>
36 #include <sys/sunddi.h>
37 #include <sys/scsi/scsi.h>
38 #include <sys/scsi/impl/scsi_reset_notify.h>
39 #include <sys/sunmdi.h>
40 #include <sys/mdi_impldefs.h>
41 #include <sys/scsi/adapters/scsi_vhci.h>
42 #include <sys/scsi/scsi_types.h>
43 #include <sys/disp.h>
44 #include <sys/types.h>
45 #include <sys/mdb_modapi.h>
46 
47 #define	FT(var, typ)	(*((typ *)(&(var))))
48 
49 static int dump_states(uintptr_t array_vaddr, int verbose,
50     struct i_ddi_soft_state *sp);
51 static int i_vhci_states(uintptr_t addr, uint_t flags, int argc,
52     const mdb_arg_t *argv, struct i_ddi_soft_state *sp);
53 static int vhci_states(uintptr_t addr, uint_t flags, int argc,
54     const mdb_arg_t *argv);
55 
56 static int mdiclient(uintptr_t addr, uint_t flags, int argc,
57     const mdb_arg_t *argv);
58 static int vhciguid(uintptr_t addr, uint_t flags, int argc,
59     const mdb_arg_t *argv);
60 static int vhcilun(uintptr_t addr, uint_t flags, int argc,
61     const mdb_arg_t *argv);
62 static int i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid);
63 
64 /* Utils */
65 static int get_mdbstr(uintptr_t addr, char *name);
66 static void dump_mutex(kmutex_t m, char *name);
67 static void dump_condvar(kcondvar_t c, char *name);
68 static void dump_string(uintptr_t addr, char *name);
69 static void dump_flags(unsigned long long flags, char **strings);
70 static void dump_state_str(char *name, uintptr_t addr, char **strings);
71 
72 static int mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata);
73 
74 static const mdb_dcmd_t dcmds[] = {
75 	{ "vhci_states", "[ -v ]", "dump all the vhci state pointers",
76 		vhci_states },
77 	{ "vhciguid", NULL, "list all clients or given a guid, list one client",
78 		vhciguid },
79 	{ NULL }
80 };
81 
82 static const mdb_modinfo_t modinfo = {
83 	MDB_API_VERSION, dcmds, NULL
84 };
85 
86 static char *client_lb_str[] =
87 {
88 	"NONE",
89 	"RR",
90 	"LBA",
91 	NULL
92 };
93 
94 static char *mdi_client_states[] =
95 {
96 	NULL,
97 	"OPTIMAL",
98 	"DEGRADED",
99 	"FAILED",
100 	NULL
101 };
102 
103 static char *client_flags[] =
104 {
105 	"MDI_CLIENT_FLAGS_OFFLINE",
106 	"MDI_CLIENT_FLAGS_SUSPEND",
107 	"MDI_CLIENT_FLAGS_POWER_DOWN",
108 	"MDI_CLIENT_FLAGS_DETACH",
109 	"MDI_CLIENT_FLAGS_FAILOVER",
110 	"MDI_CLIENT_FLAGS_REPORT_DEV",
111 	"MDI_CLIENT_FLAGS_PATH_FREE_IN_PROGRESS",
112 	"MDI_CLIENT_FLAGS_ASYNC_FREE",
113 	"MDI_CLIENT_FLAGS_DEV_NOT_SUPPORTED",
114 	NULL
115 };
116 
117 static char *vhci_conf_flags[] =
118 {
119 	"VHCI_CONF_FLAGS_AUTO_FAILBACK",
120 	NULL
121 };
122 
123 static char *svlun_flags[] =
124 {
125 	"VLUN_TASK_D_ALIVE_FLG",
126 	"VLUN_RESERVE_ACTIVE_FLG",
127 	"VLUN_QUIESCED_FLG",
128 	NULL
129 };
130 
131 static char mdipathinfo_cb_str[] = "::print struct mdi_pathinfo";
132 
133 const mdb_modinfo_t *
_mdb_init(void)134 _mdb_init(void)
135 {
136 	return (&modinfo);
137 }
138 
139 /*
140  * mdiclient()
141  *
142  * Dump mdi_client_t info and list all paths.
143  */
144 /* ARGSUSED */
145 static int
mdiclient(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)146 mdiclient(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
147 {
148 	struct mdi_client	value;
149 
150 	if (!(flags & DCMD_ADDRSPEC)) {
151 		mdb_warn("mdiclient: requires an address");
152 		return (DCMD_ERR);
153 	}
154 
155 	if (mdb_vread(&value, sizeof (struct mdi_client), addr)
156 	    != sizeof (struct mdi_client)) {
157 		mdb_warn("mdiclient: Failed read on %l#r\n", addr);
158 		return (DCMD_ERR);
159 	}
160 	mdb_printf("----------------- mdi_client @ %#lr ----------\n", addr);
161 	dump_string((uintptr_t)value.ct_guid, "GUID (ct_guid)");
162 	dump_string((uintptr_t)value.ct_drvname, "Driver Name (ct_drvname)");
163 	dump_state_str("Load Balance (ct_lb)", value.ct_lb, client_lb_str);
164 	mdb_printf("\n");
165 	mdb_printf("ct_hnext: %26l#r::print struct mdi_client\n",
166 	    value.ct_hnext);
167 	mdb_printf("ct_hprev: %26l#r::print struct mdi_client\n",
168 	    value.ct_hprev);
169 	mdb_printf("ct_dip: %28l#r::print struct dev_info\n", value.ct_dip);
170 	mdb_printf("ct_vhci: %27l#r::print struct mdi_vhci\n", value.ct_vhci);
171 	mdb_printf("ct_cprivate: %23l#r\n", value.ct_cprivate);
172 	mdb_printf("\nct_path_head: %22l#r::print struct mdi_pathinfo\n",
173 	    value.ct_path_head);
174 	mdb_printf("ct_path_tail: %22l#r::print struct mdi_pathinfo\n",
175 	    value.ct_path_tail);
176 	mdb_printf("ct_path_last: %22l#r::print struct mdi_pathfinfo\n",
177 	    value.ct_path_last);
178 	mdb_printf("ct_path_count: %21d\n", value.ct_path_count);
179 	mdb_printf("List of paths:\n");
180 	mdb_pwalk("mdipi_client_list", (mdb_walk_cb_t)mpxio_walk_cb,
181 	    mdipathinfo_cb_str, (uintptr_t)value.ct_path_head);
182 
183 	mdb_printf("\n");
184 	dump_state_str("Client State (ct_state)", value.ct_state,
185 	    mdi_client_states);
186 	dump_mutex(value.ct_mutex, "per-client mutex (ct_mutex):");
187 	mdb_printf("ct_flags: %26d\n", value.ct_flags);
188 	if (value.ct_flags) {
189 		dump_flags((unsigned long long)value.ct_flags, client_flags);
190 	}
191 	mdb_printf("ct_unstable: %23d\n", value.ct_unstable);
192 	dump_condvar(value.ct_unstable_cv, "ct_unstable_cv");
193 	dump_condvar(value.ct_failover_cv, "ct_failover_cv");
194 
195 	mdb_printf("\n");
196 	mdb_printf("ct_failover_flags TEMP_VAR: %8d\n",
197 	    value.ct_failover_flags);
198 	mdb_printf("ct_failover_status UNUSED: %9d\n",
199 	    value.ct_failover_status);
200 
201 	return (DCMD_OK);
202 }
203 
204 /*
205  * vhcilun()
206  *
207  * Get client info given a guid.
208  */
209 /* ARGSUSED */
210 static int
vhcilun(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)211 vhcilun(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
212 {
213 	if (!(flags & DCMD_ADDRSPEC)) {
214 		mdb_warn("sv_lun: requires an address");
215 		return (DCMD_ERR);
216 	}
217 
218 	return (i_vhcilun(addr, 0 /* display_single_guid */, 0));
219 }
220 
221 /*
222  * vhciguid()
223  *
224  * List all the clients.
225  */
226 /* ARGSUSED */
227 static int
vhciguid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)228 vhciguid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
229 {
230 
231 	struct i_ddi_soft_state ss;
232 	int i;
233 
234 	mdi_vhci_t	*mdi_vhci_value;
235 	mdi_client_t	*mdi_client_value;
236 	struct client_hash	*ct_hash_val;
237 	struct client_hash	*ct_hash_table_val;
238 
239 	int		len = strlen(MDI_HCI_CLASS_SCSI);
240 	int		mdi_vhci_len = sizeof (*mdi_vhci_value);
241 	int		mdi_client_len = sizeof (*mdi_client_value);
242 	int		ct_hash_len = sizeof (*ct_hash_val);
243 
244 	int		ct_hash_count = 0;
245 	char		*class;
246 	int		found = 0;
247 	uintptr_t	buf;
248 	uintptr_t	temp;
249 
250 
251 
252 	if (flags & DCMD_ADDRSPEC)
253 		mdb_warn("This command doesn't use an address\n");
254 
255 	if (i_vhci_states(0, 0, 0, 0, &ss) != DCMD_OK)
256 		return (DCMD_ERR);
257 
258 	if (mdb_readvar(&buf, "mdi_vhci_head") == -1) {
259 		mdb_warn("mdi driver variable mdi_vhci_head not found.\n");
260 		mdb_warn("Is the driver loaded ?\n");
261 		return (DCMD_ERR);
262 	}
263 	mdb_printf("----------------- mdi_vhci_head @ %#lr ----------\n", buf);
264 	mdi_vhci_value = (mdi_vhci_t *)mdb_alloc(mdi_vhci_len, UM_SLEEP|UM_GC);
265 	if (mdb_vread(mdi_vhci_value, mdi_vhci_len, buf) != mdi_vhci_len) {
266 		mdb_warn("vhciguid: Failed read on %l#r\n", mdi_vhci_value);
267 		mdb_free(mdi_vhci_value, mdi_vhci_len);
268 		return (DCMD_ERR);
269 	}
270 	temp = (uintptr_t)mdi_vhci_value->vh_class;
271 	class = (char *)mdb_alloc(len, UM_SLEEP|UM_GC);
272 	if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp)
273 	    != strlen(MDI_HCI_CLASS_SCSI)) {
274 		mdb_warn("vhciguid: Failed read of class %l#r\n",
275 		    mdi_vhci_value);
276 		mdb_free(mdi_vhci_value, mdi_vhci_len);
277 		mdb_free(class, len);
278 		return (DCMD_ERR);
279 	}
280 	class[len] = 0;
281 	mdb_printf("----------------- class @ %s----------\n", class);
282 	while (class) {
283 		if (strcmp(class, MDI_HCI_CLASS_SCSI) == 0) {
284 			found = 1;
285 			break;
286 		}
287 		if (mdi_vhci_value->vh_next == NULL) {
288 			break;
289 		}
290 		temp = (uintptr_t)mdi_vhci_value->vh_next;
291 		if (mdb_vread(mdi_vhci_value, mdi_vhci_len, temp)
292 		    != mdi_vhci_len) {
293 			mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
294 			    mdi_vhci_value);
295 			break;
296 		}
297 		temp = (uintptr_t)mdi_vhci_value->vh_class;
298 		if (mdb_vread(class, strlen(MDI_HCI_CLASS_SCSI), temp) !=
299 		    strlen(MDI_HCI_CLASS_SCSI)) {
300 			mdb_warn("vhciguid: Failed read on vh->next %l#r\n",
301 			    mdi_vhci_value);
302 			break;
303 		}
304 		class[len] = 0;
305 	}
306 
307 	if (found == 0) {
308 		mdb_warn("vhciguid: No scsi_vhci class found");
309 		mdb_free(mdi_vhci_value, mdi_vhci_len);
310 		mdb_free(class, len);
311 		return (DCMD_ERR);
312 	}
313 	mdb_printf("----- Number of devices found %d ----------\n",
314 	    mdi_vhci_value->vh_client_count);
315 	for (i = 0; i < CLIENT_HASH_TABLE_SIZE; i++) {
316 		ct_hash_table_val = &mdi_vhci_value->vh_client_table[i];
317 		if (ct_hash_table_val == NULL)
318 			continue;
319 
320 		/* Read client_hash structure */
321 		ct_hash_val = (struct client_hash *)mdb_alloc(ct_hash_len,
322 		    UM_SLEEP|UM_GC);
323 		temp = (uintptr_t)ct_hash_table_val;
324 		if (mdb_vread(ct_hash_val, ct_hash_len, temp) != ct_hash_len) {
325 			mdb_warn("Failed read on hash %l#r\n",
326 			    ct_hash_val);
327 			break;
328 		}
329 		mdb_printf("----hash[%d] %l#r: devices mapped  = %d --\n",
330 		    i, ct_hash_table_val, ct_hash_val->ct_hash_count);
331 		if (ct_hash_val->ct_hash_count == 0) {
332 			continue;
333 		}
334 
335 		ct_hash_count = ct_hash_val->ct_hash_count;
336 
337 		/* Read mdi_client structures */
338 		mdi_client_value = (mdi_client_t *)mdb_alloc(mdi_client_len,
339 		    UM_SLEEP|UM_GC);
340 		temp = (uintptr_t)ct_hash_val->ct_hash_head;
341 		if (mdb_vread(mdi_client_value, mdi_client_len, temp)
342 		    != mdi_client_len) {
343 			mdb_warn("Failed read on client %l#r\n",
344 			    mdi_client_value);
345 			break;
346 		}
347 		mdb_printf("mdi_client %l#r %l#r ------\n",
348 		    mdi_client_value, mdi_client_value->ct_vprivate);
349 		vhcilun((uintptr_t)mdi_client_value->ct_vprivate,
350 		    DCMD_ADDRSPEC, 0, 0);
351 
352 		while (--ct_hash_count) {
353 			temp = (uintptr_t)mdi_client_value->ct_hnext;
354 			if (mdb_vread(mdi_client_value, mdi_client_len,
355 			    temp) != mdi_client_len) {
356 				mdb_warn("Failed read on client %l#r\n",
357 				    mdi_client_value);
358 				break;
359 			}
360 			vhcilun((uintptr_t)mdi_client_value->ct_vprivate,
361 			    DCMD_ADDRSPEC, 0, 0);
362 		}
363 	}
364 	mdb_printf("----------done----------\n");
365 
366 	return (DCMD_OK);
367 }
368 
369 /*
370  * Print the flag name by comparing flags to the mask variable.
371  */
372 static void
dump_flags(unsigned long long flags,char ** strings)373 dump_flags(unsigned long long flags, char **strings)
374 {
375 	int i, linel = 8, first = 1;
376 	unsigned long long mask = 1;
377 
378 	for (i = 0; i < 64; i++) {
379 		if (strings[i] == NULL)
380 			break;
381 		if (flags & mask) {
382 			if (!first) {
383 				mdb_printf(" | ");
384 			} else {
385 				first = 0;
386 			}
387 			/* make output pretty */
388 			linel += strlen(strings[i]) + 3;
389 			if (linel > 80) {
390 				mdb_printf("\n\t");
391 				linel = strlen(strings[i]) + 1 + 8;
392 			}
393 			mdb_printf("%s", strings[i]);
394 		}
395 		mask <<= 1;
396 	}
397 	mdb_printf("\n");
398 }
399 
400 /* ARGSUSED */
401 static int
vhci_states(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)402 vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
403 {
404 	return (i_vhci_states(addr, flags, argc, argv, NULL));
405 }
406 
407 /*
408  * dump_states()
409  *
410  * Print the state information for vhci_states().
411  */
412 static int
dump_states(uintptr_t array_vaddr,int verbose,struct i_ddi_soft_state * sp)413 dump_states(uintptr_t array_vaddr, int verbose, struct i_ddi_soft_state *sp)
414 {
415 	int i;
416 	int array_size;
417 	struct i_ddi_soft_state *ss;
418 	struct scsi_vhci vhci;
419 
420 	if (sp == NULL) {
421 		ss = (struct i_ddi_soft_state *)mdb_alloc(sizeof (*ss),
422 		    UM_SLEEP|UM_GC);
423 	} else {
424 		ss = sp;
425 	}
426 	if (mdb_vread(ss, sizeof (*ss), array_vaddr) != sizeof (*ss)) {
427 		mdb_warn("Cannot read softstate struct (Invalid pointer?).\n");
428 		return (DCMD_ERR);
429 	}
430 	array_size = ss->n_items * (sizeof (void *));
431 	array_vaddr = (uintptr_t)ss->array;
432 	ss->array = mdb_alloc(array_size, UM_SLEEP|UM_GC);
433 	if (mdb_vread(ss->array, array_size, array_vaddr) != array_size) {
434 		mdb_warn("Corrupted softstate struct.\n");
435 		return (DCMD_ERR);
436 	}
437 	if (sp != NULL)
438 		return (DCMD_OK);
439 	if (verbose) {
440 	/*
441 	 * ss->size is of type size_t which is 4 bytes and 8 bytes
442 	 * on 32-bit and 64-bit systems respectively.
443 	 */
444 #ifdef _LP64
445 		mdb_printf("Softstate size is %lld(0x%llx) bytes.\n\n",
446 		    ss->size, ss->size);
447 #else
448 		mdb_printf("Softstate size is %ld(0x%lx) bytes.\n\n",
449 		    ss->size, ss->size);
450 #endif
451 		mdb_printf("state pointer\t\t\t\t\tinstance\n");
452 		mdb_printf("=============\t\t\t\t\t========\n");
453 	}
454 	for (i = 0; i < ss->n_items; i++) {
455 		if (ss->array[i] == 0)
456 			continue;
457 
458 		if (mdb_vread(&vhci, sizeof (vhci), (uintptr_t)ss->array[i])
459 		    != sizeof (vhci)) {
460 			mdb_warn("Corrupted softstate struct.\n");
461 			return (DCMD_ERR);
462 		}
463 		if (verbose) {
464 			mdb_printf("%l#r::print struct scsi_vhci\t\t   %d\n",
465 			    ss->array[i], i);
466 			mdb_printf("\nvhci_conf_flags: %d\n",
467 			    vhci.vhci_conf_flags);
468 			if (vhci.vhci_conf_flags) {
469 				mdb_printf("\t");
470 				dump_flags((unsigned long long)
471 				    vhci.vhci_conf_flags, vhci_conf_flags);
472 			}
473 		} else {
474 			mdb_printf("%l#r\n", ss->array[i]);
475 		}
476 	}
477 	return (DCMD_OK);
478 }
479 
480 static int
get_mdbstr(uintptr_t addr,char * string_val)481 get_mdbstr(uintptr_t addr, char *string_val)
482 {
483 	if (mdb_readstr(string_val, MAXNAMELEN, addr) == -1) {
484 		mdb_warn("Error Reading String from %l#r\n", addr);
485 		return (1);
486 	}
487 
488 	return (0);
489 }
490 
491 static void
dump_state_str(char * name,uintptr_t addr,char ** strings)492 dump_state_str(char *name, uintptr_t addr, char **strings)
493 {
494 	mdb_printf("%s: %s (%l#r)\n", name, strings[(unsigned long)addr], addr);
495 }
496 
497 /* VHCI UTILS */
498 
499 /*
500  * i_vhci_states()
501  *
502  * Internal routine for vhci_states() to check for -v arg and then
503  * print state info.
504  */
505 /* ARGSUSED */
506 static int
i_vhci_states(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,struct i_ddi_soft_state * sp)507 i_vhci_states(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
508     struct i_ddi_soft_state *sp)
509 {
510 	uintptr_t adr;
511 	int verbose = 0;
512 
513 	if (mdb_readvar(&adr, "vhci_softstate") == -1) {
514 		mdb_warn("vhci driver variable vhci_softstate not found.\n");
515 		mdb_warn("Is the driver loaded ?\n");
516 		return (DCMD_ERR);
517 	}
518 	if (sp == NULL) {
519 		if (mdb_getopts(argc, argv,
520 		    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) {
521 			return (DCMD_USAGE);
522 		}
523 	}
524 
525 	return (dump_states(adr, verbose, sp));
526 }
527 
528 /*
529  * i_vhcilun()
530  *
531  * Internal routine for vhciguid() to print client info.
532  */
533 static int
i_vhcilun(uintptr_t addr,uint_t display_single_guid,char * guid)534 i_vhcilun(uintptr_t addr, uint_t display_single_guid, char *guid)
535 {
536 
537 	scsi_vhci_lun_t		value;
538 	struct dev_info		dev_info_value;
539 	char			string_val[MAXNAMELEN];
540 	int			found = 0;
541 	struct mdi_client	ct_value;
542 	uintptr_t		temp_addr;
543 
544 	do {
545 		if (mdb_vread(&value, sizeof (scsi_vhci_lun_t), addr) !=
546 		    sizeof (scsi_vhci_lun_t)) {
547 			mdb_warn("sv_lun: Failed read on %l#r", addr);
548 			return (DCMD_ERR);
549 		}
550 
551 		temp_addr = addr;
552 		addr = (uintptr_t)value.svl_hash_next;
553 
554 		if (!get_mdbstr((uintptr_t)value.svl_lun_wwn, string_val)) {
555 			if (display_single_guid) {
556 				if (strcmp(string_val, guid) == 0) {
557 					found = 1;
558 				} else continue;
559 			}
560 		}
561 
562 		mdb_printf("%t%l#r::print struct scsi_vhci_lun", temp_addr);
563 
564 		if (mdb_vread(&dev_info_value, sizeof (struct dev_info),
565 		    (uintptr_t)value.svl_dip) != sizeof (struct dev_info)) {
566 			mdb_warn("svl_dip: Failed read on %l#r",
567 			    value.svl_dip);
568 			return (DCMD_ERR);
569 		}
570 
571 		mdb_printf("\n%tGUID: %s\n", string_val);
572 		if (value.svl_active_pclass != NULL) {
573 			if (!get_mdbstr((uintptr_t)value.svl_active_pclass,
574 			    string_val)) {
575 				mdb_printf("%tActv_cl: %s", string_val);
576 			}
577 		} else {
578 			mdb_printf("   No active pclass");
579 		}
580 		if (display_single_guid) {
581 			mdb_printf(" (%l#r)", value.svl_active_pclass);
582 		}
583 
584 		mdb_printf("\n%t%l#r::print struct mdi_client",
585 		    dev_info_value.devi_mdi_client);
586 
587 		if (value.svl_flags) {
588 			mdb_printf("\t");
589 			dump_flags((unsigned long long)value.svl_flags,
590 			    svlun_flags);
591 		} else {
592 			mdb_printf("\n");
593 		}
594 
595 		if (found) {
596 			mdiclient((uintptr_t)dev_info_value.devi_mdi_client,
597 			    DCMD_ADDRSPEC, 0, 0);
598 		} else {
599 			if (mdb_vread(&ct_value, sizeof (struct mdi_client),
600 			    (uintptr_t)dev_info_value.devi_mdi_client) !=
601 			    sizeof (struct mdi_client)) {
602 				mdb_warn("mdiclient: Failed read on %l#r",
603 				    dev_info_value.devi_mdi_client);
604 				return (DCMD_ERR);
605 			}
606 			if (ct_value.ct_flags) {
607 				mdb_printf("\t");
608 				dump_flags((unsigned long long)
609 				    ct_value.ct_flags, client_flags);
610 			}
611 			mdb_printf("%t");
612 			dump_state_str("LB", ct_value.ct_lb, client_lb_str);
613 			mdb_printf("\n");
614 		}
615 	} while (addr && !found);
616 	return (DCMD_OK);
617 }
618 
619 static void
dump_mutex(kmutex_t m,char * name)620 dump_mutex(kmutex_t m, char *name)
621 {
622 	mdb_printf("%s is%s held\n", name, FT(m, uint64_t) == 0 ? " not" : "");
623 }
624 
625 static void
dump_condvar(kcondvar_t c,char * name)626 dump_condvar(kcondvar_t c, char *name)
627 {
628 	mdb_printf("Threads sleeping on %s = %d\n", name, (int)FT(c, ushort_t));
629 }
630 
631 static void
dump_string(uintptr_t addr,char * name)632 dump_string(uintptr_t addr, char *name)
633 {
634 	char string_val[MAXNAMELEN];
635 
636 	if (get_mdbstr(addr, string_val)) {
637 		return;
638 	}
639 	mdb_printf("%s: %s (%l#r)\n", name, string_val, addr);
640 }
641 
642 /* ARGSUSED */
643 static int
mpxio_walk_cb(uintptr_t addr,const void * data,void * cbdata)644 mpxio_walk_cb(uintptr_t addr, const void *data, void *cbdata)
645 {
646 	mdb_printf("%t%l#r%s\n", addr, (char *)cbdata);
647 	return (0);
648 }
649